Xig

Merge lp:~smspillaz/xig/xig.clean-up-after-clients into lp:xig

Proposed by Sam Spilsbury
Status: Work in progress
Proposed branch: lp:~smspillaz/xig/xig.clean-up-after-clients
Merge into: lp:xig
Prerequisite: lp:~smspillaz/xig/xig.real-get-property-reply-message-length
Diff against target: 349 lines (+174/-58)
4 files modified
src/xig-remote-client-private.h (+5/-0)
src/xig-remote-client.c (+24/-1)
src/xig-server.c (+67/-19)
src/xig-window.c (+78/-38)
To merge this branch: bzr merge lp:~smspillaz/xig/xig.clean-up-after-clients
Reviewer Review Type Date Requested Status
Robert Ancell Needs Fixing
Review via email: mp+89533@code.launchpad.net

Description of the change

Remove window id's left behind by clients due to buggy X extension libraries or by SIGKILL.

Remove stale selections

To post a comment you must log in.
Revision history for this message
Robert Ancell (robert-ancell) wrote :

This patch seems a little back to front... I'd expect the client to maintain the list of resources rather than have the server call back to it. I need to think this one over a bit more (though the concept is 100% correct of course).

Revision history for this message
Sam Spilsbury (smspillaz) wrote :

The server already maintains a list of resources, so when the client goes away we need to figure out which resources the client owns and get rid of them on the server side lists too.

Revision history for this message
Robert Ancell (robert-ancell) wrote :

From me via IRC:

"What you really should do is the server should connected to the destroyed signal for the resources and remove them that way
 so you're explicitly destroying the references from both sides, but the server should be implicitly destroying them
 (or the other way around). The patch has both the server and client responsible which is dangerous if one of them gets out of sync.

So there's two ways we can do this - the client destroys itself, and the server detects that and destroys all its resources, or the client destroys all its resources then itself, and the server doesn't care"

and Sam said "So I think the best way to handle this is to have a XigClientResource which XigSelection and XigDrawable inherit"

Which is correct.

review: Needs Fixing

Unmerged revisions

255. By Sam Spilsbury

Clean up after clients - remove stale resource id's and selections. Also
handle the edge case where clients die and leave stuff behind.

254. By Sam Spilsbury

