Abstract wm event sending to wm_events.[ch]
Patch status: rejected
Patch by Tony Crisci
Long description:
Abstract handling of sending general wm events to wm_events.[ch]. These functions will send notifications to listeners through the i3ipc and by updating supported EWMH properties on the root window.
To apply this patch, use:
curl http://cr.i3wm.org/patch/556/raw.patch | git am
b/include/all.h
27 |
@@ -72,6 +72,7 @@ |
28 |
#include "move.h" |
29 |
#include "output.h" |
30 |
#include "ewmh.h" |
31 |
+#include "wm_events.h" |
32 |
#include "assignments.h" |
33 |
#include "regex.h" |
34 |
#include "libi3.h" |
b/include/wm_events.h
40 |
@@ -0,0 +1,54 @@ |
41 |
+/* |
42 |
+ * vim:ts=4:sw=4:expandtab |
43 |
+ * |
44 |
+ * i3 - an improved dynamic tiling window manager |
45 |
+ * © 2009-2014 Michael Stapelberg and contributors (see also: LICENSE) |
46 |
+ * |
47 |
+ * wm_events.c: Functions to send window manager events through the ipc and |
48 |
+ * update the properties of the root window to indicate changes in window |
49 |
+ * manager state. |
50 |
+ */ |
51 |
+#pragma once |
52 |
+ |
53 |
+/** |
54 |
+ * The "detail" of an event corresponds to the "change" field in the event to |
55 |
+ * send. |
56 |
+ */ |
57 |
+typedef enum { |
58 |
+ EVENT_DETAIL_0, |
59 |
+ |
60 |
+ E_CHANGE_FOCUS, |
61 |
+ E_CHANGE_INIT, |
62 |
+ E_CHANGE_RELOAD, |
63 |
+ E_CHANGE_RENAME, |
64 |
+ E_CHANGE_EMPTY, |
65 |
+ E_CHANGE_UNSPECIFIED, |
66 |
+ E_CHANGE_TITLE, |
67 |
+ E_CHANGE_NEW, |
68 |
+ E_CHANGE_URGENT, |
69 |
+ E_CHANGE_MOVE, |
70 |
+ E_CHANGE_FULLSCREEN_MODE, |
71 |
+ |
72 |
+ N_EVENT_DETAILS, |
73 |
+} event_detail_t; |
74 |
+ |
75 |
+/** |
76 |
+ * Sends a "workspace" event to ipc listeners with the "change" field set to |
77 |
+ * the corresponding detail string and changes supported EWMH "desktop" |
78 |
+ * properties on the root window. |
79 |
+ */ |
80 |
+void send_workspace_event(event_detail_t detail, Con *current, Con *old); |
81 |
+ |
82 |
+/** |
83 |
+ * Sends a "window" event to ipc listeners with the "change" field set to the |
84 |
+ * corresponding detail string and changes supported EWMH properties on the |
85 |
+ * root window (currently only _NET_ACTIVE_WINDOW is supported). |
86 |
+ */ |
87 |
+void send_window_event(event_detail_t detail, Con *con); |
88 |
+ |
89 |
+/** |
90 |
+ * Sends an "output" event to ipc listeners with the "change" field set to the |
91 |
+ * corresponding detail string and changes supported EWMH properties on the |
92 |
+ * root window (currently none are supported). |
93 |
+ */ |
94 |
+void send_output_event(event_detail_t detail); |
b/src/commands.c
99 |
@@ -1232,7 +1232,7 @@ void cmd_move_workspace_to_output(I3_CMD, char *name) { |
100 |
create_workspace_on_output(current_output, ws->parent); |
101 |
|
102 |
/* notify the IPC listeners */ |
103 |
- ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"init\"}"); |
104 |
+ send_workspace_event(E_CHANGE_INIT, NULL, NULL); |
105 |
} |
106 |
DLOG("Detaching\n"); |
107 |
|
108 |
@@ -1253,7 +1253,7 @@ void cmd_move_workspace_to_output(I3_CMD, char *name) { |
109 |
TAILQ_FOREACH(floating_con, &(ws->floating_head), floating_windows) |
110 |
floating_fix_coordinates(floating_con, &(old_content->rect), &(content->rect)); |
111 |
|
112 |
- ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"move\"}"); |
113 |
+ send_workspace_event(E_CHANGE_MOVE, NULL, NULL); |
114 |
if (workspace_was_visible) { |
115 |
/* Focus the moved workspace on the destination output. */ |
116 |
workspace_show(ws); |
117 |
@@ -1662,7 +1662,7 @@ void cmd_reload(I3_CMD) { |
118 |
load_configuration(conn, NULL, true); |
119 |
x_set_i3_atoms(); |
120 |
/* Send an IPC event just in case the ws names have changed */ |
121 |
- ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"reload\"}"); |
122 |
+ send_workspace_event(E_CHANGE_RELOAD, NULL, NULL); |
123 |
/* Send an update event for the barconfig just in case it has changed */ |
124 |
update_barconfig(); |
125 |
|
126 |
@@ -1932,7 +1932,7 @@ void cmd_rename_workspace(I3_CMD, char *old_name, char *new_name) { |
127 |
cmd_output->needs_tree_render = true; |
128 |
ysuccess(true); |
129 |
|
130 |
- ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"rename\"}"); |
131 |
+ send_workspace_event(E_CHANGE_RENAME, NULL, NULL); |
132 |
} |
133 |
|
134 |
/* |
b/src/con.c
139 |
@@ -621,7 +621,7 @@ void con_toggle_fullscreen(Con *con, int fullscreen_mode) { |
140 |
DLOG("mode now: %d\n", con->fullscreen_mode); |
141 |
|
142 |
/* Send an ipc window "fullscreen_mode" event */ |
143 |
- ipc_send_window_event("fullscreen_mode", con); |
144 |
+ send_window_event(E_CHANGE_FULLSCREEN_MODE, con); |
145 |
|
146 |
/* update _NET_WM_STATE if this container has a window */ |
147 |
/* TODO: when a window is assigned to a container which is already |
148 |
@@ -1385,7 +1385,7 @@ static void con_on_remove_child(Con *con) { |
149 |
if (TAILQ_EMPTY(&(con->focus_head)) && !workspace_is_visible(con)) { |
150 |
LOG("Closing old workspace (%p / %s), it is empty\n", con, con->name); |
151 |
tree_close(con, DONT_KILL_WINDOW, false, false); |
152 |
- ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"empty\"}"); |
153 |
+ send_workspace_event(E_CHANGE_EMPTY, NULL, NULL); |
154 |
} |
155 |
return; |
156 |
} |
b/src/handlers.c
161 |
@@ -440,7 +440,7 @@ static void handle_screen_change(xcb_generic_event_t *e) { |
162 |
|
163 |
scratchpad_fix_resolution(); |
164 |
|
165 |
- ipc_send_event("output", I3_IPC_EVENT_OUTPUT, "{\"change\":\"unspecified\"}"); |
166 |
+ send_output_event(E_CHANGE_UNSPECIFIED); |
167 |
|
168 |
return; |
169 |
} |
170 |
@@ -556,7 +556,7 @@ static bool handle_windowname_change(void *data, xcb_connection_t *conn, uint8_t |
171 |
x_push_changes(croot); |
172 |
|
173 |
if (window_name_changed(con->window, old_name)) |
174 |
- ipc_send_window_event("title", con); |
175 |
+ send_window_event(E_CHANGE_TITLE, con); |
176 |
|
177 |
FREE(old_name); |
178 |
|
179 |
@@ -581,7 +581,7 @@ static bool handle_windowname_change_legacy(void *data, xcb_connection_t *conn, |
180 |
x_push_changes(croot); |
181 |
|
182 |
if (window_name_changed(con->window, old_name)) |
183 |
- ipc_send_window_event("title", con); |
184 |
+ send_window_event(E_CHANGE_TITLE, con); |
185 |
|
186 |
FREE(old_name); |
187 |
|
b/src/manage.c
192 |
@@ -484,7 +484,7 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki |
193 |
tree_render(); |
194 |
|
195 |
/* Send an event about window creation */ |
196 |
- ipc_send_window_event("new", nc); |
197 |
+ send_window_event(E_CHANGE_NEW, nc); |
198 |
|
199 |
/* Defer setting focus after the 'new' event has been sent to ensure the |
200 |
* proper window event sequence. */ |
b/src/move.c
205 |
@@ -127,7 +127,7 @@ static void move_to_output_directed(Con *con, direction_t direction) { |
206 |
|
207 |
tree_flatten(croot); |
208 |
|
209 |
- ipc_send_workspace_focus_event(ws, old_ws); |
210 |
+ send_workspace_event(E_CHANGE_FOCUS, ws, old_ws); |
211 |
} |
212 |
|
213 |
/* |
b/src/wm_events.c
219 |
@@ -0,0 +1,79 @@ |
220 |
+/* |
221 |
+ * vim:ts=4:sw=4:expandtab |
222 |
+ * |
223 |
+ * i3 - an improved dynamic tiling window manager |
224 |
+ * © 2009-2014 Michael Stapelberg and contributors (see also: LICENSE) |
225 |
+ * |
226 |
+ * wm_events.c: Functions to send window manager events through the ipc and |
227 |
+ * update the properties of the root window to indicate changes in window |
228 |
+ * manager state. |
229 |
+ */ |
230 |
+ |
231 |
+#include "all.h" |
232 |
+ |
233 |
+static const char *detail_strings[] = { |
234 |
+ NULL, |
235 |
+ |
236 |
+ "focus", |
237 |
+ "init", |
238 |
+ "reload", |
239 |
+ "rename", |
240 |
+ "empty", |
241 |
+ "unspecified", |
242 |
+ "title", |
243 |
+ "new", |
244 |
+ "urgent", |
245 |
+ "move", |
246 |
+ "fullscreen_mode", |
247 |
+}; |
248 |
+ |
249 |
+static const char *detail_to_payload(event_detail_t detail) { |
250 |
+ static char *payloads[N_EVENT_DETAILS]; |
251 |
+ char *format = "{\"change\":\"%s\"}"; |
252 |
+ |
253 |
+ if (payloads[detail] != NULL) |
254 |
+ return payloads[detail]; |
255 |
+ |
256 |
+ char *payload = smalloc(sizeof(format) + sizeof(detail_strings[detail])); |
257 |
+ sasprintf(&payload, format, detail_strings[detail]); |
258 |
+ |
259 |
+ payloads[detail] = payload; |
260 |
+ |
261 |
+ return payloads[detail]; |
262 |
+} |
263 |
+ |
264 |
+/* |
265 |
+ * Sends a "workspace" event to ipc listeners with the "change" field set to |
266 |
+ * the corresponding detail string and changes supported EWMH "desktop" |
267 |
+ * properties on the root window. |
268 |
+ */ |
269 |
+void send_workspace_event(event_detail_t detail, Con *current, Con *old) { |
270 |
+ if (detail == E_CHANGE_FOCUS) { |
271 |
+ ipc_send_workspace_focus_event(current, old); |
272 |
+ ewmh_update_current_desktop(); |
273 |
+ } |
274 |
+ else { |
275 |
+ ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, detail_to_payload(detail)); |
276 |
+ } |
277 |
+} |
278 |
+ |
279 |
+/* |
280 |
+ * Sends a "window" event to ipc listeners with the "change" field set to the |
281 |
+ * corresponding detail string and changes supported EWMH properties on the |
282 |
+ * root window (currently only _NET_ACTIVE_WINDOW is supported). |
283 |
+ */ |
284 |
+void send_window_event(event_detail_t detail, Con *con) { |
285 |
+ if (detail == E_CHANGE_FOCUS && con_has_managed_window(con)) |
286 |
+ ewmh_update_active_window(con->window->id); |
287 |
+ |
288 |
+ ipc_send_window_event(detail_strings[detail], con); |
289 |
+} |
290 |
+ |
291 |
+/* |
292 |
+ * Sends an "output" event to ipc listeners with the "change" field set to the |
293 |
+ * corresponding detail string and changes supported EWMH properties on the |
294 |
+ * root window (currently none are supported). |
295 |
+ */ |
296 |
+void send_output_event(event_detail_t detail) { |
297 |
+ ipc_send_event("output", I3_IPC_EVENT_OUTPUT, detail_to_payload(detail)); |
298 |
+} |
b/src/workspace.c
303 |
@@ -91,7 +91,7 @@ Con *workspace_get(const char *num, bool *created) { |
304 |
|
305 |
con_attach(workspace, content, false); |
306 |
|
307 |
- ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"init\"}"); |
308 |
+ send_workspace_event(E_CHANGE_INIT, NULL, NULL); |
309 |
if (created != NULL) |
310 |
*created = true; |
311 |
} |
312 |
@@ -411,7 +411,7 @@ static void _workspace_show(Con *workspace) { |
313 |
} else |
314 |
con_focus(next); |
315 |
|
316 |
- ipc_send_workspace_focus_event(workspace, current); |
317 |
+ send_workspace_event(E_CHANGE_FOCUS, workspace, current); |
318 |
|
319 |
DLOG("old = %p / %s\n", old, (old ? old->name : "(null)")); |
320 |
/* Close old workspace if necessary. This must be done *after* doing |
321 |
@@ -424,7 +424,7 @@ static void _workspace_show(Con *workspace) { |
322 |
if (!workspace_is_visible(old)) { |
323 |
LOG("Closing old workspace (%p / %s), it is empty\n", old, old->name); |
324 |
tree_close(old, DONT_KILL_WINDOW, false, false); |
325 |
- ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"empty\"}"); |
326 |
+ send_workspace_event(E_CHANGE_EMPTY, NULL, NULL); |
327 |
} |
328 |
} |
329 |
|
330 |
@@ -436,9 +436,6 @@ static void _workspace_show(Con *workspace) { |
331 |
if (old_output != new_output) { |
332 |
x_set_warp_to(&next->rect); |
333 |
} |
334 |
- |
335 |
- /* Update the EWMH hints */ |
336 |
- ewmh_update_current_desktop(); |
337 |
} |
338 |
|
339 |
/* |
340 |
@@ -766,7 +763,7 @@ void workspace_update_urgent_flag(Con *ws) { |
341 |
DLOG("Workspace urgency flag changed from %d to %d\n", old_flag, ws->urgent); |
342 |
|
343 |
if (old_flag != ws->urgent) |
344 |
- ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"urgent\"}"); |
345 |
+ send_workspace_event(E_CHANGE_URGENT, NULL, NULL); |
346 |
} |
347 |
|
348 |
/* |
b/src/x.c
353 |
@@ -1014,7 +1014,7 @@ void x_push_changes(Con *con) { |
354 |
send_take_focus(to_focus, last_timestamp); |
355 |
|
356 |
if (to_focus != last_focused && is_con_attached(focused)) |
357 |
- ipc_send_window_event("focus", focused); |
358 |
+ send_window_event(E_CHANGE_FOCUS, focused); |
359 |
} else { |
360 |
DLOG("Updating focus (focused: %p / %s) to X11 window 0x%08x\n", focused, focused->name, to_focus); |
361 |
/* We remove XCB_EVENT_MASK_FOCUS_CHANGE from the event mask to get |
362 |
@@ -1030,10 +1030,8 @@ void x_push_changes(Con *con) { |
363 |
xcb_change_window_attributes(conn, focused->window->id, XCB_CW_EVENT_MASK, values); |
364 |
} |
365 |
|
366 |
- ewmh_update_active_window(to_focus); |
367 |
- |
368 |
if (to_focus != XCB_NONE && to_focus != last_focused && focused->window != NULL && is_con_attached(focused)) |
369 |
- ipc_send_window_event("focus", focused); |
370 |
+ send_window_event(E_CHANGE_FOCUS, focused); |
371 |
} |
372 |
|
373 |
focused_id = last_focused = to_focus; |