Add support for the _NET_CLIENT_LIST root window property.
Patch status: needinfo
Patch by Steve Jones
Long description:
This sets the the _NET_CLIENT_LIST property in x_push_changes when the client list changes. Changes to the client list are tracked by the client_list_changed flag which is updated by x_con_init and x_con_kill. The client list is maintained in the order of connecting by the TAILQ with head client_head.
To apply this patch, use:
curl http://cr.i3wm.org/patch/391/raw.patch | git am
b/include/atoms.xmacro
22 |
@@ -12,6 +12,7 @@ xmacro(_NET_WM_WINDOW_TYPE_TOOLBAR) |
23 |
xmacro(_NET_WM_WINDOW_TYPE_SPLASH) |
24 |
xmacro(_NET_WM_DESKTOP) |
25 |
xmacro(_NET_WM_STRUT_PARTIAL) |
26 |
+xmacro(_NET_CLIENT_LIST) |
27 |
xmacro(_NET_CLIENT_LIST_STACKING) |
28 |
xmacro(_NET_CURRENT_DESKTOP) |
29 |
xmacro(_NET_ACTIVE_WINDOW) |
b/include/ewmh.h
34 |
@@ -28,6 +28,11 @@ void ewmh_update_current_desktop(void); |
35 |
void ewmh_update_active_window(xcb_window_t window); |
36 |
|
37 |
/** |
38 |
+ * Updates the _NET_CLIENT_LIST hint. Used for window listers. |
39 |
+ */ |
40 |
+void ewmh_update_client_list(xcb_window_t *list, int num_windows); |
41 |
+ |
42 |
+/** |
43 |
* Updates the _NET_CLIENT_LIST_STACKING hint. Necessary to move tabs in |
44 |
* Chromium correctly. |
45 |
* |
b/src/ewmh.c
50 |
@@ -69,6 +69,22 @@ void ewmh_update_workarea(void) { |
51 |
} |
52 |
|
53 |
/* |
54 |
+ * Updates the _NET_CLIENT_LIST hint. |
55 |
+ * |
56 |
+ */ |
57 |
+void ewmh_update_client_list(xcb_window_t *list, int num_windows) { |
58 |
+ xcb_change_property( |
59 |
+ conn, |
60 |
+ XCB_PROP_MODE_REPLACE, |
61 |
+ root, |
62 |
+ A__NET_CLIENT_LIST, |
63 |
+ XCB_ATOM_WINDOW, |
64 |
+ 32, |
65 |
+ num_windows, |
66 |
+ list); |
67 |
+} |
68 |
+ |
69 |
+/* |
70 |
* Updates the _NET_CLIENT_LIST_STACKING hint. |
71 |
* |
72 |
*/ |
b/src/x.c
77 |
@@ -20,6 +20,9 @@ xcb_window_t focused_id = XCB_NONE; |
78 |
static xcb_window_t *btt_stack; |
79 |
static int btt_stack_num; |
80 |
|
81 |
+/* Flags new clients created or destroyed, used in x_push_changes */ |
82 |
+static bool client_list_changed = false; |
83 |
+ |
84 |
/* Stores coordinates to warp mouse pointer to if set */ |
85 |
static Rect *warp_to; |
86 |
|
87 |
@@ -55,6 +58,7 @@ typedef struct con_state { |
88 |
|
89 |
CIRCLEQ_ENTRY(con_state) state; |
90 |
CIRCLEQ_ENTRY(con_state) old_state; |
91 |
+ TAILQ_ENTRY(con_state) client_order; |
92 |
} con_state; |
93 |
|
94 |
CIRCLEQ_HEAD(state_head, con_state) state_head = |
95 |
@@ -63,6 +67,9 @@ CIRCLEQ_HEAD(state_head, con_state) state_head = |
96 |
CIRCLEQ_HEAD(old_state_head, con_state) old_state_head = |
97 |
CIRCLEQ_HEAD_INITIALIZER(old_state_head); |
98 |
|
99 |
+TAILQ_HEAD(client_head, con_state) client_head = |
100 |
+ TAILQ_HEAD_INITIALIZER(client_head); |
101 |
+ |
102 |
/* |
103 |
* Returns the container state for the given frame. This function always |
104 |
* returns a container state (otherwise, there is a bug in the code and the |
105 |
@@ -146,8 +153,11 @@ void x_con_init(Con *con, uint16_t depth) { |
106 |
state->id = con->frame; |
107 |
state->mapped = false; |
108 |
state->initial = true; |
109 |
+ DLOG("Adding window 0x%08x to lists\n", state->id); |
110 |
CIRCLEQ_INSERT_HEAD(&state_head, state, state); |
111 |
CIRCLEQ_INSERT_HEAD(&old_state_head, state, old_state); |
112 |
+ TAILQ_INSERT_TAIL(&client_head, state, client_order); |
113 |
+ client_list_changed = true; |
114 |
DLOG("adding new state for window id 0x%08x\n", state->id); |
115 |
} |
116 |
|
117 |
@@ -228,6 +238,8 @@ void x_con_kill(Con *con) { |
118 |
state = state_for_frame(con->frame); |
119 |
CIRCLEQ_REMOVE(&state_head, state, state); |
120 |
CIRCLEQ_REMOVE(&old_state_head, state, old_state); |
121 |
+ TAILQ_REMOVE(&client_head, state, client_order); |
122 |
+ client_list_changed = true; |
123 |
FREE(state->name); |
124 |
free(state); |
125 |
|
126 |
@@ -876,6 +888,8 @@ void x_push_changes(Con *con) { |
127 |
btt_stack_num = cnt; |
128 |
} |
129 |
|
130 |
+ DLOG("Getting window stacking order\n"); |
131 |
+ |
132 |
xcb_window_t *walk = btt_stack; |
133 |
|
134 |
/* X11 correctly represents the stack if we push it from bottom to top */ |
135 |
@@ -906,6 +920,33 @@ void x_push_changes(Con *con) { |
136 |
if (stacking_changed) |
137 |
ewmh_update_client_list_stacking(btt_stack, btt_stack_num); |
138 |
|
139 |
+ /* If the client list changed since the last call update the |
140 |
+ * _NET_CLIENT_LIST property. */ |
141 |
+ if (client_list_changed) { |
142 |
+ xcb_window_t *client_list; |
143 |
+ |
144 |
+ DLOG("Client list changed (%i clients)\n", cnt); |
145 |
+ |
146 |
+ if (cnt) { |
147 |
+ client_list = smalloc(cnt * sizeof(xcb_window_t)); |
148 |
+ walk = client_list; |
149 |
+ |
150 |
+ TAILQ_FOREACH(state, &client_head, client_order) { |
151 |
+ assert((client_list - walk) < cnt); |
152 |
+ if (state->con && state->con->window) |
153 |
+ *walk++ = state->con->window->id; |
154 |
+ } |
155 |
+ |
156 |
+ ewmh_update_client_list(client_list, cnt); |
157 |
+ |
158 |
+ free(client_list); |
159 |
+ } else { |
160 |
+ ewmh_update_client_list(NULL, 0); |
161 |
+ } |
162 |
+ |
163 |
+ client_list_changed = false; |
164 |
+ } |
165 |
+ |
166 |
DLOG("PUSHING CHANGES\n"); |
167 |
x_push_node(con); |
168 |
|