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 =