From 83e314bf51265ca825eaa78ffaaedeb10621f1b3 Mon Sep 17 00:00:00 2001
From: Ryan Dwyer <ryandwyer1@gmail.com>
Date: Fri, 11 May 2018 09:13:40 +1000
Subject: Highlight all child borders when using focus parent

---
 sway/desktop/output.c | 19 ++++++----
 sway/input/seat.c     | 99 +++++++++++++++++++++++++++++++--------------------
 2 files changed, 73 insertions(+), 45 deletions(-)

diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index c150270e..a25139b4 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -453,7 +453,7 @@ static void render_container_simple_border_pixel(struct sway_output *output,
 }
 
 static void render_container(struct sway_output *output,
-	pixman_region32_t *damage, struct sway_container *con);
+	pixman_region32_t *damage, struct sway_container *con, bool parent_focused);
 
 /**
  * Render a container's children using a L_HORIZ or L_VERT layout.
@@ -462,7 +462,8 @@ static void render_container(struct sway_output *output,
  * they'll apply their own borders to their children.
  */
 static void render_container_simple(struct sway_output *output,
-		pixman_region32_t *damage, struct sway_container *con) {
+		pixman_region32_t *damage, struct sway_container *con,
+		bool parent_focused) {
 	struct sway_seat *seat = input_manager_current_seat(input_manager);
 	struct sway_container *focus = seat_get_focus(seat);
 
@@ -473,7 +474,7 @@ static void render_container_simple(struct sway_output *output,
 			if (child->sway_view->border != B_NONE) {
 				struct border_colors *colors;
 				struct wlr_texture *title_texture;
-				if (focus == child) {
+				if (focus == child || parent_focused) {
 					colors = &config->border_colors.focused;
 					title_texture = child->title_focused;
 				} else if (seat_get_focus_inactive(seat, con) == child) {
@@ -494,7 +495,8 @@ static void render_container_simple(struct sway_output *output,
 			}
 			render_view(child->sway_view, output, damage);
 		} else {
-			render_container(output, damage, child);
+			render_container(output, damage, child,
+					parent_focused || focus == child);
 		}
 	}
 }
@@ -516,12 +518,13 @@ static void render_container_stacked(struct sway_output *output,
 }
 
 static void render_container(struct sway_output *output,
-		pixman_region32_t *damage, struct sway_container *con) {
+		pixman_region32_t *damage, struct sway_container *con,
+		bool parent_focused) {
 	switch (con->layout) {
 	case L_NONE:
 	case L_HORIZ:
 	case L_VERT:
-		render_container_simple(output, damage, con);
+		render_container_simple(output, damage, con, parent_focused);
 		break;
 	case L_STACKED:
 		render_container_stacked(output, damage, con);
@@ -605,7 +608,9 @@ static void render_output(struct sway_output *output, struct timespec *when,
 		render_layer(output, damage,
 			&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]);
 
-		render_container(output, damage, workspace);
+		struct sway_seat *seat = input_manager_current_seat(input_manager);
+		struct sway_container *focus = seat_get_focus(seat);
+		render_container(output, damage, workspace, focus == workspace);
 
 		render_unmanaged(output, damage,
 			&root_container.sway_root->xwayland_unmanaged);
diff --git a/sway/input/seat.c b/sway/input/seat.c
index 2c279ff2..9ac3e6a8 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -65,27 +65,49 @@ static void seat_container_destroy(struct sway_seat_container *seat_con) {
 	free(seat_con);
 }
 
-static void seat_send_focus(struct sway_seat *seat,
-		struct sway_container *con) {
-	if (con->type != C_VIEW) {
-		return;
-	}
-	struct sway_view *view = con->sway_view;
-	if (view->type == SWAY_VIEW_XWAYLAND) {
-		struct wlr_xwayland *xwayland =
-			seat->input->server->xwayland;
-		wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
-	}
-	view_set_activated(view, true);
-	struct wlr_keyboard *keyboard =
-		wlr_seat_get_keyboard(seat->wlr_seat);
-	if (keyboard) {
-		wlr_seat_keyboard_notify_enter(seat->wlr_seat,
-				view->surface, keyboard->keycodes,
-				keyboard->num_keycodes, &keyboard->modifiers);
+/**
+ * Activate all views within this container recursively.
+ */
+static void seat_send_activate(struct sway_container *con,
+		struct sway_seat *seat) {
+	if (con->type == C_VIEW) {
+		if (!seat_is_input_allowed(seat, con->sway_view->surface)) {
+			wlr_log(L_DEBUG, "Refusing to set focus, input is inhibited");
+			return;
+		}
+		view_set_activated(con->sway_view, true);
 	} else {
-		wlr_seat_keyboard_notify_enter(
-				seat->wlr_seat, view->surface, NULL, 0, NULL);
+		for (int i = 0; i < con->children->length; ++i) {
+			struct sway_container *child = con->children->items[i];
+			seat_send_activate(child, seat);
+		}
+	}
+}
+
+/**
+ * If con is a view, set it as active and enable keyboard input.
+ * If con is a container, set all child views as active and don't enable
+ * keyboard input on any.
+ */
+static void seat_send_focus(struct sway_container *con,
+		struct sway_seat *seat) {
+	seat_send_activate(con, seat);
+
+	if (con->type == C_VIEW
+			&& seat_is_input_allowed(seat, con->sway_view->surface)) {
+		if (con->sway_view->type == SWAY_VIEW_XWAYLAND) {
+			struct wlr_xwayland *xwayland = seat->input->server->xwayland;
+			wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
+		}
+		struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
+		if (keyboard) {
+			wlr_seat_keyboard_notify_enter(seat->wlr_seat,
+					con->sway_view->surface, keyboard->keycodes,
+					keyboard->num_keycodes, &keyboard->modifiers);
+		} else {
+			wlr_seat_keyboard_notify_enter(
+					seat->wlr_seat, con->sway_view->surface, NULL, 0, NULL);
+		}
 	}
 }
 
@@ -160,7 +182,7 @@ static void handle_seat_container_destroy(struct wl_listener *listener,
 		// the structure change might have caused it to move up to the top of
 		// the focus stack without sending focus notifications to the view
 		if (seat_get_focus(seat) == next_focus) {
-			seat_send_focus(seat, next_focus);
+			seat_send_focus(next_focus, seat);
 		} else {
 			seat_set_focus(seat, next_focus);
 		}
@@ -457,6 +479,20 @@ bool seat_is_input_allowed(struct sway_seat *seat,
 	return !seat->exclusive_client || seat->exclusive_client == client;
 }
 
+// Unfocus the container and any children (eg. when leaving `focus parent`)
+static void seat_send_unfocus(struct sway_container *container,
+		struct sway_seat *seat) {
+	if (container->type == C_VIEW) {
+		wlr_seat_keyboard_clear_focus(seat->wlr_seat);
+		view_set_activated(container->sway_view, false);
+	} else {
+		for (int i = 0; i < container->children->length; ++i) {
+			struct sway_container *child = container->children->items[i];
+			seat_send_unfocus(child, seat);
+		}
+	}
+}
+
 void seat_set_focus_warp(struct sway_seat *seat,
 		struct sway_container *container, bool warp) {
 	if (seat->focused_layer) {
@@ -521,15 +557,11 @@ void seat_set_focus_warp(struct sway_seat *seat,
 		wl_list_remove(&seat_con->link);
 		wl_list_insert(&seat->focus_stack, &seat_con->link);
 
-		if (container->type == C_VIEW && !seat_is_input_allowed(
-					seat, container->sway_view->surface)) {
-			wlr_log(L_DEBUG, "Refusing to set focus, input is inhibited");
-			return;
+		if (last_focus) {
+			seat_send_unfocus(last_focus, seat);
 		}
 
-		if (container->type == C_VIEW) {
-			seat_send_focus(seat, container);
-		}
+		seat_send_focus(container, seat);
 		container_damage_whole(container);
 	}
 
@@ -580,12 +612,6 @@ void seat_set_focus_warp(struct sway_seat *seat,
 		container_damage_whole(last_focus);
 	}
 
-	if (last_focus && last_focus->type == C_VIEW &&
-			!input_manager_has_focus(seat->input, last_focus)) {
-		struct sway_view *view = last_focus->sway_view;
-		view_set_activated(view, false);
-	}
-
 	if (last_workspace && last_workspace != new_workspace) {
 		cursor_send_pointer_motion(seat->cursor, 0);
 	}
@@ -607,10 +633,7 @@ void seat_set_focus_surface(struct sway_seat *seat,
 	}
 	if (seat->has_focus) {
 		struct sway_container *focus = seat_get_focus(seat);
-		if (focus->type == C_VIEW) {
-			wlr_seat_keyboard_clear_focus(seat->wlr_seat);
-			view_set_activated(focus->sway_view, false);
-		}
+		seat_send_unfocus(focus, seat);
 		seat->has_focus = false;
 	}
 	struct wlr_keyboard *keyboard =
-- 
cgit v1.2.3