Merge lp:~unity-team/libunity/launcher-api into lp:libunity

Proposed by Mikkel Kamstrup Erlandsen
Status: Merged
Merged at revision: 22
Proposed branch: lp:~unity-team/libunity/launcher-api
Merge into: lp:libunity
Diff against target: 592 lines (+503/-6) (has conflicts)
9 files modified
configure.ac (+4/-3)
src/Makefile.am (+4/-1)
src/unity-inspector.vala (+121/-0)
src/unity-launcher.vala.OTHER (+267/-0)
src/unity-serializable.vala (+51/-0)
test/vala/Makefile.am (+2/-1)
test/vala/test-launcher.vala (+50/-0)
test/vala/test-vala.vala (+3/-0)
unity.pc.in (+1/-1)
Contents conflict in src/unity-launcher.vala
To merge this branch: bzr merge lp:~unity-team/libunity/launcher-api
Reviewer Review Type Date Requested Status
Neil J. Patel (community) Approve
Review via email: mp+47677@code.launchpad.net

Description of the change

This is the initial cut on the launcher API. It introduces three new public classes:

 Unity.LauncherEntry : a thin wrapper for some DBus logic that syncs the properties in a clever way to Unity. You can control count, progress, emblem, and quicklist.

 Unity.Inspector : a singleton "hub" for collecting metadata about the running, or not running, Unity process. In particular whether Unity is running or not.

 Unity.Serializable : An interface for objects that can be transformed into variants.

I need to add some more tests that assert that all the clever DBus caching and re-syncing works as it should (only manually verified at this point), but this will come in a different branch because it requires some fiddling to get right.

To post a comment you must log in.
Revision history for this message
Neil J. Patel (njpatel) wrote :

