From 5678d824e43d1ae2e2abaa1bc9a03391a4683a86 Mon Sep 17 00:00:00 2001
From: taiyu <taiyu.len@gmail.com>
Date: Thu, 27 Aug 2015 23:18:28 -0700
Subject: [PATCH] update visibility + container info functions

---
 include/container.h |   4 ++
 sway/container.c    | 104 ++++++++++++++++++++++++++------------------
 sway/focus.c        |  20 ++++-----
 sway/layout.c       |   2 +-
 4 files changed, 77 insertions(+), 53 deletions(-)

diff --git a/include/container.h b/include/container.h
index 29f75f45..cfb2e868 100644
--- a/include/container.h
+++ b/include/container.h
@@ -103,6 +103,10 @@ swayc_t *swayc_active_workspace_for(swayc_t *view);
 
 bool swayc_is_fullscreen(swayc_t *view);
 bool swayc_is_active(swayc_t *view);
+// Is `parent` the parent of `child`
+bool swayc_is_parent_of(swayc_t *parent, swayc_t *child);
+// Is `child` a child of `parent`
+bool swayc_is_child_of(swayc_t *child, swayc_t *parent);
 
 // Mapping functions
 
diff --git a/sway/container.c b/sway/container.c
index d6d27033..19a40090 100644
--- a/sway/container.c
+++ b/sway/container.c
@@ -547,6 +547,20 @@ bool swayc_is_active(swayc_t *view) {
 	return view && view->type == C_VIEW && (wlc_view_get_state(view->handle) & WLC_BIT_ACTIVATED);
 }
 
+bool swayc_is_parent_of(swayc_t *parent, swayc_t *child) {
+	while (child != &root_container) {
+		child = child->parent;
+		if (child == parent) {
+			return true;
+		}
+	}
+	return false;
+}
+
+bool swayc_is_child_of(swayc_t *child, swayc_t *parent) {
+	return swayc_is_parent_of(parent, child);
+}
+
 // Mapping
 
 void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), void *data) {
@@ -568,58 +582,64 @@ void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), voi
 	}
 }
 
