From 922afe1919d7969a9bfd6083504e563642f07eff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Thu, 17 Sep 2015 22:52:56 +0200 Subject: [PATCH] Keep a sticky window focused if it was the focused window on the source workspace. fixes #1924 --- include/output.h | 2 +- src/commands.c | 2 +- src/handlers.c | 2 +- src/output.c | 23 +++++++++++++---------- src/workspace.c | 3 ++- testcases/t/251-sticky.t | 27 ++++++++++++++++++++++----- 6 files changed, 40 insertions(+), 19 deletions(-) diff --git a/include/output.h b/include/output.h index 38e2689a..8299a19b 100644 --- a/include/output.h +++ b/include/output.h @@ -27,4 +27,4 @@ Output *get_output_from_string(Output *current_output, const char *output_str); * workspace on that output. * */ -void output_push_sticky_windows(void); +void output_push_sticky_windows(Con *to_focus); diff --git a/src/commands.c b/src/commands.c index 1472a812..bbe3ee80 100644 --- a/src/commands.c +++ b/src/commands.c @@ -1598,7 +1598,7 @@ void cmd_sticky(I3_CMD, char *action) { /* A window we made sticky might not be on a visible workspace right now, so we need to make * sure it gets pushed to the front now. */ - output_push_sticky_windows(); + output_push_sticky_windows(focused); cmd_output->needs_tree_render = true; ysuccess(true); diff --git a/src/handlers.c b/src/handlers.c index d0b66374..f8c45bcf 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -736,7 +736,7 @@ static void handle_client_message(xcb_client_message_event_t *event) { con->sticky = !con->sticky; DLOG("New sticky status for con = %p is %i.\n", con, con->sticky); - output_push_sticky_windows(); + output_push_sticky_windows(focused); } tree_render(); diff --git a/src/output.c b/src/output.c index e29ab746..62b146a7 100644 --- a/src/output.c +++ b/src/output.c @@ -52,31 +52,34 @@ Output *get_output_from_string(Output *current_output, const char *output_str) { * workspace on that output. * */ -void output_push_sticky_windows(void) { +void output_push_sticky_windows(Con *to_focus) { Con *output; - TAILQ_FOREACH(output, &(croot->nodes_head), nodes) { + TAILQ_FOREACH(output, &(croot->focus_head), focused) { Con *workspace, *visible_ws = NULL; GREP_FIRST(visible_ws, output_get_content(output), workspace_is_visible(child)); /* We use this loop instead of TAILQ_FOREACH to avoid problems if the * sticky window was the last window on that workspace as moving it in * this case will close the workspace. */ - for (workspace = TAILQ_FIRST(&(output_get_content(output)->nodes_head)); - workspace != TAILQ_END(&(output_get_content(output)->nodes_head));) { + for (workspace = TAILQ_FIRST(&(output_get_content(output)->focus_head)); + workspace != TAILQ_END(&(output_get_content(output)->focus_head));) { Con *current_ws = workspace; - workspace = TAILQ_NEXT(workspace, nodes); + workspace = TAILQ_NEXT(workspace, focused); /* Since moving the windows actually removes them from the list of * floating windows on this workspace, here too we need to use * another loop than TAILQ_FOREACH. */ Con *child; - for (child = TAILQ_FIRST(&(current_ws->floating_head)); - child != TAILQ_END(&(current_ws->floating_head));) { + for (child = TAILQ_FIRST(&(current_ws->focus_head)); + child != TAILQ_END(&(current_ws->focus_head));) { Con *current = child; - child = TAILQ_NEXT(child, floating_windows); + child = TAILQ_NEXT(child, focused); + if (current->type != CT_FLOATING_CON) + continue; - if (con_is_sticky(current)) - con_move_to_workspace(current, visible_ws, true, false, true); + if (con_is_sticky(current)) { + con_move_to_workspace(current, visible_ws, true, false, current != to_focus->parent); + } } } } diff --git a/src/workspace.c b/src/workspace.c index 1a3b15d5..d3a97453 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -363,6 +363,7 @@ static void workspace_defer_update_urgent_hint_cb(EV_P_ ev_timer *w, int revents static void _workspace_show(Con *workspace) { Con *current, *old = NULL; + Con *old_focus = focused; /* safe-guard against showing i3-internal workspaces like __i3_scratch */ if (con_is_internal(workspace)) @@ -478,7 +479,7 @@ static void _workspace_show(Con *workspace) { ewmh_update_current_desktop(); /* Push any sticky windows to the now visible workspace. */ - output_push_sticky_windows(); + output_push_sticky_windows(old_focus); } /* diff --git a/testcases/t/251-sticky.t b/testcases/t/251-sticky.t index 6729556d..85fc11f7 100644 --- a/testcases/t/251-sticky.t +++ b/testcases/t/251-sticky.t @@ -18,7 +18,7 @@ # Ticket: #1455 use i3test; -my ($ws, $focused); +my ($ws, $tmp, $focused); ############################################################################### # 1: Given a sticky tiling container, when the workspace is switched, then @@ -62,9 +62,9 @@ is(@{get_ws($ws)->{floating_nodes}}, 2, 'multiple sticky windows can be used at cmd '[class="findme"] kill'; ############################################################################### -# 4: Given a sticky floating container and a tiling container on the target -# workspace, when the workspace is switched, then the tiling container is -# focused. +# 4: Given an unfocused sticky floating container and a tiling container on the +# target workspace, when the workspace is switched, then the tiling container +# is focused. ############################################################################### $ws = fresh_workspace; open_window; @@ -72,13 +72,30 @@ $focused = get_focused($ws); fresh_workspace; open_floating_window(wm_class => 'findme'); cmd 'sticky enable'; +open_window; cmd 'workspace ' . $ws; is(get_focused($ws), $focused, 'the tiling container has focus'); cmd '[class="findme"] kill'; ############################################################################### -# 5: Given a floating container on a non-visible workspace, when the window +# 5: Given a focused sticky floating container and a tiling container on the +# target workspace, when the workspace is switched, then the tiling container +# is focused. +############################################################################### +$ws = fresh_workspace; +open_window; +$tmp = fresh_workspace; +open_floating_window(wm_class => 'findme'); +$focused = get_focused($tmp); +cmd 'sticky enable'; +cmd 'workspace ' . $ws; + +is(get_focused($ws), $focused, 'the sticky container has focus'); +cmd '[class="findme"] kill'; + +############################################################################### +# 6: Given a floating container on a non-visible workspace, when the window # is made sticky, then the window immediately jumps to the currently # visible workspace. ###############################################################################