Bugfix: `move <direction>` sends workspace focus
Patch status: merged
Patch by Tony Crisci
Long description:
Make sure the command `move <direction>` properly sends the workspace focus ipc event required for i3bar to be properly updated and redrawn. Make `ipc_send_workspace_focus_event publicly available from ipc.h for more flexible event sending.
To apply this patch, use:
curl http://cr.i3wm.org/patch/377/raw.patch | git am
b/include/ipc.h
23 |
@@ -80,3 +80,10 @@ void ipc_send_event(const char *event, uint32_t message_type, const char *payloa |
24 |
void ipc_shutdown(void); |
25 |
|
26 |
void dump_node(yajl_gen gen, Con *con, bool inplace_restart); |
27 |
+ |
28 |
+/** |
29 |
+ * For the workspace "focus" event we send, along the usual "change" field, |
30 |
+ * also the current and previous workspace, in "current" and "old" |
31 |
+ * respectively. |
32 |
+ */ |
33 |
+void ipc_send_workspace_focus_event(Con *current, Con *old); |
b/src/ipc.c
38 |
@@ -1022,3 +1022,37 @@ int ipc_create_socket(const char *filename) { |
39 |
current_socketpath = resolved; |
40 |
return sockfd; |
41 |
} |
42 |
+ |
43 |
+/* |
44 |
+ * For the workspace "focus" event we send, along the usual "change" field, |
45 |
+ * also the current and previous workspace, in "current" and "old" |
46 |
+ * respectively. |
47 |
+ */ |
48 |
+void ipc_send_workspace_focus_event(Con *current, Con *old) { |
49 |
+ setlocale(LC_NUMERIC, "C"); |
50 |
+ yajl_gen gen = ygenalloc(); |
51 |
+ |
52 |
+ y(map_open); |
53 |
+ |
54 |
+ ystr("change"); |
55 |
+ ystr("focus"); |
56 |
+ |
57 |
+ ystr("current"); |
58 |
+ dump_node(gen, current, false); |
59 |
+ |
60 |
+ ystr("old"); |
61 |
+ if (old == NULL) |
62 |
+ y(null); |
63 |
+ else |
64 |
+ dump_node(gen, old, false); |
65 |
+ |
66 |
+ y(map_close); |
67 |
+ |
68 |
+ const unsigned char *payload; |
69 |
+ ylength length; |
70 |
+ y(get_buf, &payload, &length); |
71 |
+ |
72 |
+ ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, (const char *)payload); |
73 |
+ y(free); |
74 |
+ setlocale(LC_NUMERIC, ""); |
75 |
+} |
b/src/move.c
80 |
@@ -99,6 +99,7 @@ static void attach_to_workspace(Con *con, Con *ws, direction_t direction) { |
81 |
* |
82 |
*/ |
83 |
static void move_to_output_directed(Con *con, direction_t direction) { |
84 |
+ Con *old_ws = con_get_workspace(con); |
85 |
Con *current_output_con = con_get_output(con); |
86 |
Output *current_output = get_output_by_name(current_output_con->name); |
87 |
Output *output = get_output_next(direction, current_output, CLOSEST_OUTPUT); |
88 |
@@ -117,6 +118,16 @@ static void move_to_output_directed(Con *con, direction_t direction) { |
89 |
} |
90 |
|
91 |
attach_to_workspace(con, ws, direction); |
92 |
+ |
93 |
+ /* fix the focus stack */ |
94 |
+ con_focus(con); |
95 |
+ |
96 |
+ /* force re-painting the indicators */ |
97 |
+ FREE(con->deco_render_params); |
98 |
+ |
99 |
+ tree_flatten(croot); |
100 |
+ |
101 |
+ ipc_send_workspace_focus_event(ws, old_ws); |
102 |
} |
103 |
|
104 |
/* |
105 |
@@ -141,7 +152,7 @@ void tree_move(int direction) { |
106 |
if (con->parent->type == CT_WORKSPACE && con_num_children(con->parent) == 1) { |
107 |
/* This is the only con on this workspace */ |
108 |
move_to_output_directed(con, direction); |
109 |
- goto end; |
110 |
+ return; |
111 |
} |
112 |
|
113 |
orientation_t o = (direction == D_LEFT || direction == D_RIGHT ? HORIZ : VERT); |
114 |
@@ -201,7 +212,7 @@ void tree_move(int direction) { |
115 |
/* If we couldn't find a place to move it on this workspace, |
116 |
* try to move it to a workspace on a different output */ |
117 |
move_to_output_directed(con, direction); |
118 |
- goto end; |
119 |
+ return; |
120 |
} |
121 |
|
122 |
/* If there was no con with which we could swap the current one, |
b/src/workspace.c
127 |
@@ -11,9 +11,6 @@ |
128 |
* |
129 |
*/ |
130 |
#include "all.h" |
131 |
-#include "yajl_utils.h" |
132 |
- |
133 |
-#include <yajl/yajl_gen.h> |
134 |
|
135 |
/* Stores a copy of the name of the last used workspace for the workspace |
136 |
* back-and-forth switching. */ |
137 |
@@ -335,39 +332,6 @@ static void workspace_defer_update_urgent_hint_cb(EV_P_ ev_timer *w, int revents |
138 |
FREE(con->urgency_timer); |
139 |
} |
140 |
|
141 |
-/* |
142 |
- * For the "focus" event we send, along the usual "change" field, also the |
143 |
- * current and previous workspace, in "current" and "old" respectively. |
144 |
- */ |
145 |
-static void ipc_send_workspace_focus_event(Con *current, Con *old) { |
146 |
- setlocale(LC_NUMERIC, "C"); |
147 |
- yajl_gen gen = ygenalloc(); |
148 |
- |
149 |
- y(map_open); |
150 |
- |
151 |
- ystr("change"); |
152 |
- ystr("focus"); |
153 |
- |
154 |
- ystr("current"); |
155 |
- dump_node(gen, current, false); |
156 |
- |
157 |
- ystr("old"); |
158 |
- if (old == NULL) |
159 |
- y(null); |
160 |
- else |
161 |
- dump_node(gen, old, false); |
162 |
- |
163 |
- y(map_close); |
164 |
- |
165 |
- const unsigned char *payload; |
166 |
- ylength length; |
167 |
- y(get_buf, &payload, &length); |
168 |
- |
169 |
- ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, (const char *)payload); |
170 |
- y(free); |
171 |
- setlocale(LC_NUMERIC, ""); |
172 |
-} |
173 |
- |
174 |
static void _workspace_show(Con *workspace) { |
175 |
Con *current, *old = NULL; |
176 |
|
b/testcases/t/517-regress-move-direction-ipc.t
182 |
@@ -0,0 +1,79 @@ |
183 |
+#!perl |
184 |
+# vim:ts=4:sw=4:expandtab |
185 |
+# |
186 |
+# Please read the following documents before working on tests: |
187 |
+# • http://build.i3wm.org/docs/testsuite.html |
188 |
+# (or docs/testsuite) |
189 |
+# |
190 |
+# • http://build.i3wm.org/docs/lib-i3test.html |
191 |
+# (alternatively: perldoc ./testcases/lib/i3test.pm) |
192 |
+# |
193 |
+# • http://build.i3wm.org/docs/ipc.html |
194 |
+# (or docs/ipc) |
195 |
+# |
196 |
+# • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf |
197 |
+# (unless you are already familiar with Perl) |
198 |
+# |
199 |
+# Make sure the command `move <direction>` properly sends the workspace focus |
200 |
+# ipc event required for i3bar to be properly updated and redrawn. |
201 |
+# |
202 |
+# Bug still in: 4.6-195-g34232b8 |
203 |
+use i3test i3_autostart => 0; |
204 |
+ |
205 |
+my $config = <<EOT; |
206 |
+# i3 config file (v4) |
207 |
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 |
208 |
+ |
209 |
+fake-outputs 1024x768+0+0,1024x768+1024+0 |
210 |
+workspace ws-left output fake-0 |
211 |
+workspace ws-right output fake-1 |
212 |
+EOT |
213 |
+ |
214 |
+my $pid = launch_with_config($config); |
215 |
+ |
216 |
+my $i3 = i3(get_socket_path()); |
217 |
+$i3->connect()->recv; |
218 |
+ |
219 |
+# subscribe to the 'focus' ipc event |
220 |
+my $focus = AnyEvent->condvar; |
221 |
+$i3->subscribe({ |
222 |
+ workspace => sub { |
223 |
+ my ($event) = @_; |
224 |
+ if ($event->{change} eq 'focus') { |
225 |
+ $focus->send($event); |
226 |
+ } |
227 |
+ } |
228 |
+})->recv; |
229 |
+ |
230 |
+# give up after 0.5 seconds |
231 |
+my $timer = AnyEvent->timer( |
232 |
+ after => 0.5, |
233 |
+ cb => sub { |
234 |
+ $focus->send(0); |
235 |
+ } |
236 |
+); |
237 |
+ |
238 |
+# open two windows on the left output |
239 |
+cmd 'workspace ws-left'; |
240 |
+open_window; |
241 |
+open_window; |
242 |
+ |
243 |
+# move a window over to the right output |
244 |
+cmd 'move right'; |
245 |
+my $event = $focus->recv; |
246 |
+ |
247 |
+ok($event, 'moving from workspace with two windows triggered focus ipc event'); |
248 |
+is($event->{current}->{name}, 'ws-right', 'focus event gave the right workspace'); |
249 |
+is(@{$event->{current}->{nodes}}, 1, 'focus event gave the right number of windows on the workspace'); |
250 |
+ |
251 |
+# reset and try again |
252 |
+$focus = AnyEvent->condvar; |
253 |
+cmd 'workspace ws-left; move right'; |
254 |
+$event = $focus->recv; |
255 |
+ok($event, 'moving from workspace with one window triggered focus ipc event'); |
256 |
+is($event->{current}->{name}, 'ws-right', 'focus event gave the right workspace'); |
257 |
+is(@{$event->{current}->{nodes}}, 2, 'focus event gave the right number of windows on the workspace'); |
258 |
+ |
259 |
+exit_gracefully($pid); |
260 |
+ |
261 |
+done_testing; |