-void set_view_visibility(swayc_t *view, void *data) {
-	if (!ASSERT_NONNULL(view)) {
-		return;
+void update_visibility_output(swayc_t *container, wlc_handle output) {
+	// Inherit visibility
+	swayc_t *parent = container->parent;
+	container->visible = parent->visible;
+	// special cases where visibility depends on focus
+	if (parent->type == C_OUTPUT
+			|| parent->layout == L_TABBED
+			|| parent->layout == L_STACKED) {
+		container->visible = parent->focused == container;
 	}
-	// TODO add something like this.
-//	if (container->type == C_ROOT) {
-//		container->visible = true;
-//	} else {
-//		// Inherit visibility
-//		swayc_t *parent = container->parent;
-//		container->visible = parent->visible;
-//		// special cases where visibility depends on focus
-//		if (parent->type == C_OUTPUT || parent->layout == L_TABBED ||
-//				parent->layout == L_STACKED) {
-//			container->visible = parent->focused == container;
-//		}
-//	}
-	bool visible = *(bool *)data;
-	if (view->type == C_VIEW) {
-		wlc_view_set_output(view->handle, swayc_parent_by_type(view, C_OUTPUT)->handle);
-		wlc_view_set_mask(view->handle, visible ? VISIBLE : 0);
-		if (visible) {
-			wlc_view_bring_to_front(view->handle);
+	// Set visibility and output for view
+	if (container->type == C_VIEW) {
+		wlc_view_set_output(container->handle, output);
+		wlc_view_set_mask(container->handle, container->visible ? VISIBLE : 0);
+		if (container->visible) {
+			wlc_view_bring_to_front(container->handle);
 		} else {
-			wlc_view_send_to_back(view->handle);
+			wlc_view_send_to_back(container->handle);
+		}
+	}
+	// Update visibility for children
+	else if (container->children) {
+		int i, len = container->children->length;
+		for (i = 0; i < len; ++i) {
+			update_visibility_output(container->children->items[i], output);
 		}
 	}
-	view->visible = visible;
-	sway_log(L_DEBUG, "Container %p is now %s", view, visible ? "visible" : "invisible");
 }
 
 void update_visibility(swayc_t *container) {
-	if (!container) {
-		return;
-	}
-	swayc_t *ws;
-	if (container->type == C_ROOT || container->type == C_OUTPUT) {
-		int i, len = container->children->length;
-		for (i = 0; i < len; ++i) {
-			update_visibility(container->children->items[i]);
+	if (!container) return;
+	switch (container->type) {
+	case C_ROOT:
+		container->visible = true;
+		if (container->children) {
+			int i, len = container->children->length;
+			for (i = 0; i < len; ++i) {
+				update_visibility(container->children->items[i]);
+			}
 		}
 		return;
-	} else if (container->type == C_WORKSPACE) {
-		container->visible = container->parent->focused == container;
-		ws = container;
-	} else {
-		ws = swayc_active_workspace_for(container);
+
+	case C_OUTPUT:
+		container->visible = true;
+		if (container->children) {
+			int i, len = container->children->length;
+			for (i = 0; i < len; ++i) {
+				update_visibility_output(container->children->items[i], container->handle);
+			}
+		}
+		return;
+
+	default:
+		{
+			swayc_t *op = swayc_parent_by_type(container, C_OUTPUT);
+			update_visibility_output(container, op->handle);
+		}
 	}
-	// TODO better visibility setting
-	bool visible = (ws->parent->focused == ws);
-	sway_log(L_DEBUG, "Setting visibility of container %p to %s", container, visible ? "visible" : "invisible");
-	container_map(ws, set_view_visibility, &visible);
 }
 
 void reset_gaps(swayc_t *view, void *data) {
diff --git a/sway/focus.c b/sway/focus.c
index f7b55b27..45108a11 100644
--- a/sway/focus.c
+++ b/sway/focus.c
@@ -14,6 +14,10 @@ static void update_focus(swayc_t *c) {
 	// Handle if focus switches
 	swayc_t *parent = c->parent;
 	if (parent->focused != c) {
+		// Get previous focus
+		swayc_t *prev = parent->focused;
+		// Set new focus
+		parent->focused = c;
 		switch (c->type) {
 		// Shouldnt happen
 		case C_ROOT: return;
@@ -25,16 +29,13 @@ static void update_focus(swayc_t *c) {
 
 		// Case where workspace changes
 		case C_WORKSPACE:
-			if (parent->focused) {
-				swayc_t *ws = parent->focused;
-				// hide visibility of old workspace
-				bool visible = false;
-				container_map(ws, set_view_visibility, &visible);
-				// set visibility of new workspace
-				visible = true;
-				container_map(c, set_view_visibility, &visible);
-				destroy_workspace(ws);
+			if (prev) {
+				// update visibility of old workspace
+				update_visibility(prev);
+				destroy_workspace(prev);
 			}
+			// Update visibility of newly focused workspace
+			update_visibility(c);
 			break;
 
 		default:
@@ -44,7 +45,6 @@ static void update_focus(swayc_t *c) {
 			// for example, stacked and tabbing change stuff.
 			break;
 		}
-		c->parent->focused = c;
 	}
 }
 
diff --git a/sway/layout.c b/sway/layout.c
index 5ade5e63..f04007ed 100644
--- a/sway/layout.c
+++ b/sway/layout.c
@@ -221,7 +221,7 @@ void move_container(swayc_t *container,swayc_t* root,enum movement_direction dir
 }
 
 void move_container_to(swayc_t* container, swayc_t* destination) {
-	if (container == destination) {
+	if (container == destination && swayc_is_parent_of(container, destination)) {
 		return;
 	}
 	swayc_t *parent = remove_child(container);