Write message length according to format, not actual length as that's too much

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/xig-remote-client-private.h'
2--- src/xig-remote-client-private.h 2011-12-01 23:46:20 +0000
3+++ src/xig-remote-client-private.h 2012-01-21 11:59:25 +0000
4@@ -23,4 +23,9 @@
5
6 void _xig_remote_client_circulate_request (XigRemoteClient *client, XigWindow *window, XigCirculatePlace place);
7
8+GList * _xig_remote_client_get_owned_drawables (XigRemoteClient *client);
9+
10+void _xig_remote_client_add_drawable (XigRemoteClient *client, XigDrawable *drawable);
11+void _xig_remote_client_remove_drawable (XigRemoteClient *client, XigDrawable *drawable);
12+
13 #endif /* _XIG_REMOTE_CLIENT_PRIVATE_H_ */
14
15=== modified file 'src/xig-remote-client.c'
16--- src/xig-remote-client.c 2012-01-10 16:45:57 +0000
17+++ src/xig-remote-client.c 2012-01-21 11:59:25 +0000
18@@ -47,6 +47,9 @@
19
20 /* Event masks */
21 GHashTable *window_events;
22+
23+ /* Owned windows */
24+ GHashTable *owned_drawables;
25 };
26
27 enum
28@@ -287,6 +290,24 @@
29 xig_codec_feed_circulate_request (XIG_CODEC (client), &message);
30 }
31
32+GList *
33+_xig_remote_client_get_owned_drawables (XigRemoteClient *client)
34+{
35+ return g_hash_table_get_keys (client->priv->owned_drawables);
36+}
37+
38+void
39+_xig_remote_client_add_drawable (XigRemoteClient *client, XigDrawable *drawable)
40+{
41+ g_hash_table_insert (client->priv->owned_drawables, GINT_TO_POINTER (xig_drawable_get_id (drawable)), g_object_ref (drawable));
42+}
43+
44+void
45+_xig_remote_client_remove_drawable (XigRemoteClient *client, XigDrawable *drawable)
46+{
47+ g_hash_table_remove (client->priv->owned_drawables, GINT_TO_POINTER (xig_drawable_get_id (drawable)));
48+}
49+
50 static void
51 circulate_notify_cb (XigWindow *window, XigRemoteClient *client)
52 {
53@@ -412,7 +433,7 @@
54 if (n_read < 0)
55 g_warning ("Error reading from socket: %s", strerror (errno));
56 else if (n_read == 0)
57- {
58+ {
59 g_signal_emit (client, signals[DISCONNECTED], 0);
60 return FALSE;
61 }
62@@ -1574,6 +1595,7 @@
63
64 reply.sequence_number = message->sequence_number;
65 focus = xig_server_get_input_focus (client->priv->server, &reply.revert_to);
66+
67 reply.focus = focus ? xig_window_get_id (focus) : XIG_WINDOW_ID_NONE;
68
69 xig_codec_feed_get_input_focus_reply (XIG_CODEC (codec), &reply);
70@@ -2582,6 +2604,7 @@
71 client->priv->server = server;
72 client->priv->socket = g_object_ref (socket);
73 client->priv->channel = g_io_channel_unix_new (g_socket_get_fd (socket));
74+ client->priv->owned_drawables = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
75 g_io_add_watch (client->priv->channel, G_IO_IN, socket_data_cb, client);
76
77 return client;
78
79=== modified file 'src/xig-server.c'
80--- src/xig-server.c 2011-12-02 10:34:45 +0000
81+++ src/xig-server.c 2012-01-21 11:59:25 +0000
82@@ -150,12 +150,78 @@
83 server->priv->listen_tcp = listen_tcp;
84 }
85
86+static gboolean
87+_xig_server_hash_table_remove_selection_for_window (gpointer key,
88+ gpointer owner,
89+ gpointer user_data)
90+{
91+ return owner == user_data ? TRUE : FALSE;
92+}
93+
94+void
95+_xig_server_remove_window (XigServer *server, XigWindow *window)
96+{
97+ g_hash_table_remove (server->priv->drawables, GINT_TO_POINTER (xig_drawable_get_id (XIG_DRAWABLE (window))));
98+
99+ /* Remove any selection owners too */
100+ g_hash_table_foreach_remove (server->priv->selection_owners, _xig_server_hash_table_remove_selection_for_window, (gpointer) window);
101+
102+ /* Unset the focus window (revert to root window */
103+ if (window == server->priv->focus_window)
104+ server->priv->focus_window = NULL;
105+}
106+
107+void
108+_xig_server_add_window (XigServer *server, XigWindow *window)
109+{
110+ g_hash_table_insert (server->priv->drawables, GINT_TO_POINTER (xig_drawable_get_id (XIG_DRAWABLE (window))), g_object_ref (window));
111+}
112+
113+void
114+_xig_server_add_pixmap (XigServer *server, XigPixmap *pixmap)
115+{
116+ g_hash_table_insert (server->priv->drawables, GINT_TO_POINTER (xig_drawable_get_id (XIG_DRAWABLE (pixmap))), g_object_ref (pixmap));
117+}
118+
119+void
120+_xig_server_remove_pixmap (XigServer *server, XigPixmap *pixmap)
121+{
122+ g_hash_table_remove (server->priv->drawables, GINT_TO_POINTER (xig_drawable_get_id (XIG_DRAWABLE (pixmap))));
123+}
124+
125+
126 static void
127 xig_remote_client_disconnected_cb (XigRemoteClient *client, XigServer *server)
128 {
129 g_signal_handlers_disconnect_matched (client, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, server);
130 server->priv->clients = g_list_remove (server->priv->clients, client);
131 g_signal_emit (server, signals[CLIENT_DISCONNECTED], 0, client);
132+
133+ GList *list = _xig_remote_client_get_owned_drawables (client);
134+ GList *orig = list;
135+
136+ while (list)
137+ {
138+ gint id = GPOINTER_TO_INT (list->data);
139+ XigDrawable *drawable = g_hash_table_lookup (server->priv->drawables, GINT_TO_POINTER (id));
140+
141+ if (XIG_IS_WINDOW (drawable))
142+ {
143+ XigWindow *window = XIG_WINDOW (drawable);
144+
145+ _xig_server_remove_window (server, window);
146+ }
147+ else if (XIG_IS_PIXMAP (drawable))
148+ {
149+ XigPixmap *pixmap = XIG_PIXMAP (drawable);
150+
151+ _xig_server_remove_pixmap (server, pixmap);
152+ }
153+ list = g_list_next (list);
154+ }
155+
156+ g_list_free (orig);
157+
158 g_object_unref (client);
159 }
160
161@@ -257,12 +323,6 @@
162 }
163
164 void
165-_xig_server_add_window (XigServer *server, XigWindow *window)
166-{
167- g_hash_table_insert (server->priv->drawables, GINT_TO_POINTER (xig_drawable_get_id (XIG_DRAWABLE (window))), g_object_ref (window));
168-}
169-
170-void
171 _xig_server_set_selection_owner (XigServer *server, const gchar *name, XigWindow *window)
172 {
173 g_hash_table_insert (server->priv->selection_owners, g_strdup (name), g_object_ref (window));
174@@ -274,18 +334,6 @@
175 return g_hash_table_lookup (server->priv->selection_owners, name);
176 }
177
178-void
179-_xig_server_add_pixmap (XigServer *server, XigPixmap *pixmap)
180-{
181- g_hash_table_insert (server->priv->drawables, GINT_TO_POINTER (xig_drawable_get_id (XIG_DRAWABLE (pixmap))), g_object_ref (pixmap));
182-}
183-
184-void
185-_xig_server_remove_pixmap (XigServer *server, XigPixmap *pixmap)
186-{
187- g_hash_table_remove (server->priv->drawables, GINT_TO_POINTER (xig_drawable_get_id (XIG_DRAWABLE (pixmap))));
188-}
189-
190 XigDrawable *
191 xig_server_get_drawable (XigServer *server, guint32 drawable)
192 {
193@@ -346,7 +394,7 @@
194 void
195 xig_server_set_input_focus (XigServer *server, XigWindow *window, guint8 revert_to)
196 {
197- server->priv->focus_window = g_object_ref (window);
198+ server->priv->focus_window = window;
199 // FIXME: Catch delete event
200 server->priv->focus_revert_to = revert_to;
201 }
202
203=== modified file 'src/xig-window.c'
204--- src/xig-window.c 2012-01-10 17:14:41 +0000
205+++ src/xig-window.c 2012-01-21 11:59:25 +0000
206@@ -76,6 +76,76 @@
207 };
208 static guint signals[LAST_SIGNAL] = { 0 };
209
210+static void
211+destroy_recursive (XigWindow *window)
212+{
213+ GList *link;
214+
215+ /* Destroy all children first */
216+ for (link = window->priv->children; link; link = link->next)
217+ {
218+ XigWindow *w = link->data;
219+ destroy_recursive (w);
220+ }
221+
222+ g_signal_emit (window, signals[DESTROY_NOTIFY], 0);
223+ g_signal_emit (window->priv->parent, signals[CHILD_DESTROY_NOTIFY], 0, window);
224+
225+ g_object_unref (window);
226+}
227+
228+void
229+xig_window_destroy (XigWindow *window)
230+{
231+ window->priv->parent->priv->children = g_list_remove (window->priv->parent->priv->children, window);
232+ destroy_recursive (window);
233+}
234+
235+void
236+xig_window_destroy_subwindows (XigWindow *window)
237+{
238+ GList *link;
239+ for (link = window->priv->children; link; link = link->next)
240+ {
241+ XigWindow *w = link->data;
242+ destroy_recursive (w);
243+ }
244+ g_list_free (window->priv->children);
245+ window->priv->children = NULL;
246+}
247+
248+/* When clients disconnect, they are meant to (implicitly, through xcb)
249+ * remove any resources that they held. When a client dies, it can't do that
250+ * so clean up after it */
251+static void
252+xig_window_client_disconnected_cb (XigServer *server, XigRemoteClient *client, XigWindow *window)
253+{
254+ GList *list = _xig_remote_client_get_owned_drawables (client);
255+ GList *orig = list;
256+
257+ while (list)
258+ {
259+ gint id = GPOINTER_TO_INT (list->data);
260+
261+ GList *child = window->priv->children;
262+
263+ while (child)
264+ {
265+ if (xig_window_get_id (XIG_WINDOW (child->data)) == id)
266+ {
267+ xig_window_destroy (XIG_WINDOW (child->data));
268+ break;
269+ }
270+
271+ child = g_list_next (child);
272+ }
273+
274+ list = g_list_next (list);
275+ }
276+
277+ g_list_free (orig);
278+}
279+
280 XigWindow *
281 _xig_window_new (XigServer *server, XigRemoteClient *client, guint32 wid, XigWindow *parent, XigWindowClassType class, gint16 x, gint16 y, guint16 width, guint16 height, guint16 border_width, XigVisual *visual)
282 {
283@@ -97,6 +167,10 @@
284 window->priv->border_width = border_width;
285 window->priv->visual = g_object_ref (visual);
286
287+ if (client)
288+ _xig_remote_client_add_drawable (client, XIG_DRAWABLE (window));
289+ g_signal_connect (server, "client-disconnected", G_CALLBACK (xig_window_client_disconnected_cb), window);
290+
291 if (parent)
292 g_signal_emit (parent, signals[CREATE_NOTIFY], 0, window);
293
294@@ -695,44 +769,6 @@
295 }
296
297 static void
298-destroy_recursive (XigWindow *window)
299-{
300- GList *link;
301-
302- /* Destroy all children first */
303- for (link = window->priv->children; link; link = link->next)
304- {
305- XigWindow *w = link->data;
306- destroy_recursive (w);
307- }
308-
309- g_signal_emit (window, signals[DESTROY_NOTIFY], 0);
310- g_signal_emit (window->priv->parent, signals[CHILD_DESTROY_NOTIFY], 0, window);
311-
312- g_object_unref (window);
313-}
314-
315-void
316-xig_window_destroy (XigWindow *window)
317-{
318- window->priv->parent->priv->children = g_list_remove (window->priv->parent->priv->children, window);
319- destroy_recursive (window);
320-}
321-
322-void
323-xig_window_destroy_subwindows (XigWindow *window)
324-{
325- GList *link;
326- for (link = window->priv->children; link; link = link->next)
327- {
328- XigWindow *w = link->data;
329- destroy_recursive (w);
330- }
331- g_list_free (window->priv->children);
332- window->priv->children = NULL;
333-}
334-
335-static void
336 xig_window_init (XigWindow *window)
337 {
338 window->priv = G_TYPE_INSTANCE_GET_PRIVATE (window, xig_window_get_type (), XigWindowPrivate);
339@@ -753,6 +789,10 @@
340 xig_window_finalize (GObject *object)
341 {
342 XigWindow *window = (XigWindow *) object;
343+
344+ if (window->priv->client)
345+ _xig_remote_client_remove_drawable (window->priv->client, XIG_DRAWABLE (window));
346+
347 if (window->priv->visual)
348 g_object_unref (window->priv->visual);
349 if (window->priv->background_pixmap)

Subscribers

People subscribed via source and target branches