Feature: improve active window request handling
Patch status: merged
Patch by Tony Crisci
Long description:
Allow client requests of type _NET_ACTIVE_WINDOW to switch workspaces if they indicate they are a pager. Otherwise, set the urgency hint on that con to indicate that something happened. This allows task switchers like skippy-xd to work properly. http://standards.freedesktop.org/wm-spec/latest/ar01s03.html#idm140251368127856
To apply this patch, use:
curl http://cr.i3wm.org/patch/534/raw.patch | git am
b/src/handlers.c
21 |
@@ -694,7 +694,11 @@ static void handle_client_message(xcb_client_message_event_t *event) { |
22 |
|
23 |
tree_render(); |
24 |
} else if (event->type == A__NET_ACTIVE_WINDOW) { |
25 |
+ if (event->format != 32) |
26 |
+ return; |
27 |
+ |
28 |
DLOG("_NET_ACTIVE_WINDOW: Window 0x%08x should be activated\n", event->window); |
29 |
+ |
30 |
Con *con = con_by_window_id(event->window); |
31 |
if (con == NULL) { |
32 |
DLOG("Could not get window for client message\n"); |
33 |
@@ -702,8 +706,9 @@ static void handle_client_message(xcb_client_message_event_t *event) { |
34 |
} |
35 |
|
36 |
Con *ws = con_get_workspace(con); |
37 |
- if (!workspace_is_visible(ws)) { |
38 |
- DLOG("Workspace not visible, ignoring _NET_ACTIVE_WINDOW\n"); |
39 |
+ |
40 |
+ if (ws == NULL) { |
41 |
+ DLOG("Window is not being managed, ignoring _NET_ACTIVE_WINDOW\n"); |
42 |
return; |
43 |
} |
44 |
|
45 |
@@ -712,10 +717,26 @@ static void handle_client_message(xcb_client_message_event_t *event) { |
46 |
return; |
47 |
} |
48 |
|
49 |
- if (ws != con_get_workspace(focused)) |
50 |
+ /* data32[0] indicates the source of the request (application or pager) */ |
51 |
+ if (event->data.data32[0] == 2) { |
52 |
+ /* Always focus the con if it is from a pager, because this is most |
53 |
+ * likely from some user action */ |
54 |
+ DLOG("This request came from a pager. Focusing con = %p\n", con); |
55 |
workspace_show(ws); |
56 |
+ con_focus(con); |
57 |
+ } else { |
58 |
+ /* If the request is from an application, only focus if the |
59 |
+ * workspace is visible. Otherwise set the urgnecy hint. */ |
60 |
+ if (workspace_is_visible(ws)) { |
61 |
+ DLOG("Request to focus con on a visible workspace. Focusing con = %p\n", con); |
62 |
+ workspace_show(ws); |
63 |
+ con_focus(con); |
64 |
+ } else { |
65 |
+ DLOG("Request to focus con on a hidden workspace. Setting urgent con = %p\n", con); |
66 |
+ con_set_urgency(con, true); |
67 |
+ } |
68 |
+ } |
69 |
|
70 |
- con_focus(con); |
71 |
tree_render(); |
72 |
} else if (event->type == A_I3_SYNC) { |
73 |
xcb_window_t window = event->data.data32[0]; |
b/testcases/t/195-net-active-window.t
78 |
@@ -21,7 +21,9 @@ |
79 |
use i3test; |
80 |
|
81 |
sub send_net_active_window { |
82 |
- my ($id) = @_; |
83 |
+ my ($id, $source) = @_; |
84 |
+ |
85 |
+ $source = ($source eq 'pager' ? 2 : 0); |
86 |
|
87 |
my $msg = pack "CCSLLLLLLL", |
88 |
X11::XCB::CLIENT_MESSAGE, # response_type |
89 |
@@ -29,7 +31,7 @@ sub send_net_active_window { |
90 |
0, # sequence |
91 |
$id, # destination window |
92 |
$x->atom(name => '_NET_ACTIVE_WINDOW')->id, |
93 |
- 0, |
94 |
+ $source, |
95 |
0, |
96 |
0, |
97 |
0, |
98 |
@@ -54,7 +56,8 @@ is($x->input_focus, $win1->id, 'window 1 has focus'); |
99 |
|
100 |
################################################################################ |
101 |
# Switch to a different workspace and ensure sending the _NET_ACTIVE_WINDOW |
102 |
-# ClientMessage has no effect anymore. |
103 |
+# ClientMessage switches to that workspaces only if source indicates it is a |
104 |
+# pager and otherwise sets the urgent hint. |
105 |
################################################################################ |
106 |
|
107 |
my $ws2 = fresh_workspace; |
108 |
@@ -62,9 +65,36 @@ my $win3 = open_window; |
109 |
|
110 |
is($x->input_focus, $win3->id, 'window 3 has focus'); |
111 |
|
112 |
+send_net_active_window($win1->id, 'pager'); |
113 |
+ |
114 |
+is($x->input_focus, $win1->id, 'focus switched to window 1 when message source was a pager'); |
115 |
+ |
116 |
+cmd '[id="' . $win3->id . '"] focus'; |
117 |
+ |
118 |
send_net_active_window($win1->id); |
119 |
|
120 |
-is($x->input_focus, $win3->id, 'window 3 still has focus'); |
121 |
+is($x->input_focus, $win3->id, |
122 |
+ 'focus did not switch to window 1 on a hidden workspace when message source was an application'); |
123 |
+ |
124 |
+ok(get_ws($ws1)->{urgent}, 'urgent hint set on ws 1'); |
125 |
+ |
126 |
+ |
127 |
+################################################################################ |
128 |
+# Make sure the ClientMessage only works with managed windows, and specifying a |
129 |
+# window that is not managed does not crash i3 (#774) |
130 |
+################################################################################ |
131 |
+ |
132 |
+my $dock = open_window(window_type => $x->atom(name => '_NET_WM_WINDOW_TYPE_DOCK')); |
133 |
+ |
134 |
+send_net_active_window($dock->id); |
135 |
+ |
136 |
+does_i3_live; |
137 |
+is($x->input_focus, $win3->id, 'dock did not get input focus'); |
138 |
+ |
139 |
+send_net_active_window($x->get_root_window()); |
140 |
+ |
141 |
+does_i3_live; |
142 |
+is($x->input_focus, $win3->id, 'root window did not get input focus'); |
143 |
|
144 |
################################################################################ |
145 |
# Move a window to the scratchpad, send a _NET_ACTIVE_WINDOW for it and verify |