Looks sexy.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'configure.ac'
2--- configure.ac 2011-01-21 09:14:30 +0000
3+++ configure.ac 2011-01-27 16:02:15 +0000
4@@ -88,10 +88,11 @@
5 PKG_CHECK_MODULES(GIO_UNIX2, [gio-unix-2.0])
6 PKG_CHECK_MODULES(GEE, [gee-1.0 >= 0.6.0])
7 PKG_CHECK_MODULES(DEE, [dee-1.0 >= 0.5.2])
8+PKG_CHECK_MODULES(DBUSMENU, [dbusmenu-glib-0.4 >= 0.3.93])
9
10-LIBUNITY_CFLAGS="$GLIB2_CFLAGS $GOBJECT2_CFLAGS $GIO2_CFLAGS $GIO_UNIX2_CFLAGS $GEE_CFLAGS $DEE_CFLAGS"
11-LIBUNITY_LIBS="$GLIB2_LIBS $GOBJECT2_LIBS $GIO2_LIBS $GIO_UNIX2_LIBS $GEE_LIBS $DEE_LIBS"
12-LIBUNITY_PACKAGES="--pkg glib-2.0 --pkg gobject-2.0 --pkg gio-2.0 --pkg gio-unix-2.0 --pkg gee-1.0 --pkg dee-1.0"
13+LIBUNITY_CFLAGS="$GLIB2_CFLAGS $GOBJECT2_CFLAGS $GIO2_CFLAGS $GIO_UNIX2_CFLAGS $GEE_CFLAGS $DEE_CFLAGS $DBUSMENU_CFLAGS"
14+LIBUNITY_LIBS="$GLIB2_LIBS $GOBJECT2_LIBS $GIO2_LIBS $GIO_UNIX2_LIBS $GEE_LIBS $DEE_LIBS $DBUSMENU_LIBS"
15+LIBUNITY_PACKAGES="--pkg glib-2.0 --pkg gobject-2.0 --pkg gio-2.0 --pkg gio-unix-2.0 --pkg gee-1.0 --pkg dee-1.0 --pkg Dbusmenu-Glib-0.4"
16 AC_SUBST(LIBUNITY_CFLAGS)
17 AC_SUBST(LIBUNITY_LIBS)
18 AC_SUBST(LIBUNITY_PACKAGES)
19
20=== modified file 'src/Makefile.am'
21--- src/Makefile.am 2011-01-20 10:29:21 +0000
22+++ src/Makefile.am 2011-01-27 16:02:15 +0000
23@@ -48,10 +48,13 @@
24
25 libunity_la_VALASOURCES = \
26 unity-appinfo-manager.vala \
27+ unity-inspector.vala \
28 unity-io.vala \
29+ unity-launcher.vala \
30 unity-place.vala \
31 unity-place-activation.vala \
32- unity-place-browser.vala
33+ unity-place-browser.vala \
34+ unity-serializable.vala
35
36
37 libunity_la_APIFILES = \
38
39=== added file 'src/unity-inspector.vala'
40--- src/unity-inspector.vala 1970-01-01 00:00:00 +0000
41+++ src/unity-inspector.vala 2011-01-27 16:02:15 +0000
42@@ -0,0 +1,121 @@
43+/*
44+ * Copyright (C) 2011 Canonical, Ltd.
45+ *
46+ * This library is free software; you can redistribute it and/or modify
47+ * it under the terms of the GNU Lesser General Public License
48+ * version 3.0 as published by the Free Software Foundation.
49+ *
50+ * This library is distributed in the hope that it will be useful,
51+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
52+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
53+ * GNU Lesser General Public License version 3.0 for more details.
54+ *
55+ * You should have received a copy of the GNU Lesser General Public
56+ * License along with this library. If not, see
57+ * <http://www.gnu.org/licenses/>.
58+ *
59+ * Authored by Mikkel Kamstrup Erlandsen <mikkel.kamstrup@canonical.com>
60+ *
61+ */
62+
63+/*
64+ * IMPLEMENTATION NOTE:
65+ * We want the generated C API to be nice and not too Vala-ish. We must
66+ * anticipate that libunity consumers will be written in both Vala , C,
67+ * and through GObject Introspection
68+ *
69+ */
70+
71+using GLib;
72+
73+namespace Unity {
74+
75+ /**
76+ * The Unity.Inspector is a singleton that can be used to inspect the
77+ * state of Unity.
78+ *
79+ * One of the most basic and most useful applications of the inspector
80+ * is to check if Unity is running or not.
81+ *
82+ */
83+ public class Inspector : Object
84+ {
85+ /**
86+ * Boolean property determining whether Unity is running or not. You
87+ * can use this property to determine whether Unity is running or not.
88+ */
89+ public bool unity_running { get { return _unity_running; } }
90+ private bool _unity_running = false;
91+
92+ /**
93+ * Property holding the unique DBus name of the Unity process if
94+ * Unity is running, or null otherwise.
95+ */
96+ public string? unity_bus_name { get { return _unity_bus_name; } }
97+ private string? _unity_bus_name = null;
98+
99+ private DBusConnection bus;
100+ private uint unity_watcher;
101+ private static Inspector? singleton = null;
102+
103+ /**
104+ * Get the default singleton Unity.Inspector instance, creating it
105+ * dynamically if necessary.
106+ *
107+ * @return The singleton Unity.Inspector. If calling from C do not
108+ * free this instance.
109+ *
110+ */
111+ public static unowned Inspector get_default ()
112+ {
113+ if (singleton == null)
114+ singleton = new Inspector ();
115+
116+ return singleton;
117+ }
118+
119+ /* Constructor is private to bar 3rd parties from creating instances */
120+ private Inspector ()
121+ {
122+ try {
123+ bus = Bus.get_sync (BusType.SESSION);
124+ unity_watcher = Bus.watch_name_on_connection (bus, "com.canonical.Unity",
125+ BusNameWatcherFlags.NONE,
126+ on_unity_appeared,
127+ on_unity_vanished);
128+ } catch (IOError e) {
129+ critical ("Unable to connect to session bus: %s", e.message);
130+ }
131+
132+ }
133+
134+ private void on_unity_appeared (DBusConnection conn,
135+ string name,
136+ string name_owner)
137+ {
138+ if (name != "com.canonical.Unity")
139+ {
140+ critical ("Internal error in libunity: Got name owner notification " +
141+ "from '%'. Expected 'com.canonical.Unity'", name);
142+ return;
143+ }
144+
145+ _unity_running = true;
146+ _unity_bus_name = name_owner;
147+ notify_property ("unity-running");
148+ notify_property ("unity-bus-name");
149+ }
150+
151+ private void on_unity_vanished (DBusConnection conn,
152+ string name)
153+ {
154+ _unity_running = false;
155+ _unity_bus_name = null;
156+ notify_property ("unity-running");
157+ notify_property ("unity-bus-name");
158+ }
159+
160+ } /* class Unity.Inspector */
161+
162+
163+} /* namespace */
164
165=== added file 'src/unity-launcher.vala.OTHER'
166--- src/unity-launcher.vala.OTHER 1970-01-01 00:00:00 +0000
167+++ src/unity-launcher.vala.OTHER 2011-01-27 16:02:15 +0000
168@@ -0,0 +1,267 @@
169+/*
170+ * Copyright (C) 2011 Canonical, Ltd.
171+ *
172+ * This library is free software; you can redistribute it and/or modify
173+ * it under the terms of the GNU Lesser General Public License
174+ * version 3.0 as published by the Free Software Foundation.
175+ *
176+ * This library is distributed in the hope that it will be useful,
177+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
178+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
179+ * GNU Lesser General Public License version 3.0 for more details.
180+ *
181+ * You should have received a copy of the GNU Lesser General Public
182+ * License along with this library. If not, see
183+ * <http://www.gnu.org/licenses/>.
184+ *
185+ * Authored by Mikkel Kamstrup Erlandsen <mikkel.kamstrup@canonical.com>
186+ *
187+ */
188+
189+/*
190+ * IMPLEMENTATION NOTE:
191+ * We want the generated C API to be nice and not too Vala-ish. We must
192+ * anticipate that libunity consumers will be written in both Vala , C,
193+ * and through GObject Introspection
194+ *
195+ */
196+
197+using GLib;
198+
199+namespace Unity {
200+
201+ /* Private class to wire up the DBus stuff. Private so that we don't
202+ * leak DBus implementation details into the public API */
203+ [DBus (name = "org.canonical.Unity.LauncherEntry")]
204+ private class LauncherEntryDBusImpl : Object
205+ {
206+
207+ public weak LauncherEntry? owner;
208+
209+ public LauncherEntryDBusImpl (DBusConnection conn,
210+ ObjectPath object_path,
211+ LauncherEntry owner)
212+ {
213+ try {
214+ conn.register_object (object_path, this);
215+ } catch (IOError e) {
216+ warning ("Unable to connecto to session bus. Unable to control " +
217+ "LauncherEntry for %s", object_path);
218+ }
219+
220+ this.owner = owner;
221+ }
222+
223+ public signal void update (string app_uri,
224+ HashTable<string,Variant> properties);
225+
226+ public HashTable<string,Variant> query ()
227+ {
228+ /*var props = new HashTable<string,Variant>(str_hash, str_equal);
229+
230+ if (owner == null)
231+ return props;
232+
233+ props.insert ("count", owner.count);
234+ props.insert ("count-visible", owner.count_visible);
235+ props.insert ("progress", owner.progress);
236+ props.insert ("progress-visible", owner.progress_visible);
237+ props.insert ("emblem", owner.emblem == null ? "" : owner.emblem);
238+ props.insert ("emblem-visible", owner.emblem_visible);
239+
240+ if (owner.quicklist != null)
241+ props.insert ("quicklist", owner._object_path);
242+
243+ return props;*/
244+ if (owner == null)
245+ return new HashTable<string,Variant>(str_hash, str_equal);
246+
247+ return collect_launcher_entry_properties (owner);
248+ }
249+ }
250+
251+ /**
252+ * This class represents your control point for your application's icon
253+ * in the Unity Launcher. You can control properties such as a counter,
254+ * progress, or emblem that will be overlaid on your application's launcher
255+ * icon. You can also set a quicklist on it by setting the "quicklist"
256+ * property to point at the Dbusmenu.Menuitem which is the root of your
257+ * quicklist.
258+ *
259+ * Create a LauncherEntry by giving your desktop file id to the constructor
260+ * (eg. "myapp.desktop").
261+ */
262+ public class LauncherEntry : Serializable, Object
263+ {
264+ public string app_uri {get; set construct; }
265+
266+ public int64 count { get; set; default = 0; }
267+ public bool count_visible { get; set; default = false; }
268+
269+ public double progress { get; set; default = 0.0; }
270+ public bool progress_visible { get; set; default = false; }
271+
272+ public string? emblem { get; set; default = null; }
273+ public bool emblem_visible { get; set; default = false; }
274+
275+ private Dbusmenu.Menuitem? _quicklist;
276+ public Dbusmenu.Menuitem? quicklist {
277+ get { return _quicklist; }
278+ set {
279+ _quicklist = value;
280+ if (_quicklist != null) {
281+ _quicklist_server = new Dbusmenu.Server (_object_path);
282+ _quicklist_server.root_node = _quicklist;
283+ }
284+ }
285+ }
286+
287+ private HashTable<string,Variant> _queued_properties;
288+ private Dbusmenu.Server? _quicklist_server;
289+ private uint _property_source_id;
290+ private DBusConnection _bus;
291+ private LauncherEntryDBusImpl _dbus_impl;
292+ internal ObjectPath _object_path;
293+
294+ construct
295+ {
296+ _queued_properties = new HashTable<string,Variant>(str_hash, str_equal);
297+ _quicklist_server = null;
298+ _property_source_id = 0;
299+
300+ try {
301+ _bus = Bus.get_sync (BusType.SESSION);
302+ _object_path = new ObjectPath (@"/com/canonical/unity/launcherentry/$(app_uri.hash())");
303+ _dbus_impl = new LauncherEntryDBusImpl (_bus, _object_path, this);
304+
305+ var inspector = Inspector.get_default();
306+ inspector.notify["unity-running"].connect (on_unity_running_changed);
307+
308+ this.notify.connect (queue_property_notification);
309+ } catch (IOError e) {
310+ critical ("Unable to connect to session bus: %s", e.message);
311+ }
312+
313+ }
314+
315+ /**
316+ * Create a new LauncherEntry for the desktop file id of your application.
317+ *
318+ * The desktop file id is defined as the basename of your application's
319+ * .desktop file (including the extension), eg. myapp.desktop.
320+ */
321+ public LauncherEntry(string desktop_id)
322+ {
323+ Object (app_uri : "application://" + desktop_id);
324+ }
325+
326+ /* Implement interface Unity.Serializable */
327+ public Variant serialize ()
328+ {
329+ /* Vala will automagically marhshal the properties into a 'a{sv}' Variant */
330+ return collect_launcher_entry_properties (this);
331+ }
332+
333+ private void queue_property_notification (Object self, ParamSpec pspec)
334+ {
335+ Variant? v;
336+ ObjectPath object_path;
337+
338+ switch (pspec.name)
339+ {
340+ case "count":
341+ v = this.count;
342+ break;
343+ case "count-visible":
344+ v = this.count_visible;
345+ break;
346+ case "progress":
347+ v = this.progress;
348+ break;
349+ case "progress-visible":
350+ v = this.progress_visible;
351+ break;
352+ case "emblem":
353+ v = this.emblem != null ? this.emblem : "";
354+ break;
355+ case "emblem-visible":
356+ v = this.emblem_visible;
357+ break;
358+ case "quicklist":
359+ if (_quicklist_server != null)
360+ {
361+ _quicklist_server.get ("dbus-object", out object_path);
362+ v = object_path;
363+ }
364+ else
365+ {
366+ v = null; // FIXME: How to retract quicklist
367+ }
368+ break;
369+ default:
370+ /* Assume that this is a property we want to ignore wrt DBus */
371+ v = null;
372+ break;
373+ }
374+
375+ if (v != null)
376+ {
377+ _queued_properties.insert (pspec.name, v);
378+ }
379+
380+ if (_property_source_id == 0)
381+ {
382+ _property_source_id = Idle.add (dispatch_property_notification);
383+ }
384+ }
385+
386+ private bool dispatch_property_notification ()
387+ {
388+ /* Emit DBus signal with our changes if Unity is running.
389+ * If it's not running at this point we'll sync all our state
390+ * when it gets up */
391+ if (Inspector.get_default().unity_running)
392+ _dbus_impl.update (app_uri, _queued_properties);
393+
394+ /* Reset state */
395+ _property_source_id = 0;
396+ _queued_properties.remove_all ();
397+
398+ return false;
399+ }
400+
401+ /* Callback for when Unity comes or goes */
402+ private void on_unity_running_changed (Object _inspector, ParamSpec pspec)
403+ {
404+ Inspector inspector = _inspector as Inspector;
405+
406+ /* If Unity has just come online sync all out props to it */
407+ if (inspector.unity_running)
408+ {
409+ Variant props = serialize ();
410+ _bus.emit_signal (null, _object_path,
411+ "com.canonical.Unity.LauncherEntry",
412+ "Update", new Variant.tuple(new Variant[1]{props}));
413+ }
414+ }
415+
416+ } /* class Unity.LauncherEntry */
417+
418+ private static HashTable<string,Variant> collect_launcher_entry_properties (LauncherEntry l)
419+ {
420+ var props = new HashTable<string,Variant>(str_hash, str_equal);
421+
422+ props.insert ("count", l.count);
423+ props.insert ("count-visible", l.count_visible);
424+ props.insert ("progress", l.progress);
425+ props.insert ("progress-visible", l.progress_visible);
426+ props.insert ("emblem", l.emblem == null ? "" : l.emblem);
427+ props.insert ("emblem-visible", l.emblem_visible);
428+
429+ if (l.quicklist != null)
430+ props.insert ("quicklist", l._object_path);
431+
432+ return props;
433+ }
434+
435+} /* namespace */
436
437=== added file 'src/unity-serializable.vala'
438--- src/unity-serializable.vala 1970-01-01 00:00:00 +0000
439+++ src/unity-serializable.vala 2011-01-27 16:02:15 +0000
440@@ -0,0 +1,51 @@
441+/*
442+ * Copyright (C) 2011 Canonical, Ltd.
443+ *
444+ * This library is free software; you can redistribute it and/or modify
445+ * it under the terms of the GNU Lesser General Public License
446+ * version 3.0 as published by the Free Software Foundation.
447+ *
448+ * This library is distributed in the hope that it will be useful,
449+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
450+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
451+ * GNU Lesser General Public License version 3.0 for more details.
452+ *
453+ * You should have received a copy of the GNU Lesser General Public
454+ * License along with this library. If not, see
455+ * <http://www.gnu.org/licenses/>.
456+ *
457+ * Authored by Mikkel Kamstrup Erlandsen <mikkel.kamstrup@canonical.com>
458+ *
459+ */
460+
461+/*
462+ * IMPLEMENTATION NOTE:
463+ * We want the generated C API to be nice and not too Vala-ish. We must
464+ * anticipate that libunity consumers will be written in both Vala , C,
465+ * and through GObject Introspection
466+ *
467+ */
468+
469+using GLib;
470+
471+namespace Unity {
472+
473+ /**
474+ * Interface for anything that can be serialized to a GVariant.
475+ * This is useful both for persisting stuff to disk and for
476+ * sending across DBus.
477+ */
478+ public interface Serializable
479+ {
480+ /**
481+ * Create a GVariant describing the instance being serialized.
482+ *
483+ * @return A non-floating reference to a GVariant. If calling from C
484+ * free it with g_variant_unref().
485+ */
486+ public abstract Variant serialize ();
487+
488+ } /* interface Unity.Serializable */
489+
490+
491+} /* namespace */
492
493=== modified file 'test/vala/Makefile.am'
494--- test/vala/Makefile.am 2011-01-11 22:24:05 +0000
495+++ test/vala/Makefile.am 2011-01-27 16:02:15 +0000
496@@ -27,8 +27,9 @@
497 test_vala_SOURCES = \
498 test-appinfo-manager.vala \
499 test-io.vala \
500- test-place.vala \
501+ test-launcher.vala \
502 test-place-browser.vala \
503+ test-place.vala \
504 test-vala.vala
505
506 EXTRA_DIST += config.vapi
507
508=== added file 'test/vala/test-launcher.vala'
509--- test/vala/test-launcher.vala 1970-01-01 00:00:00 +0000
510+++ test/vala/test-launcher.vala 2011-01-27 16:02:15 +0000
511@@ -0,0 +1,50 @@
512+/* -*- Mode: vala; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
513+/*
514+ * Copyright (C) 2010 Canonical Ltd
515+ *
516+ * This program is free software: you can redistribute it and/or modify
517+ * it under the terms of the GNU General Public License version 3 as
518+ * published by the Free Software Foundation.
519+ *
520+ * This program is distributed in the hope that it will be useful,
521+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
522+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
523+ * GNU General Public License for more details.
524+ *
525+ * You should have received a copy of the GNU General Public License
526+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
527+ *
528+ * Authored by Mikkel Kamstrup Erlandsen <mikkel.kamstrup@canonical.com>
529+ *
530+ */
531+using Unity;
532+
533+namespace Unity.Test
534+{
535+ public class LauncherSuite
536+ {
537+ public LauncherSuite ()
538+ {
539+ GLib.Test.add_data_func ("/Unit/Launcher/Empty",
540+ LauncherSuite.test_empty_launcher_entry);
541+ }
542+
543+ internal static void test_empty_launcher_entry()
544+ {
545+ var l = new Unity.LauncherEntry("foo.desktop");
546+ assert (l is LauncherEntry);
547+ assert (l.app_uri == "application://foo.desktop");
548+
549+ assert (l.count == 0);
550+ assert (l.count_visible == false);
551+
552+ assert (l.progress == 0.0);
553+ assert (l.progress_visible == false);
554+
555+ assert (l.emblem == null);
556+ assert (l.emblem_visible == false);
557+
558+ assert (l.quicklist == null);
559+ }
560+ }
561+}
562
563=== modified file 'test/vala/test-vala.vala'
564--- test/vala/test-vala.vala 2011-01-20 10:00:26 +0000
565+++ test/vala/test-vala.vala 2011-01-27 16:02:15 +0000
566@@ -27,6 +27,7 @@
567 PlaceBrowserSuite place_browser;
568 IOSuite io;
569 AppInfoManagerSuite appinfo_manager;
570+ LauncherSuite launcher;
571
572 Environment.set_variable ("XDG_DATA_HOME", Config.TESTDIR+"/data", true);
573 Test.init (ref args);
574@@ -39,6 +40,8 @@
575 io = new IOSuite ();
576 appinfo_manager = new AppInfoManagerSuite ();
577
578+ launcher = new LauncherSuite ();
579+
580 Test.run ();
581
582 return 0;
583
584=== modified file 'unity.pc.in'
585--- unity.pc.in 2011-01-11 17:37:13 +0000
586+++ unity.pc.in 2011-01-27 16:02:15 +0000
587@@ -8,5 +8,5 @@
588 Version: @VERSION@
589 Libs: -L${libdir} -lunity
590 Cflags: -I${includedir}/unity/unity
591-Requires: glib-2.0 gthread-2.0 gobject-2.0 gio-2.0 gio-unix-2.0 dee-1.0 gee-1.0
592+Requires: glib-2.0 gthread-2.0 gobject-2.0 gio-2.0 gio-unix-2.0 dee-1.0 gee-1.0 dbusmenu-glib-0.4
593

Subscribers

People subscribed via source and target branches