diff --git a/src/handlers.c b/src/handlers.c index 8c3bb486..d6e88913 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -694,7 +694,11 @@ static void handle_client_message(xcb_client_message_event_t *event) { tree_render(); } else if (event->type == A__NET_ACTIVE_WINDOW) { + if (event->format != 32) + return; + DLOG("_NET_ACTIVE_WINDOW: Window 0x%08x should be activated\n", event->window); + Con *con = con_by_window_id(event->window); if (con == NULL) { DLOG("Could not get window for client message\n"); @@ -702,8 +706,9 @@ static void handle_client_message(xcb_client_message_event_t *event) { } Con *ws = con_get_workspace(con); - if (!workspace_is_visible(ws)) { - DLOG("Workspace not visible, ignoring _NET_ACTIVE_WINDOW\n"); + + if (ws == NULL) { + DLOG("Window is not being managed, ignoring _NET_ACTIVE_WINDOW\n"); return; } @@ -712,10 +717,26 @@ static void handle_client_message(xcb_client_message_event_t *event) { return; } - if (ws != con_get_workspace(focused)) + /* data32[0] indicates the source of the request (application or pager) */ + if (event->data.data32[0] == 2) { + /* Always focus the con if it is from a pager, because this is most + * likely from some user action */ + DLOG("This request came from a pager. Focusing con = %p\n", con); workspace_show(ws); + con_focus(con); + } else { + /* If the request is from an application, only focus if the + * workspace is visible. Otherwise set the urgency hint. */ + if (workspace_is_visible(ws)) { + DLOG("Request to focus con on a visible workspace. Focusing con = %p\n", con); + workspace_show(ws); + con_focus(con); + } else { + DLOG("Request to focus con on a hidden workspace. Setting urgent con = %p\n", con); + con_set_urgency(con, true); + } + } - con_focus(con); tree_render(); } else if (event->type == A_I3_SYNC) { xcb_window_t window = event->data.data32[0]; diff --git a/testcases/t/195-net-active-window.t b/testcases/t/195-net-active-window.t index c3061c00..21018118 100644 --- a/testcases/t/195-net-active-window.t +++ b/testcases/t/195-net-active-window.t @@ -21,7 +21,9 @@ use i3test; sub send_net_active_window { - my ($id) = @_; + my ($id, $source) = @_; + + $source = ($source eq 'pager' ? 2 : 0); my $msg = pack "CCSLLLLLLL", X11::XCB::CLIENT_MESSAGE, # response_type @@ -29,7 +31,7 @@ sub send_net_active_window { 0, # sequence $id, # destination window $x->atom(name => '_NET_ACTIVE_WINDOW')->id, - 0, + $source, 0, 0, 0, @@ -54,7 +56,8 @@ is($x->input_focus, $win1->id, 'window 1 has focus'); ################################################################################ # Switch to a different workspace and ensure sending the _NET_ACTIVE_WINDOW -# ClientMessage has no effect anymore. +# ClientMessage switches to that workspaces only if source indicates it is a +# pager and otherwise sets the urgent hint. ################################################################################ my $ws2 = fresh_workspace; @@ -62,9 +65,36 @@ my $win3 = open_window; is($x->input_focus, $win3->id, 'window 3 has focus'); +send_net_active_window($win1->id, 'pager'); + +is($x->input_focus, $win1->id, 'focus switched to window 1 when message source was a pager'); + +cmd '[id="' . $win3->id . '"] focus'; + send_net_active_window($win1->id); -is($x->input_focus, $win3->id, 'window 3 still has focus'); +is($x->input_focus, $win3->id, + 'focus did not switch to window 1 on a hidden workspace when message source was an application'); + +ok(get_ws($ws1)->{urgent}, 'urgent hint set on ws 1'); + + +################################################################################ +# Make sure the ClientMessage only works with managed windows, and specifying a +# window that is not managed does not crash i3 (#774) +################################################################################ + +my $dock = open_window(window_type => $x->atom(name => '_NET_WM_WINDOW_TYPE_DOCK')); + +send_net_active_window($dock->id); + +does_i3_live; +is($x->input_focus, $win3->id, 'dock did not get input focus'); + +send_net_active_window($x->get_root_window()); + +does_i3_live; +is($x->input_focus, $win3->id, 'root window did not get input focus'); ################################################################################ # Move a window to the scratchpad, send a _NET_ACTIVE_WINDOW for it and verify