From f78d07d39bb4e401920efb1396cb85d9cadd8adf Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sun, 31 Jul 2016 18:10:33 -0400 Subject: [PATCH 1/4] Implement focus handling for containers The previous implementation of focus handling assumed that only views can be focused. Containers can also be focused with a command like `focus parent` or `focus child`. Change `set_focused_container()` to handle the case of the given container being a container with children and update borders accordingly. --- include/border.h | 5 +++++ sway/border.c | 20 +++++++++++++++++--- sway/focus.c | 29 ++++++++++++++--------------- 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/include/border.h b/include/border.h index b629ba469..b61b0f8ad 100644 --- a/include/border.h +++ b/include/border.h @@ -16,6 +16,11 @@ struct border { */ void border_clear(struct border *border); +/** + * Recursively update all of the borders within a container. + */ +void update_container_border(swayc_t *container); + void render_view_borders(wlc_handle view); void update_view_border(swayc_t *view); void map_update_view_border(swayc_t *view, void *data); diff --git a/sway/border.c b/sway/border.c index c1a62bc6e..c3e1004a4 100644 --- a/sway/border.c +++ b/sway/border.c @@ -308,6 +308,9 @@ void update_view_border(swayc_t *view) { swayc_t *focused = get_focused_view(&root_container); swayc_t *container = swayc_parent_by_type(view, C_CONTAINER); swayc_t *focused_inactive = NULL; + + bool is_child_of_focused = swayc_is_parent_of(get_focused_container(&root_container), view); + if (container) { focused_inactive = swayc_focus_by_type(container, C_VIEW); } else { @@ -334,7 +337,7 @@ void update_view_border(swayc_t *view) { cr = create_border_buffer(view, g, &surface); bool render_top = !should_hide_top_border(view, view->y); - if (view == focused) { + if (view == focused || is_child_of_focused) { render_borders(view, cr, &config->border_colors.focused, render_top); } else { render_borders(view, cr, &config->border_colors.focused_inactive, render_top); @@ -360,7 +363,7 @@ void update_view_border(swayc_t *view) { break; } - if (focused == view) { + if (focused == view || is_child_of_focused) { render_borders(view, cr, &config->border_colors.focused, true); } else if (focused_inactive == view) { render_borders(view, cr, &config->border_colors.focused_inactive, true); @@ -375,7 +378,7 @@ void update_view_border(swayc_t *view) { break; } - if (focused == view) { + if (focused == view || is_child_of_focused) { render_borders(view, cr, &config->border_colors.focused, false); render_title_bar(view, cr, &view->border_geometry, &config->border_colors.focused); @@ -403,6 +406,17 @@ void update_view_border(swayc_t *view) { } } +void update_container_border(swayc_t *container) { + if (container->type == C_VIEW) { + update_view_border(container); + return; + } else { + for (int i = 0; i < container->children->length; ++i) { + update_container_border(container->children->items[i]); + } + } +} + void render_view_borders(wlc_handle view) { swayc_t *c = swayc_by_handle(view); diff --git a/sway/focus.c b/sway/focus.c index 0f629e1e7..576a5e9b2 100644 --- a/sway/focus.c +++ b/sway/focus.c @@ -115,7 +115,7 @@ bool set_focused_container(swayc_t *c) { // Get workspace for c, get that workspaces current focused container. swayc_t *workspace = swayc_active_workspace_for(c); - swayc_t *focused = get_focused_view(workspace); + swayc_t *focused = get_focused_container(workspace); if (swayc_is_fullscreen(focused) && focused != c) { // if switching to a workspace with a fullscreen view, @@ -140,33 +140,32 @@ bool set_focused_container(swayc_t *c) { } // get new focused view and set focus to it. - p = get_focused_view(c); - if (p->type == C_VIEW && !(wlc_view_get_type(p->handle) & WLC_BIT_POPUP)) { + if (c->type == C_CONTAINER || (c->type == C_VIEW && !(wlc_view_get_type(p->handle) & WLC_BIT_POPUP))) { // unactivate previous focus if (focused->type == C_VIEW) { wlc_view_set_state(focused->handle, WLC_BIT_ACTIVATED, false); - update_view_border(focused); } + update_container_border(focused); // activate current focus - if (p->type == C_VIEW) { - wlc_view_set_state(p->handle, WLC_BIT_ACTIVATED, true); - // set focus if view_focus is unlocked - if (!locked_view_focus) { - wlc_view_focus(p->handle); - if (p->parent->layout != L_TABBED - && p->parent->layout != L_STACKED) { - update_view_border(p); - } + if (c->type == C_VIEW) { + wlc_view_set_state(c->handle, WLC_BIT_ACTIVATED, true); + } + // set focus if view_focus is unlocked + if (!locked_view_focus) { + wlc_view_focus(c->handle); + if (c->parent->layout != L_TABBED + && c->parent->layout != L_STACKED) { + update_container_border(c); } } // rearrange if parent container is tabbed/stacked - swayc_t *parent = swayc_tabbed_stacked_ancestor(p); + swayc_t *parent = swayc_tabbed_stacked_ancestor(c); if (parent != NULL) { arrange_backgrounds(); arrange_windows(parent, -1, -1); } - } else if (p->type == C_WORKSPACE) { + } else if (c->type == C_WORKSPACE) { // remove previous focus if view_focus is unlocked if (!locked_view_focus) { wlc_view_focus(0); From b39249508f458e302d843c440db8f992e1d545ca Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sun, 31 Jul 2016 20:32:40 -0400 Subject: [PATCH 2/4] Refactor functions to update container borders Replace `update_view_border()` with `update_container_border()`. The latter should handle both the case where the container is a view or if the container has children. --- include/border.h | 1 - sway/border.c | 14 +++++++------- sway/commands.c | 2 +- sway/handlers.c | 4 ++-- sway/layout.c | 8 ++++---- 5 files changed, 14 insertions(+), 15 deletions(-) diff --git a/include/border.h b/include/border.h index b61b0f8ad..b72dc5dcd 100644 --- a/include/border.h +++ b/include/border.h @@ -22,7 +22,6 @@ void border_clear(struct border *border); void update_container_border(swayc_t *container); void render_view_borders(wlc_handle view); -void update_view_border(swayc_t *view); void map_update_view_border(swayc_t *view, void *data); int get_font_text_height(const char *font); bool should_hide_top_border(swayc_t *con, double y); diff --git a/sway/border.c b/sway/border.c index c3e1004a4..f681e4f14 100644 --- a/sway/border.c +++ b/sway/border.c @@ -201,12 +201,6 @@ static void render_title_bar(swayc_t *view, cairo_t *cr, struct wlc_geometry *b, } } -void map_update_view_border(swayc_t *view, void *data) { - if (view->type == C_VIEW) { - update_view_border(view); - } -} - /** * Generate nested container title for tabbed/stacked layouts */ @@ -293,7 +287,7 @@ void update_tabbed_stacked_titlebars(swayc_t *c, cairo_t *cr, struct wlc_geometr } } -void update_view_border(swayc_t *view) { +static void update_view_border(swayc_t *view) { if (!view->visible) { return; } @@ -417,6 +411,12 @@ void update_container_border(swayc_t *container) { } } +void map_update_view_border(swayc_t *view, void *data) { + if (view->type == C_VIEW) { + update_view_border(view); + } +} + void render_view_borders(wlc_handle view) { swayc_t *c = swayc_by_handle(view); diff --git a/sway/commands.c b/sway/commands.c index 28dcc9966..a65e0a016 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -2340,7 +2340,7 @@ static struct cmd_results *_do_split(int argc, char **argv, int layout) { // update container title if tabbed/stacked if (swayc_tabbed_stacked_ancestor(focused)) { - update_view_border(focused); + update_container_border(focused); swayc_t *output = swayc_parent_by_type(focused, C_OUTPUT); // schedule render to make changes take effect right away, // otherwise we would have to wait for the view to render, diff --git a/sway/handlers.c b/sway/handlers.c index bdcdcaa43..87b7253bb 100644 --- a/sway/handlers.c +++ b/sway/handlers.c @@ -553,9 +553,9 @@ static void handle_view_properties_updated(wlc_handle view, uint32_t mask) { swayc_t *p = swayc_tabbed_stacked_ancestor(c); if (p) { // TODO: we only got the topmost tabbed/stacked container, update borders of all containers on the path - update_view_border(get_focused_view(p)); + update_container_border(get_focused_view(p)); } else if (c->border_type == B_NORMAL) { - update_view_border(c); + update_container_border(c); } ipc_event_window(c, "title"); } diff --git a/sway/layout.c b/sway/layout.c index 6502d930e..42954ebc8 100644 --- a/sway/layout.c +++ b/sway/layout.c @@ -441,7 +441,7 @@ static void update_border_geometry_floating(swayc_t *c, struct wlc_geometry *geo c->border_geometry = g; *geometry = c->actual_geometry; - update_view_border(c); + update_container_border(c); } void update_layout_geometry(swayc_t *parent, enum swayc_layouts prev_layout) { @@ -688,7 +688,7 @@ void update_geometry(swayc_t *container) { container->actual_geometry = geometry; if (container->type == C_VIEW) { - update_view_border(container); + update_container_border(container); } } @@ -867,7 +867,7 @@ static void arrange_windows_r(swayc_t *container, double width, double height) { // update focused view border last because it may // depend on the title bar geometry of its siblings. if (focused && container->children->length > 1) { - update_view_border(focused); + update_container_border(focused); } } break; @@ -911,7 +911,7 @@ static void arrange_windows_r(swayc_t *container, double width, double height) { // update focused view border last because it may // depend on the title bar geometry of its siblings. if (focused && container->children->length > 1) { - update_view_border(focused); + update_container_border(focused); } } break; From d731d6a846ec37e5a3c172fdd14801886d45ff93 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sun, 31 Jul 2016 21:25:40 -0400 Subject: [PATCH 3/4] Bugfix: descend focus stack on new window focus When switching back to a workspace after new window creation, it is now necessary to descend the focus stack into the focused container of the workspace to determine which container should get the focus. This is because the `set_focused_container()` function no longer automatically descends into the focus stack to find the correct view to focus. --- sway/handlers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/handlers.c b/sway/handlers.c index 87b7253bb..684e45ba9 100644 --- a/sway/handlers.c +++ b/sway/handlers.c @@ -415,7 +415,7 @@ static bool handle_view_created(wlc_handle handle) { // we were on one workspace, switched to another to add this view, // now let's return to where we were workspace_switch(current_ws); - set_focused_container(current_ws->focused); + set_focused_container(get_focused_container(current_ws)); } suspend_workspace_cleanup = false; From fe608c80ae66d77f826ca077bd1c6a4fa7db3dd6 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sun, 31 Jul 2016 21:42:51 -0400 Subject: [PATCH 4/4] Update view border when workspace is focused When a workspace is focused, update the borders of all its child containers to be focused to indicate the workspace container is focused. --- sway/focus.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sway/focus.c b/sway/focus.c index 576a5e9b2..45ec43e96 100644 --- a/sway/focus.c +++ b/sway/focus.c @@ -168,6 +168,7 @@ bool set_focused_container(swayc_t *c) { } else if (c->type == C_WORKSPACE) { // remove previous focus if view_focus is unlocked if (!locked_view_focus) { + update_container_border(c); wlc_view_focus(0); } }