i3bar: Reduce noise to tray clients
Patch status: needinfo
Patch by Tony Crisci
Long description:
Try not to send messages to tray clients which could raise errors on the client side, causing some clients to die. BadWindow errors can be caused by sending tray clients messages pointing to false manager selections and by race conditions related to setting the tray manager selection multiple times per loading of i3. Expands support for running multiple bar instances. Fixes an issue which may cause tray clients to appear on a bar which does not have the tray manager selection.
To apply this patch, use:
curl http://cr.i3wm.org/patch/302/raw.patch | git am
b/i3bar/src/xcb.c
24 |
@@ -53,6 +53,9 @@ xcb_window_t xcb_root; |
25 |
static xcb_window_t selwin = XCB_NONE; |
26 |
static xcb_intern_atom_reply_t *tray_reply = NULL; |
27 |
|
28 |
+/* set to true when selwin has the tray manager selection */ |
29 |
+static bool has_tray_selection= false; |
30 |
+ |
31 |
/* This is needed for integration with libi3 */ |
32 |
xcb_connection_t *conn; |
33 |
|
34 |
@@ -1078,6 +1081,9 @@ void init_xcb_late(char *fontname) { |
35 |
* |
36 |
*/ |
37 |
static void send_tray_clientmessage(void) { |
38 |
+ if (!has_tray_selection) |
39 |
+ return; |
40 |
+ |
41 |
uint8_t buffer[32] = { 0 }; |
42 |
xcb_client_message_event_t *ev = (xcb_client_message_event_t*)buffer; |
43 |
|
44 |
@@ -1104,13 +1110,41 @@ static void send_tray_clientmessage(void) { |
45 |
* |
46 |
*/ |
47 |
void init_tray(void) { |
48 |
- DLOG("Initializing system tray functionality\n"); |
49 |
+ DLOG("Starting tray initialization.\n"); |
50 |
/* request the tray manager atom for the X11 display we are running on */ |
51 |
char atomname[strlen("_NET_SYSTEM_TRAY_S") + 11]; |
52 |
snprintf(atomname, strlen("_NET_SYSTEM_TRAY_S") + 11, "_NET_SYSTEM_TRAY_S%d", screen); |
53 |
xcb_intern_atom_cookie_t tray_cookie; |
54 |
- if (tray_reply == NULL) |
55 |
+ |
56 |
+ if (tray_reply == NULL) { |
57 |
tray_cookie = xcb_intern_atom(xcb_connection, 0, strlen(atomname), atomname); |
58 |
+ tray_reply = xcb_intern_atom_reply(xcb_connection, tray_cookie, NULL); |
59 |
+ |
60 |
+ if (!tray_reply) { |
61 |
+ ELOG("Could not get atom %s\n", atomname); |
62 |
+ exit(EXIT_FAILURE); |
63 |
+ } |
64 |
+ } |
65 |
+ |
66 |
+ /* be nice and back off if anybody owns the tray already */ |
67 |
+ xcb_get_selection_owner_cookie_t current_sel_cookie; |
68 |
+ xcb_get_selection_owner_reply_t *current_sel_reply; |
69 |
+ |
70 |
+ current_sel_cookie = xcb_get_selection_owner(xcb_connection, tray_reply->atom); |
71 |
+ current_sel_reply = xcb_get_selection_owner_reply(xcb_connection, current_sel_cookie, NULL); |
72 |
+ |
73 |
+ if (current_sel_reply == NULL) { |
74 |
+ DLOG("Could not get selection owner for %s\n", atomname); |
75 |
+ exit(EXIT_FAILURE); |
76 |
+ } |
77 |
+ |
78 |
+ if (current_sel_reply->owner) { |
79 |
+ DLOG("Tray owned by 0x%08x, not configuring tray.\n", current_sel_reply->owner); |
80 |
+ free(current_sel_reply); |
81 |
+ return; |
82 |
+ } |
83 |
+ |
84 |
+ free(current_sel_reply); |
85 |
|
86 |
/* tray support: we need a window to own the selection */ |
87 |
selwin = xcb_generate_id(xcb_connection); |
88 |
@@ -1141,13 +1175,6 @@ void init_tray(void) { |
89 |
|
90 |
init_tray_colors(); |
91 |
|
92 |
- if (tray_reply == NULL) { |
93 |
- if (!(tray_reply = xcb_intern_atom_reply(xcb_connection, tray_cookie, NULL))) { |
94 |
- ELOG("Could not get atom %s\n", atomname); |
95 |
- exit(EXIT_FAILURE); |
96 |
- } |
97 |
- } |
98 |
- |
99 |
xcb_set_selection_owner(xcb_connection, |
100 |
selwin, |
101 |
tray_reply->atom, |
102 |
@@ -1163,16 +1190,17 @@ void init_tray(void) { |
103 |
exit(EXIT_FAILURE); |
104 |
} |
105 |
|
106 |
- if (selreply->owner != selwin) { |
107 |
- ELOG("Could not set the %s selection. " \ |
108 |
- "Maybe another tray is already running?\n", atomname); |
109 |
+ if (selreply->owner == selwin) { |
110 |
+ DLOG("Tray initialized. Tray selection owned by 0x%08x.\n", selwin); |
111 |
+ has_tray_selection = true; |
112 |
+ send_tray_clientmessage(); |
113 |
+ } else { |
114 |
+ ELOG("Could not set the %s selection. Cannot initialize tray.\n", atomname); |
115 |
/* NOTE that this error is not fatal. We just can’t provide tray |
116 |
* functionality */ |
117 |
- free(selreply); |
118 |
- return; |
119 |
} |
120 |
|
121 |
- send_tray_clientmessage(); |
122 |
+ free(selreply); |
123 |
} |
124 |
|
125 |
/* |
126 |
@@ -1273,7 +1301,7 @@ void get_atoms(void) { |
127 |
* |
128 |
*/ |
129 |
void kick_tray_clients(i3_output *output) { |
130 |
- if (TAILQ_EMPTY(output->trayclients)) |
131 |
+ if (!has_tray_selection || TAILQ_EMPTY(output->trayclients)) |
132 |
return; |
133 |
|
134 |
trayclient *trayclient; |
135 |
@@ -1304,7 +1332,8 @@ void kick_tray_clients(i3_output *output) { |
136 |
|
137 |
xcb_send_event(conn, false, selwin, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (char*)event); |
138 |
|
139 |
- send_tray_clientmessage(); |
140 |
+ if (has_tray_selection) |
141 |
+ send_tray_clientmessage(); |
142 |
} |
143 |
|
144 |
/* |
145 |
@@ -1319,7 +1348,9 @@ void destroy_window(i3_output *output) { |
146 |
return; |
147 |
} |
148 |
|
149 |
- kick_tray_clients(output); |
150 |
+ if (has_tray_selection) |
151 |
+ kick_tray_clients(output); |
152 |
+ |
153 |
xcb_destroy_window(xcb_connection, output->bar); |
154 |
output->bar = XCB_NONE; |
155 |
} |