Include workspace con in workspace event
Patch status: merged
Patch by Tony Crisci
Long description:
Send the affected workspace in the "current" property for each workspace event for any type of workspace event that affects a particular workspace. fixes #1411
To apply this patch, use:
curl http://cr.i3wm.org/patch/694/raw.patch | git am
b/docs/ipc
26 |
@@ -668,15 +668,16 @@ if ($is_event) { |
27 |
|
28 |
This event consists of a single serialized map containing a property |
29 |
+change (string)+ which indicates the type of the change ("focus", "init", |
30 |
-"empty", "urgent"). |
31 |
- |
32 |
-Moreover, when the change is "focus", an +old (object)+ and a +current |
33 |
-(object)+ properties will be present with the previous and current |
34 |
-workspace respectively. When the first switch occurs (when i3 focuses |
35 |
-the workspace visible at the beginning) there is no previous |
36 |
-workspace, and the +old+ property will be set to +null+. Also note |
37 |
-that if the previous is empty it will get destroyed when switching, |
38 |
-but will still be present in the "old" property. |
39 |
+"empty", "urgent"). A +current (object)+ property will be present with the |
40 |
+affected workspace whenever the type of event affects a workspace (otherwise, |
41 |
+it will be +null). |
42 |
+ |
43 |
+When the change is "focus", an +old (object)+ property will be present with the |
44 |
+previous workspace. When the first switch occurs (when i3 focuses the |
45 |
+workspace visible at the beginning) there is no previous workspace, and the |
46 |
++old+ property will be set to +null+. Also note that if the previous is empty |
47 |
+it will get destroyed when switching, but will still be present in the "old" |
48 |
+property. |
49 |
|
50 |
*Example:* |
51 |
--------------------- |
b/include/ipc.h
56 |
@@ -89,11 +89,17 @@ void ipc_shutdown(void); |
57 |
void dump_node(yajl_gen gen, Con *con, bool inplace_restart); |
58 |
|
59 |
/** |
60 |
- * For the workspace "focus" event we send, along the usual "change" field, |
61 |
- * also the current and previous workspace, in "current" and "old" |
62 |
- * respectively. |
63 |
+ * Generates a json workspace event. Returns a dynamically allocated yajl |
64 |
+ * generator. Free with yajl_gen_free(). |
65 |
*/ |
66 |
-void ipc_send_workspace_focus_event(Con *current, Con *old); |
67 |
+yajl_gen ipc_marshal_workspace_event(const char *change, Con *current, Con *old); |
68 |
+ |
69 |
+/** |
70 |
+ * For the workspace events we send, along with the usual "change" field, also |
71 |
+ * the workspace container in "current". For focus events, we send the |
72 |
+ * previously focused workspace in "old". |
73 |
+ */ |
74 |
+void ipc_send_workspace_event(const char *change, Con *current, Con *old); |
75 |
|
76 |
/** |
77 |
* For the window events we send, along the usual "change" field, |
b/src/commands.c
82 |
@@ -944,7 +944,7 @@ void cmd_append_layout(I3_CMD, char *path) { |
83 |
restore_open_placeholder_windows(parent); |
84 |
|
85 |
if (content == JSON_CONTENT_WORKSPACE) |
86 |
- ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"restored\"}"); |
87 |
+ ipc_send_workspace_event("restored", parent, NULL); |
88 |
|
89 |
cmd_output->needs_tree_render = true; |
90 |
} |
91 |
@@ -1313,7 +1313,7 @@ void cmd_move_workspace_to_output(I3_CMD, char *name) { |
92 |
create_workspace_on_output(current_output, ws->parent); |
93 |
|
94 |
/* notify the IPC listeners */ |
95 |
- ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"init\"}"); |
96 |
+ ipc_send_workspace_event("init", ws, NULL); |
97 |
} |
98 |
DLOG("Detaching\n"); |
99 |
|
100 |
@@ -1334,7 +1334,7 @@ void cmd_move_workspace_to_output(I3_CMD, char *name) { |
101 |
TAILQ_FOREACH(floating_con, &(ws->floating_head), floating_windows) |
102 |
floating_fix_coordinates(floating_con, &(old_content->rect), &(content->rect)); |
103 |
|
104 |
- ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"move\"}"); |
105 |
+ ipc_send_workspace_event("move", ws, NULL); |
106 |
if (workspace_was_visible) { |
107 |
/* Focus the moved workspace on the destination output. */ |
108 |
workspace_show(ws); |
109 |
@@ -1761,7 +1761,7 @@ void cmd_reload(I3_CMD) { |
110 |
load_configuration(conn, NULL, true); |
111 |
x_set_i3_atoms(); |
112 |
/* Send an IPC event just in case the ws names have changed */ |
113 |
- ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"reload\"}"); |
114 |
+ ipc_send_workspace_event("reload", NULL, NULL); |
115 |
/* Send an update event for the barconfig just in case it has changed */ |
116 |
update_barconfig(); |
117 |
|
118 |
@@ -2040,7 +2040,7 @@ void cmd_rename_workspace(I3_CMD, char *old_name, char *new_name) { |
119 |
cmd_output->needs_tree_render = true; |
120 |
ysuccess(true); |
121 |
|
122 |
- ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"rename\"}"); |
123 |
+ ipc_send_workspace_event("rename", workspace, NULL); |
124 |
ewmh_update_desktop_names(); |
125 |
ewmh_update_desktop_viewport(); |
126 |
ewmh_update_current_desktop(); |
b/src/con.c
131 |
@@ -12,6 +12,7 @@ |
132 |
* |
133 |
*/ |
134 |
#include "all.h" |
135 |
+#include "yajl_utils.h" |
136 |
|
137 |
static void con_on_remove_child(Con *con); |
138 |
|
139 |
@@ -1435,8 +1436,15 @@ static void con_on_remove_child(Con *con) { |
140 |
if (con->type == CT_WORKSPACE) { |
141 |
if (TAILQ_EMPTY(&(con->focus_head)) && !workspace_is_visible(con)) { |
142 |
LOG("Closing old workspace (%p / %s), it is empty\n", con, con->name); |
143 |
+ yajl_gen gen = ipc_marshal_workspace_event("empty", con, NULL); |
144 |
tree_close(con, DONT_KILL_WINDOW, false, false); |
145 |
- ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"empty\"}"); |
146 |
+ |
147 |
+ const unsigned char *payload; |
148 |
+ ylength length; |
149 |
+ y(get_buf, &payload, &length); |
150 |
+ ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, (const char *)payload); |
151 |
+ |
152 |
+ y(free); |
153 |
} |
154 |
return; |
155 |
} |
b/src/ipc.c
160 |
@@ -1120,21 +1120,23 @@ int ipc_create_socket(const char *filename) { |
161 |
} |
162 |
|
163 |
/* |
164 |
- * For the workspace "focus" event we send, along the usual "change" field, |
165 |
- * also the current and previous workspace, in "current" and "old" |
166 |
- * respectively. |
167 |
+ * Generates a json workspace event. Returns a dynamically allocated yajl |
168 |
+ * generator. Free with yajl_gen_free(). |
169 |
*/ |
170 |
-void ipc_send_workspace_focus_event(Con *current, Con *old) { |
171 |
+yajl_gen ipc_marshal_workspace_event(const char *change, Con *current, Con *old) { |
172 |
setlocale(LC_NUMERIC, "C"); |
173 |
yajl_gen gen = ygenalloc(); |
174 |
|
175 |
y(map_open); |
176 |
|
177 |
ystr("change"); |
178 |
- ystr("focus"); |
179 |
+ ystr(change); |
180 |
|
181 |
ystr("current"); |
182 |
- dump_node(gen, current, false); |
183 |
+ if (current == NULL) |
184 |
+ y(null); |
185 |
+ else |
186 |
+ dump_node(gen, current, false); |
187 |
|
188 |
ystr("old"); |
189 |
if (old == NULL) |
190 |
@@ -1144,13 +1146,26 @@ void ipc_send_workspace_focus_event(Con *current, Con *old) { |
191 |
|
192 |
y(map_close); |
193 |
|
194 |
+ setlocale(LC_NUMERIC, ""); |
195 |
+ |
196 |
+ return gen; |
197 |
+} |
198 |
+ |
199 |
+/* |
200 |
+ * For the workspace events we send, along with the usual "change" field, also |
201 |
+ * the workspace container in "current". For focus events, we send the |
202 |
+ * previously focused workspace in "old". |
203 |
+ */ |
204 |
+void ipc_send_workspace_event(const char *change, Con *current, Con *old) { |
205 |
+ yajl_gen gen = ipc_marshal_workspace_event(change, current, old); |
206 |
+ |
207 |
const unsigned char *payload; |
208 |
ylength length; |
209 |
y(get_buf, &payload, &length); |
210 |
|
211 |
ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, (const char *)payload); |
212 |
+ |
213 |
y(free); |
214 |
- setlocale(LC_NUMERIC, ""); |
215 |
} |
216 |
|
217 |
/** |
b/src/move.c
222 |
@@ -128,7 +128,7 @@ static void move_to_output_directed(Con *con, direction_t direction) { |
223 |
|
224 |
tree_flatten(croot); |
225 |
|
226 |
- ipc_send_workspace_focus_event(ws, old_ws); |
227 |
+ ipc_send_workspace_event("focus", ws, old_ws); |
228 |
} |
229 |
|
230 |
/* |
b/src/workspace.c
235 |
@@ -11,6 +11,7 @@ |
236 |
* |
237 |
*/ |
238 |
#include "all.h" |
239 |
+#include "yajl_utils.h" |
240 |
|
241 |
/* Stores a copy of the name of the last used workspace for the workspace |
242 |
* back-and-forth switching. */ |
243 |
@@ -91,7 +92,7 @@ Con *workspace_get(const char *num, bool *created) { |
244 |
|
245 |
con_attach(workspace, content, false); |
246 |
|
247 |
- ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"init\"}"); |
248 |
+ ipc_send_workspace_event("init", workspace, NULL); |
249 |
ewmh_update_number_of_desktops(); |
250 |
ewmh_update_desktop_names(); |
251 |
ewmh_update_desktop_viewport(); |
252 |
@@ -409,7 +410,7 @@ static void _workspace_show(Con *workspace) { |
253 |
} else |
254 |
con_focus(next); |
255 |
|
256 |
- ipc_send_workspace_focus_event(workspace, current); |
257 |
+ ipc_send_workspace_event("focus", workspace, current); |
258 |
|
259 |
DLOG("old = %p / %s\n", old, (old ? old->name : "(null)")); |
260 |
/* Close old workspace if necessary. This must be done *after* doing |
261 |
@@ -421,8 +422,16 @@ static void _workspace_show(Con *workspace) { |
262 |
/* check if this workspace is currently visible */ |
263 |
if (!workspace_is_visible(old)) { |
264 |
LOG("Closing old workspace (%p / %s), it is empty\n", old, old->name); |
265 |
+ yajl_gen gen = ipc_marshal_workspace_event("empty", old, NULL); |
266 |
tree_close(old, DONT_KILL_WINDOW, false, false); |
267 |
- ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"empty\"}"); |
268 |
+ |
269 |
+ const unsigned char *payload; |
270 |
+ ylength length; |
271 |
+ y(get_buf, &payload, &length); |
272 |
+ ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, (const char *)payload); |
273 |
+ |
274 |
+ y(free); |
275 |
+ |
276 |
ewmh_update_number_of_desktops(); |
277 |
ewmh_update_desktop_names(); |
278 |
ewmh_update_desktop_viewport(); |
279 |
@@ -766,7 +775,7 @@ void workspace_update_urgent_flag(Con *ws) { |
280 |
DLOG("Workspace urgency flag changed from %d to %d\n", old_flag, ws->urgent); |
281 |
|
282 |
if (old_flag != ws->urgent) |
283 |
- ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"urgent\"}"); |
284 |
+ ipc_send_workspace_event("urgent", ws, NULL); |
285 |
} |
286 |
|
287 |
/* |
b/testcases/t/115-ipc-workspaces.t
292 |
@@ -23,7 +23,7 @@ $i3->connect()->recv; |
293 |
# Workspaces requests and events |
294 |
################################ |
295 |
|
296 |
-my $focused = get_ws(focused_ws()); |
297 |
+my $old_ws = get_ws(focused_ws()); |
298 |
|
299 |
# Events |
300 |
|
301 |
@@ -36,15 +36,11 @@ $i3->subscribe({ |
302 |
workspace => sub { |
303 |
my ($event) = @_; |
304 |
if ($event->{change} eq 'init') { |
305 |
- $init->send(1); |
306 |
+ $init->send($event); |
307 |
} elsif ($event->{change} eq 'focus') { |
308 |
- # Check that we have the old and new workspace |
309 |
- $focus->send( |
310 |
- $event->{current}->{name} == '2' && |
311 |
- $event->{old}->{name} == $focused->{name} |
312 |
- ); |
313 |
+ $focus->send($event); |
314 |
} elsif ($event->{change} eq 'empty') { |
315 |
- $empty->send(1); |
316 |
+ $empty->send($event); |
317 |
} |
318 |
} |
319 |
})->recv; |
320 |
@@ -61,8 +57,20 @@ $t = AnyEvent->timer( |
321 |
} |
322 |
); |
323 |
|
324 |
-ok($init->recv, 'Workspace "init" event received'); |
325 |
-ok($focus->recv, 'Workspace "focus" event received'); |
326 |
-ok($empty->recv, 'Workspace "empty" event received'); |
327 |
+my $init_event = $init->recv; |
328 |
+my $focus_event = $focus->recv; |
329 |
+my $empty_event = $empty->recv; |
330 |
+ |
331 |
+my $current_ws = get_ws(focused_ws()); |
332 |
+ |
333 |
+ok($init_event, 'workspace "init" event received'); |
334 |
+is($init_event->{current}->{id}, $current_ws->{id}, 'the "current" property should contain the initted workspace con'); |
335 |
+ |
336 |
+ok($focus_event, 'workspace "focus" event received'); |
337 |
+is($focus_event->{current}->{id}, $current_ws->{id}, 'the "current" property should contain the focused workspace con'); |
338 |
+is($focus_event->{old}->{id}, $old_ws->{id}, 'the "old" property should contain the workspace con that was focused last'); |
339 |
+ |
340 |
+ok($empty_event, 'workspace "empty" event received'); |
341 |
+is($empty_event->{current}->{id}, $old_ws->{id}, 'the "current" property should contain the emptied workspace con'); |
342 |
|
343 |
done_testing; |
b/testcases/t/227-ipc-workspace-empty.t
348 |
@@ -50,6 +50,7 @@ subtest 'Workspace empty event upon switch', sub { |
349 |
|
350 |
my $event = $cond->recv; |
351 |
is($event->{change}, 'empty', '"Empty" event received upon workspace switch'); |
352 |
+ is($event->{current}->{name}, $ws1, '"current" property should be set to the workspace con'); |
353 |
}; |
354 |
|
355 |
################################################################################ |
356 |
@@ -116,6 +117,7 @@ subtest 'Workspace empty event upon window close', sub { |
357 |
|
358 |
my $event = $cond->recv; |
359 |
is($event->{change}, 'empty', '"Empty" event received upon window close'); |
360 |
+ is($event->{current}->{name}, $ws1, '"current" property should be set to the workspace con'); |
361 |
}; |
362 |
|
363 |
} |