Merge lp:~3v1n0/bamf/factory-ref-rework into lp:bamf

Proposed by Marco Trevisan (Treviño)
Status: Merged
Approved by: Ted Gould
Approved revision: 569
Merged at revision: 547
Proposed branch: lp:~3v1n0/bamf/factory-ref-rework
Merge into: lp:bamf
Diff against target: 451 lines (+164/-87)
4 files modified
debian/changelog (+9/-10)
lib/libbamf/bamf-factory.c (+135/-75)
lib/libbamf/bamf-view.c (+19/-1)
src/bamf-matcher.c (+1/-1)
To merge this branch: bzr merge lp:~3v1n0/bamf/factory-ref-rework
Reviewer Review Type Date Requested Status
Andrea Azzarone (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Ted Gould (community) Approve
Review via email: mp+169193@code.launchpad.net

Commit message

BamfFactory: fix references of allocated/closed views; improve re-matching of views

Now the ownership of the open views is in the hash-table, closed views must be owned
by clients (if they want to). The factory also tracks the allocated views until they
don't get destroyed to re-use them if possible.

Description of the change

The factory was owning the views it allocated in the bad way, and was re-opening closed views without taking the ownership of them.

Now the ownership of the open views is in the hash-table, closed views must be owned by clients (if they want to). The factory also tracks the allocated views until they don't get destroyed to re-use them if possible.

Added closed view re-matching by application name (only if the name is unique).

When the bamfdaemon is killed / stopped now all the views are set as closed, so that they can be correctly re-matched.

You can use this test-binary to check what happens in libbamf: http://pastebin.ubuntu.com/5761483/

Together with a script like
count=0; while [ $count -lt 20 ]; do xclock& sleep 0.3 && kill $(pidof xclock); count=$((count+1)); done

Can give some informations..

To post a comment you must log in.
lp:~3v1n0/bamf/factory-ref-rework updated
569. By Marco Trevisan (Treviño)

BamfFactory: comment wording fix

Revision history for this message
Ted Gould (ted) wrote :

Really worried about reference leaks there, but I can't find any. You should probably consider in the future adding some tests that make sure you're not keeping any internal references of objects.

review: Approve
Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

> Really worried about reference leaks there, but I can't find any. You should
> probably consider in the future adding some tests that make sure you're not
> keeping any internal references of objects.

Yes, true... Tests are something I must work on, but bamf was mostly untested since few months ago, so slowly adding them...

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Andrea Azzarone (azzar1) wrote :

LGTM too.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/changelog'
2--- debian/changelog 2013-06-11 14:24:57 +0000
3+++ debian/changelog 2013-06-13 13:28:30 +0000
4@@ -1,5 +1,6 @@
5 bamf (0.5.0) UNRELEASED; urgency=low
6
7+ [ Marco Trevisan (Treviño) ]
8 * New upstream release, bumping debian version to 0.5.0
9 * LibBamfPrivate: add new private library to share code between client
10 and daemon.
11@@ -7,16 +8,14 @@
12 allows to have correct values and signals when they get updated.
13 Deprecating related dbus methods/signals.
14 * debian/control:
15- - don't build-depend anymore on libdbus-glib-1-dev
16-
17- -- Marco Trevisan (Treviño) <marco@ubuntu.com> Wed, 05 Jun 2013 14:00:27 +0200
18-
19-bamf (0.4.0daily13.06.07-0ubuntu2) UNRELEASED; urgency=low
20-
21- * Have libbamf3-dev depend on gir1.2-bamf-3
22- * Drop explicit build-depends on gir1.2-glib-2.0
23-
24- -- Jeremy Bicha <jbicha@ubuntu.com> Mon, 10 Jun 2013 14:28:12 -0400
25+ - don't build-depend anymore on libdbus-glib-1-dev
26+
27+ [ Jeremy Bicha ]
28+ * debian/control:
29+ - Have libbamf3-dev depend on gir1.2-bamf-3
30+ - Drop explicit build-depends on gir1.2-glib-2.0
31+
32+ -- Marco Trevisan (Treviño) <marco@ubuntu.com> Wed, 12 Jun 2013 14:30:03 +0200
33
34 bamf (0.4.0daily13.06.07-0ubuntu1) saucy; urgency=low
35
36
37=== modified file 'lib/libbamf/bamf-factory.c'
38--- lib/libbamf/bamf-factory.c 2013-06-10 16:58:39 +0000
39+++ lib/libbamf/bamf-factory.c 2013-06-13 13:28:30 +0000
40@@ -1,5 +1,5 @@
41 /*
42- * Copyright 2010-2012 Canonical Ltd.
43+ * Copyright 2010-2013 Canonical Ltd.
44 *
45 * This program is free software: you can redistribute it and/or modify it
46 * under the terms of either or both of the following licenses:
47@@ -21,7 +21,7 @@
48 *
49 * Authored by: Jason Smith <jason.smith@canonical.com>
50 * Neil Jagdish Patel <neil.patel@canonical.com>
51- * Marco Trevisan (Treviño) <3v1n0@ubuntu.com>
52+ * Marco Trevisan (Treviño) <marco.trevisan@canonical.com>
53 *
54 */
55 /**
56@@ -49,40 +49,57 @@
57 {
58 GHashTable *open_views;
59 GList *local_views;
60- GList *registered_views;
61+ GList *allocated_views;
62 };
63
64 static BamfFactory *static_factory = NULL;
65
66+static void on_view_weak_unref (BamfFactory *self, BamfView *view_was_here);
67+
68 static void
69 bamf_factory_dispose (GObject *object)
70 {
71- BamfFactory *self = (BamfFactory *) object;
72-
73- if (self->priv->open_views)
74- {
75- g_hash_table_destroy (self->priv->open_views);
76- self->priv->open_views = NULL;
77- }
78-
79- if (self->priv->registered_views)
80- {
81- g_list_free (self->priv->registered_views);
82- self->priv->registered_views = NULL;
83+ GList *l, *next;
84+ BamfFactory *self = BAMF_FACTORY (object);
85+
86+ if (self->priv->allocated_views)
87+ {
88+ for (l = self->priv->allocated_views, next = NULL; l; l = next)
89+ {
90+ g_object_weak_unref (G_OBJECT (l->data), (GWeakNotify) on_view_weak_unref, self);
91+ next = l->next;
92+ g_list_free1 (l);
93+ }
94+
95+ self->priv->allocated_views = NULL;
96 }
97
98 if (self->priv->local_views)
99 {
100- g_list_free_full (self->priv->local_views, g_object_unref);
101+ g_list_free (self->priv->local_views);
102 self->priv->local_views = NULL;
103 }
104
105+ if (self->priv->open_views)
106+ {
107+ g_hash_table_remove_all (self->priv->open_views);
108+ self->priv->open_views = NULL;
109+ }
110+
111 G_OBJECT_CLASS (bamf_factory_parent_class)->dispose (object);
112 }
113
114 static void
115 bamf_factory_finalize (GObject *object)
116 {
117+ BamfFactory *self = BAMF_FACTORY (object);
118+
119+ if (self->priv->open_views)
120+ {
121+ g_hash_table_destroy (self->priv->open_views);
122+ self->priv->open_views = NULL;
123+ }
124+
125 static_factory = NULL;
126
127 G_OBJECT_CLASS (bamf_factory_parent_class)->finalize (object);
128@@ -103,62 +120,75 @@
129 static void
130 bamf_factory_init (BamfFactory *self)
131 {
132- BamfFactoryPrivate *priv;
133-
134- priv = self->priv = BAMF_FACTORY_GET_PRIVATE (self);
135-
136- priv->open_views = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
137+ self->priv = BAMF_FACTORY_GET_PRIVATE (self);
138+ self->priv->open_views = g_hash_table_new_full (g_str_hash, g_str_equal,
139+ g_free, g_object_unref);
140 }
141
142 static void
143 on_view_closed (BamfView *view, BamfFactory *self)
144 {
145 const char *path;
146-
147- g_return_if_fail (BAMF_IS_VIEW (view));
148-
149+ gboolean removed;
150+
151+ removed = FALSE;
152 path = _bamf_view_get_path (view);
153
154+ g_signal_handlers_disconnect_by_func (view, on_view_closed, self);
155+
156 if (path)
157- g_hash_table_remove (self->priv->open_views, path);
158-
159- g_object_unref (view);
160-}
161-
162-static void
163-on_view_weak_unref (BamfFactory *self, BamfView *view)
164-{
165- GHashTableIter iter;
166- gpointer key, value;
167-
168- g_return_if_fail (BAMF_IS_FACTORY (self));
169-
170- self->priv->local_views = g_list_remove (self->priv->local_views, view);
171- self->priv->registered_views = g_list_remove (self->priv->registered_views, view);
172-
173- g_hash_table_iter_init (&iter, self->priv->open_views);
174- while (g_hash_table_iter_next (&iter, &key, &value))
175- {
176- if (value == view)
177+ {
178+ removed = g_hash_table_remove (self->priv->open_views, path);
179+ }
180+
181+ if (G_UNLIKELY (!removed))
182+ {
183+ /* Unlikely to happen, but who knows... */
184+ GHashTableIter iter;
185+ gpointer value;
186+
187+ g_hash_table_iter_init (&iter, self->priv->open_views);
188+ while (g_hash_table_iter_next (&iter, NULL, &value))
189 {
190- g_hash_table_iter_remove (&iter);
191- break;
192+ if (value == view)
193+ {
194+ g_hash_table_iter_remove (&iter);
195+ removed = TRUE;
196+ break;
197+ }
198 }
199 }
200 }
201
202 static void
203+on_view_weak_unref (BamfFactory *self, BamfView *view_was_here)
204+{
205+ self->priv->local_views = g_list_remove (self->priv->local_views, view_was_here);
206+ self->priv->allocated_views = g_list_remove (self->priv->allocated_views, view_was_here);
207+}
208+
209+static void
210+bamf_factory_track_view (BamfFactory *self, BamfView *view)
211+{
212+ g_return_if_fail (BAMF_IS_VIEW (view));
213+
214+ if (g_list_find (self->priv->allocated_views, view))
215+ return;
216+
217+ g_object_weak_ref (G_OBJECT (view), (GWeakNotify) on_view_weak_unref, self);
218+ self->priv->allocated_views = g_list_prepend (self->priv->allocated_views, view);
219+}
220+
221+static void
222 bamf_factory_register_view (BamfFactory *self, BamfView *view, const char *path)
223 {
224+ g_return_if_fail (BAMF_IS_VIEW (view));
225+ g_return_if_fail (path != NULL);
226+
227+ g_object_ref_sink (view);
228 g_hash_table_insert (self->priv->open_views, g_strdup (path), view);
229-
230- if (g_list_find (self->priv->registered_views, view))
231- return;
232-
233- g_signal_connect_after (G_OBJECT (view), "closed", (GCallback) on_view_closed, self);
234- g_object_weak_ref (G_OBJECT (view), (GWeakNotify) on_view_weak_unref, self);
235-
236- self->priv->registered_views = g_list_prepend (self->priv->registered_views, view);
237+ g_signal_connect_after (G_OBJECT (view), BAMF_VIEW_SIGNAL_CLOSED,
238+ G_CALLBACK (on_view_closed), self);
239 }
240
241 BamfApplication *
242@@ -188,9 +218,11 @@
243 {
244 /* delay registration until match time */
245 result = bamf_application_new_favorite (path);
246- if (result && !g_list_find (factory->priv->local_views, result))
247+
248+ if (BAMF_IS_APPLICATION (result))
249 {
250 factory->priv->local_views = g_list_prepend (factory->priv->local_views, result);
251+ bamf_factory_track_view (factory, BAMF_VIEW (result));
252 }
253 }
254
255@@ -249,7 +281,6 @@
256 BamfView *view;
257 BamfDBusItemView *vproxy;
258 GList *l;
259- gboolean created = FALSE;
260
261 g_return_val_if_fail (BAMF_IS_FACTORY (factory), NULL);
262
263@@ -298,20 +329,25 @@
264 break;
265 }
266
267- created = TRUE;
268 BamfView *matched_view = NULL;
269
270+ /* handle case where another allocated (but closed) view exists and the new
271+ * one matches it, so that we can reuse it. */
272 if (BAMF_IS_APPLICATION (view))
273 {
274- /* handle case where another living view exists and the new one matches it */
275 const char *local_desktop_file = bamf_application_get_desktop_file (BAMF_APPLICATION (view));
276 GList *local_children = _bamf_application_get_cached_xids (BAMF_APPLICATION (view));
277+ char *local_name = bamf_view_get_name (view);
278+ gboolean matched_by_name = FALSE;
279
280- for (l = factory->priv->local_views; l; l = l->next)
281+ for (l = factory->priv->allocated_views; l; l = l->next)
282 {
283 if (!BAMF_IS_APPLICATION (l->data))
284 continue;
285
286+ if (!bamf_view_is_closed (l->data))
287+ continue;
288+
289 BamfView *list_view = BAMF_VIEW (l->data);
290 BamfApplication *list_app = BAMF_APPLICATION (l->data);
291
292@@ -326,7 +362,7 @@
293
294 /* If the primary search doesn't give out any result, we fallback
295 * to children window comparison */
296- if (!list_desktop_file && !matched_view)
297+ if (!list_desktop_file)
298 {
299 GList *list_children, *ll;
300 list_children = _bamf_application_get_cached_xids (list_app);
301@@ -341,18 +377,45 @@
302 break;
303 }
304 }
305+
306+ if ((!matched_view || matched_by_name) && local_name && local_name[0] != '\0')
307+ {
308+ char *list_name = bamf_view_get_name (list_view);
309+ if (g_strcmp0 (local_name, list_name) == 0)
310+ {
311+ if (!matched_by_name)
312+ {
313+ matched_view = list_view;
314+ matched_by_name = TRUE;
315+ }
316+ else
317+ {
318+ /* We have already matched an app by its name, this
319+ * means that there are two apps with the same name.
320+ * It's safer to ignore both, then. */
321+ matched_view = NULL;
322+ }
323+ }
324+
325+ g_free (list_name);
326+ }
327 }
328 }
329+
330+ g_free (local_name);
331 }
332 else if (BAMF_IS_WINDOW (view))
333 {
334 guint32 local_xid = bamf_window_get_xid (BAMF_WINDOW (view));
335
336- for (l = factory->priv->local_views; l; l = l->next)
337+ for (l = factory->priv->allocated_views; l; l = l->next)
338 {
339 if (!BAMF_IS_WINDOW (l->data))
340 continue;
341
342+ if (!bamf_view_is_closed (l->data))
343+ continue;
344+
345 BamfView *list_view = BAMF_VIEW (l->data);
346 BamfWindow *list_win = BAMF_WINDOW (l->data);
347
348@@ -369,27 +432,24 @@
349
350 if (matched_view)
351 {
352- created = FALSE;
353-
354 if (view)
355- g_object_unref (view);
356+ {
357+ /* We don't need anymore the view we've just created, let's forget it */
358+ g_object_unref (view);
359+ }
360
361+ /* If we are here, we're pretty sure that the view is not in the
362+ * open_views, hash-table (since it has been closed) so we can safely
363+ * re-register it here again. */
364 view = matched_view;
365 _bamf_view_set_path (view, path);
366-
367- // FIXME: this is shouldn't be needed
368- g_object_ref_sink (view);
369+ bamf_factory_register_view (factory, view, path);
370 }
371-
372- if (view)
373+ else if (view)
374 {
375+ /* It's the first time we register this view, we also have to track it, then */
376+ bamf_factory_track_view (factory, view);
377 bamf_factory_register_view (factory, view, path);
378-
379- if (created)
380- {
381- g_object_ref_sink (view);
382- factory->priv->local_views = g_list_prepend (factory->priv->local_views, view);
383- }
384 }
385
386 return view;
387
388=== modified file 'lib/libbamf/bamf-view.c'
389--- lib/libbamf/bamf-view.c 2013-06-11 13:00:51 +0000
390+++ lib/libbamf/bamf-view.c 2013-06-13 13:28:30 +0000
391@@ -506,6 +506,21 @@
392 }
393
394 static void
395+bamf_view_on_name_owner_changed (BamfDBusItemView *proxy, GParamSpec *param, BamfView *self)
396+{
397+ /* This is called when the bamfdaemon is killed / started */
398+ gchar *name_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (proxy));
399+
400+ if (!name_owner)
401+ {
402+ _bamf_view_set_closed (self, TRUE);
403+ g_signal_emit (G_OBJECT (self), view_signals[CLOSED], 0);
404+ }
405+
406+ g_free (name_owner);
407+}
408+
409+static void
410 bamf_view_on_active_changed (BamfDBusItemView *proxy, GParamSpec *param, BamfView *self)
411 {
412 gboolean active = _bamf_dbus_item_view_get_active (proxy);
413@@ -768,6 +783,9 @@
414 _bamf_view_reset_flags (view);
415 g_object_notify_by_pspec (G_OBJECT (view), properties[PROP_PATH]);
416
417+ g_signal_connect (priv->proxy, "notify::g-name-owner",
418+ G_CALLBACK (bamf_view_on_name_owner_changed), view);
419+
420 g_signal_connect (priv->proxy, "notify::active",
421 G_CALLBACK (bamf_view_on_active_changed), view);
422
423@@ -835,7 +853,7 @@
424 view_signals [CLOSED] =
425 g_signal_new (BAMF_VIEW_SIGNAL_CLOSED,
426 G_OBJECT_CLASS_TYPE (klass),
427- G_SIGNAL_RUN_FIRST,
428+ G_SIGNAL_RUN_LAST,
429 G_STRUCT_OFFSET (BamfViewClass, closed),
430 NULL, NULL,
431 g_cclosure_marshal_VOID__VOID,
432
433=== modified file 'src/bamf-matcher.c'
434--- src/bamf-matcher.c 2013-06-11 13:18:00 +0000
435+++ src/bamf-matcher.c 2013-06-13 13:28:30 +0000
436@@ -2821,6 +2821,7 @@
437 return TRUE;
438 }
439
440+#ifdef HAVE_WEBAPPS
441 static gboolean
442 bamf_matcher_has_tab_with_parent_xid (BamfMatcher *matcher, guint64 xid)
443 {
444@@ -2839,7 +2840,6 @@
445 return FALSE;
446 }
447
448-#ifdef HAVE_WEBAPPS
449 static void
450 on_webapp_child_added (BamfView *application,
451 BamfView *child,

Subscribers

People subscribed via source and target branches