Merge lp:~ted/libappindicator/unity-parser into lp:libappindicator/13.10

Proposed by Ted Gould
Status: Superseded
Proposed branch: lp:~ted/libappindicator/unity-parser
Merge into: lp:libappindicator/13.10
Diff against target: 818 lines (+333/-157)
8 files modified
configure.ac (+2/-2)
debian/control (+2/-3)
example/simple-client.c (+0/-2)
src/app-indicator.c (+283/-84)
src/app-indicator.h (+0/-4)
src/notification-item.xml (+2/-0)
tests/test-libappindicator.c (+35/-55)
tests/test-simple-app.c (+9/-7)
To merge this branch: bzr merge lp:~ted/libappindicator/unity-parser
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing
Indicator Applet Developers Pending
Review via email: mp+162011@code.launchpad.net

This proposal has been superseded by a proposal from 2013-06-09.

Commit message

Convert from DBusmenu to GMenuModel

Description of the change

Changing the backend of libappindicator to be based on GMenuModel instead of DBusmenu.

Pushing this up for review and people to start looking at, but if it lands the world will end. Okay, probably not that, but nothing will work as indicator-application needs to be updated first.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Charles Kerr (charlesk) wrote :

> Pushing this up for review and people to start looking at, but if it lands the world will end.

Some people just want to watch the world burn. APPROVE

lp:~ted/libappindicator/unity-parser updated
278. By Ted Gould

Adding back the server property and returning a warning

279. By Ted Gould

Keep the menu property as DBusmenu so we can tell between the two

280. By Ted Gould

Add properties for the GMenuModels

281. By Ted Gould

Adding support for the properties in their current form.

282. By Ted Gould

Fixing some docs errors

283. By Ted Gould

Adds in a structure and an array so that we can start tracking action groups as a set

284. By Ted Gould

Putting the bus stuff in the action info structure

285. By Ted Gould

Switch over to using the ActionInfo array

286. By Ted Gould

Handling the debug property using boxed types

287. By Ted Gould

Upgrade to a pop culture reference

288. By Ted Gould

Make GTK doc happy

289. By Ted Gould

Blocking a silly warning that isn't useful. Remember this when commenting on the quality of the GLib API.

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

Okay, I think I'm happy with this now. Had to clean up some of the action groups stuff. But it should work in most cases now. Next rev we can add a way to put GMenu/GActionGroups in with supported functions. For now we just need to support the old API.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Ted Gould (ted) wrote :

Wanted to note here so no one else investigates that the reason Jenkins is failing is because Raring doesn't have the required dependencies. They are in Saucy and the job is on the list to be updated.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)

Unmerged revisions

289. By Ted Gould

Blocking a silly warning that isn't useful. Remember this when commenting on the quality of the GLib API.

288. By Ted Gould

Make GTK doc happy

287. By Ted Gould

Upgrade to a pop culture reference

286. By Ted Gould

Handling the debug property using boxed types

285. By Ted Gould

Switch over to using the ActionInfo array

284. By Ted Gould

Putting the bus stuff in the action info structure

283. By Ted Gould

Adds in a structure and an array so that we can start tracking action groups as a set

282. By Ted Gould

Fixing some docs errors

281. By Ted Gould

Adding support for the properties in their current form.

280. By Ted Gould

Add properties for the GMenuModels

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 2013-01-29 17:50:13 +0000
3+++ configure.ac 2013-05-08 17:21:26 +0000
4@@ -58,7 +58,7 @@
5 glib-2.0 >= $GLIB_REQUIRED_VERSION
6 gio-2.0 >= $GIO_REQUIRED_VERSION
7 indicator3-0.4 >= $INDICATOR_REQUIRED_VERSION
8- dbusmenu-gtk3-0.4 >= $DBUSMENUGTK_REQUIRED_VERSION)
9+ unity-gtk3-parser)
10 AC_DEFINE(HAVE_GTK3, 1, [whether gtk3 is available])
11 ],
12 [test "x$with_gtk" = x2],
13@@ -66,7 +66,7 @@
14 glib-2.0 >= $GLIB_REQUIRED_VERSION
15 gio-2.0 >= $GIO_REQUIRED_VERSION
16 indicator-0.4 >= $INDICATOR_REQUIRED_VERSION
17- dbusmenu-gtk-0.4 >= $DBUSMENUGTK_REQUIRED_VERSION)
18+ unity-gtk2-parser)
19 ],
20 [AC_MSG_FAILURE([Value for --with-gtk was neither 2 nor 3])]
21 )
22
23=== modified file 'debian/control'
24--- debian/control 2013-03-11 12:59:43 +0000
25+++ debian/control 2013-05-08 17:21:26 +0000
26@@ -26,9 +26,8 @@
27 libdbus-glib-1-dev (>= 0.82),
28 libindicator-dev (>= 0.3.90),
29 libindicator3-dev (>= 0.3.90),
30- libdbusmenu-glib-dev (>= 0.5.90),
31- libdbusmenu-gtk-dev (>= 0.5.90),
32- libdbusmenu-gtk3-dev (>= 0.5.90),
33+ libunity-gtk2-parser-dev,
34+ libunity-gtk3-parser-dev,
35 libgirepository1.0-dev,
36 gir1.2-glib-2.0,
37 gir1.2-gtk-2.0,
38
39=== modified file 'example/simple-client.c'
40--- example/simple-client.c 2012-01-29 03:38:55 +0000
41+++ example/simple-client.c 2013-05-08 17:21:26 +0000
42@@ -21,8 +21,6 @@
43 */
44
45 #include "app-indicator.h"
46-#include "libdbusmenu-glib/server.h"
47-#include "libdbusmenu-glib/menuitem.h"
48
49 GMainLoop * mainloop = NULL;
50 static gboolean active = TRUE;
51
52=== modified file 'src/app-indicator.c'
53--- src/app-indicator.c 2013-04-19 12:07:21 +0000
54+++ src/app-indicator.c 2013-05-08 17:21:26 +0000
55@@ -31,10 +31,7 @@
56 #include "config.h"
57 #endif
58
59-#include <libdbusmenu-glib/menuitem.h>
60-#include <libdbusmenu-glib/server.h>
61-#include <libdbusmenu-gtk/client.h>
62-#include <libdbusmenu-gtk/parser.h>
63+#include <unity-gtk-parser.h>
64
65 #include <libindicator/indicator-desktop-shortcuts.h>
66
67@@ -52,16 +49,8 @@
68
69 /**
70 * AppIndicatorPrivate:
71+ *
72 * All of the private data in an instance of an application indicator.
73- *
74- * Private Fields
75- * @id: The ID of the indicator. Maps to AppIndicator:id.
76- * @category: Which category the indicator is. Maps to AppIndicator:category.
77- * @status: The status of the indicator. Maps to AppIndicator:status.
78- * @icon_name: The name of the icon to use. Maps to AppIndicator:icon-name.
79- * @attention_icon_name: The name of the attention icon to use. Maps to AppIndicator:attention-icon-name.
80- * @menu: The menu for this indicator. Maps to AppIndicator:menu
81- * @watcher_proxy: The proxy connection to the watcher we're connected to. If we're not connected to one this will be %NULL.
82 */
83 struct _AppIndicatorPrivate {
84 /*< Private >*/
85@@ -73,7 +62,6 @@
86 gchar *icon_name;
87 gchar *attention_icon_name;
88 gchar *icon_theme_path;
89- DbusmenuServer *menuservice;
90 GtkWidget *menu;
91 GtkWidget *sec_activate_target;
92 gboolean sec_activate_enabled;
93@@ -88,6 +76,12 @@
94 GtkStatusIcon * status_icon;
95 gint fallback_timer;
96
97+ /* Menu Stuff */
98+ GMenuModel * menu_model;
99+ guint menu_model_export;
100+ gchar * menu_shell_path;
101+ GArray * menu_groups;
102+
103 /* Fun stuff */
104 GDBusProxy *watcher_proxy;
105 GDBusConnection *connection;
106@@ -98,6 +92,16 @@
107 IndicatorDesktopShortcuts * shorties;
108 };
109
110+typedef struct _ActionInfo ActionInfo;
111+struct _ActionInfo {
112+ gchar * prefix;
113+ gchar * path;
114+ GActionGroup * group;
115+
116+ GDBusConnection * bus;
117+ guint export;
118+};
119+
120 /* Signals Stuff */
121 enum {
122 NEW_ICON,
123@@ -129,6 +133,8 @@
124 PROP_LABEL_GUIDE,
125 PROP_ORDERING_INDEX,
126 PROP_DBUS_MENU_SERVER,
127+ PROP_MENU_MODEL,
128+ PROP_ACTION_GROUPS,
129 PROP_TITLE
130 };
131
132@@ -147,6 +153,8 @@
133 #define PROP_ORDERING_INDEX_S "ordering-index"
134 #define PROP_DBUS_MENU_SERVER_S "dbus-menu-server"
135 #define PROP_TITLE_S "title"
136+#define PROP_MENU_MODEL_S "menu-model"
137+#define PROP_ACTION_GROUPS_S "action-groups"
138
139 /* Private macro, shhhh! */
140 #define APP_INDICATOR_GET_PRIVATE(o) \
141@@ -194,6 +202,10 @@
142 static void bus_method_call (GDBusConnection * connection, const gchar * sender, const gchar * path, const gchar * interface, const gchar * method, GVariant * params, GDBusMethodInvocation * invocation, gpointer user_data);
143 static void bus_creation (GObject * obj, GAsyncResult * res, gpointer user_data);
144 static void bus_watcher_ready (GObject * obj, GAsyncResult * res, gpointer user_data);
145+static void setup_dbusmenu (AppIndicator *self);
146+static void unexport_menu (AppIndicator *self);
147+static void export_me_maybe (AppIndicator *self);
148+static void action_info_clear (gpointer datain);
149
150 static const GDBusInterfaceVTable item_interface_table = {
151 method_call: bus_method_call,
152@@ -399,7 +411,6 @@
153 "A way to override the default ordering of the applications by providing a very specific idea of where this entry should be placed.",
154 0, G_MAXUINT32, 0,
155 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
156-
157 /**
158 * AppIndicator:dbus-menu-server:
159 *
160@@ -411,7 +422,7 @@
161 g_param_spec_object (PROP_DBUS_MENU_SERVER_S,
162 "The internal DBusmenu Server",
163 "DBusmenu server which is available for testing the application indicators.",
164- DBUSMENU_TYPE_SERVER,
165+ G_TYPE_OBJECT,
166 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
167 /**
168 * AppIndicator:title:
169@@ -429,6 +440,34 @@
170 NULL,
171 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
172
173+ /**
174+ * AppIndicator:menu-model:
175+ *
176+ * The built menu model. This is only used for testing and should
177+ * not be considered stable.
178+ */
179+ g_object_class_install_property(object_class,
180+ PROP_MENU_MODEL,
181+ g_param_spec_object (PROP_MENU_MODEL_S,
182+ "Internal Menu Model",
183+ "TESTING ONLY: Property to get the menu model",
184+ G_TYPE_MENU_MODEL,
185+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
186+
187+ /**
188+ * AppIndicator:action-groups:
189+ *
190+ * The built action group. This is only used for testing and should
191+ * not be considered stable.
192+ */
193+ g_object_class_install_property(object_class,
194+ PROP_ACTION_GROUPS,
195+ g_param_spec_boxed (PROP_ACTION_GROUPS_S,
196+ "Internal Action Group",
197+ "TESTING ONLY: Property to get the action group",
198+ G_TYPE_ARRAY,
199+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
200+
201 /* Signals */
202
203 /**
204@@ -479,7 +518,7 @@
205 * AppIndicator::new-label:
206 * @arg0: The #AppIndicator object
207 * @arg1: The string for the label
208- * @arg1: The string for the guide
209+ * @arg2: The string for the guide
210 *
211 * Emitted when either #AppIndicator:label or #AppIndicator:label-guide are
212 * changed.
213@@ -591,7 +630,7 @@
214 priv->attention_icon_name = NULL;
215 priv->icon_theme_path = NULL;
216 priv->menu = NULL;
217- priv->menuservice = NULL;
218+ priv->menu_shell_path = NULL;
219 priv->ordering_index = 0;
220 priv->title = NULL;
221 priv->label = NULL;
222@@ -611,6 +650,9 @@
223 priv->sec_activate_target = NULL;
224 priv->sec_activate_enabled = FALSE;
225
226+ priv->menu_groups = g_array_new(FALSE /* zero term */, FALSE /* clear */, sizeof(ActionInfo));
227+ g_array_set_clear_func(priv->menu_groups, action_info_clear);
228+
229 self->priv = priv;
230
231 /* Start getting the session bus */
232@@ -663,8 +705,12 @@
233 priv->menu = NULL;
234 }
235
236- if (priv->menuservice != NULL) {
237- g_object_unref (priv->menuservice);
238+ unexport_menu(self);
239+
240+ g_clear_object(&priv->menu_model);
241+
242+ if (priv->menu_groups->len > 0) {
243+ g_array_remove_range(priv->menu_groups, 0, priv->menu_groups->len);
244 }
245
246 if (priv->watcher_proxy != NULL) {
247@@ -765,10 +811,37 @@
248 priv->path = NULL;
249 }
250
251+ g_clear_pointer(&priv->menu_shell_path, g_free);
252+
253+ if (priv->menu_groups != NULL) {
254+ g_array_free(priv->menu_groups, TRUE /* destroy segment */);
255+ priv->menu_groups = NULL;
256+ }
257+
258 G_OBJECT_CLASS (app_indicator_parent_class)->finalize (object);
259 return;
260 }
261
262+/* Cleans up an action info struct */
263+static void
264+action_info_clear (gpointer datain)
265+{
266+ ActionInfo * ainfo = (ActionInfo *)datain;
267+
268+ g_clear_pointer(&ainfo->prefix, g_free);
269+ g_clear_pointer(&ainfo->path, g_free);
270+ g_clear_object(&ainfo->group);
271+
272+ if (ainfo->export != 0) {
273+ g_dbus_connection_unexport_action_group(ainfo->bus, ainfo->export);
274+ ainfo->export = 0;
275+ }
276+
277+ g_clear_object(&ainfo->bus);
278+
279+ return;
280+}
281+
282 #define WARN_BAD_TYPE(prop, value) g_warning("Can not work with property '%s' with value of type '%s'.", prop, G_VALUE_TYPE_NAME(value))
283
284 /* Set some properties */
285@@ -926,10 +999,28 @@
286 break;
287
288 case PROP_DBUS_MENU_SERVER:
289- g_clear_object (&priv->menuservice);
290- priv->menuservice = DBUSMENU_SERVER (g_value_dup_object(value));
291- break;
292-
293+ g_warning("DBus Menu Server is a testing parameter. Why are you using it? Please stop.");
294+ break;
295+
296+ case PROP_MENU_MODEL:
297+ unexport_menu(self);
298+
299+ g_clear_object(&priv->menu_model);
300+ priv->menu_model = g_value_dup_object(value);
301+
302+ export_me_maybe(self);
303+ break;
304+ case PROP_ACTION_GROUPS:
305+ if (priv->menu_groups != NULL) {
306+ g_array_free(priv->menu_groups, TRUE /* destroy segment */);
307+ priv->menu_groups = NULL;
308+ }
309+
310+ priv->menu_groups = g_value_get_boxed(value);
311+ g_array_ref(priv->menu_groups);
312+
313+ export_me_maybe(self);
314+ break;
315 default:
316 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
317 break;
318@@ -1009,13 +1100,22 @@
319 break;
320
321 case PROP_DBUS_MENU_SERVER:
322- g_value_set_object(value, priv->menuservice);
323+ g_warning("DBus Menu Server is a testing parameter. Why are you using it? Please stop.");
324+ g_value_set_object(value, NULL);
325 break;
326
327 case PROP_TITLE:
328 g_value_set_string(value, priv->title);
329 break;
330
331+ case PROP_MENU_MODEL:
332+ g_value_set_object(value, priv->menu_model);
333+ break;
334+
335+ case PROP_ACTION_GROUPS:
336+ g_value_set_boxed(value, priv->menu_groups);
337+ break;
338+
339 default:
340 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
341 break;
342@@ -1138,16 +1238,7 @@
343 } else if (g_strcmp0(property, "IconThemePath") == 0) {
344 return g_variant_new_string(priv->icon_theme_path ? priv->icon_theme_path : "");
345 } else if (g_strcmp0(property, "Menu") == 0) {
346- if (priv->menuservice != NULL) {
347- GValue strval = { 0 };
348- g_value_init(&strval, G_TYPE_STRING);
349- g_object_get_property (G_OBJECT (priv->menuservice), DBUSMENU_SERVER_PROP_DBUS_OBJECT, &strval);
350- GVariant * var = g_variant_new("o", g_value_get_string(&strval));
351- g_value_unset(&strval);
352- return var;
353- } else {
354- return g_variant_new("o", "/");
355- }
356+ return g_variant_new("o", "/");
357 } else if (g_strcmp0(property, "XAyatanaLabel") == 0) {
358 return g_variant_new_string(priv->label ? priv->label : "");
359 } else if (g_strcmp0(property, "XAyatanaLabelGuide") == 0) {
360@@ -1158,6 +1249,31 @@
361 return g_variant_new_string(priv->accessible_desc ? priv->accessible_desc : "");
362 } else if (g_strcmp0(property, "AttentionAccessibleDesc") == 0) {
363 return g_variant_new_string(priv->att_accessible_desc ? priv->att_accessible_desc : "");
364+ } else if (g_strcmp0(property, "XCanonicalMenuModel") == 0) {
365+ if (priv->menu_shell_path != NULL) {
366+ return g_variant_new_object_path(priv->menu_shell_path);
367+ } else {
368+ return g_variant_new_object_path("/");
369+ }
370+ } else if (g_strcmp0(property, "XCanonicalActionGroups") == 0) {
371+ if (priv->menu_groups->len != 0) {
372+ GVariantBuilder array;
373+ g_variant_builder_init(&array, G_VARIANT_TYPE_ARRAY);
374+
375+ int i;
376+ for (i = 0; i < priv->menu_groups->len; i++) {
377+ ActionInfo * ainfo = &g_array_index(priv->menu_groups, ActionInfo, i);
378+
379+ g_variant_builder_open(&array, G_VARIANT_TYPE_TUPLE);
380+ g_variant_builder_add_value(&array, g_variant_new_string(ainfo->prefix));
381+ g_variant_builder_add_value(&array, g_variant_new_object_path(ainfo->path));
382+ g_variant_builder_close(&array);
383+ }
384+
385+ return g_variant_builder_end(&array);
386+ } else {
387+ return g_variant_new_array(G_VARIANT_TYPE("(so)"), NULL, 0);
388+ }
389 }
390
391 *error = g_error_new(0, 0, "Unknown property: %s", property);
392@@ -1261,6 +1377,8 @@
393 }
394 }
395
396+ export_me_maybe(self);
397+
398 /* NOTE: It's really important the order here. We make sure to *publish*
399 the object on the bus and *then* get the proxy. The reason is that we
400 want to ensure all the filters are setup before talking to the watcher
401@@ -1746,6 +1864,79 @@
402 self->priv->sec_activate_enabled = widget_is_menu_child(self, menuitem);
403 }
404
405+/* Unexport the menu, doesn't unref objects */
406+static void
407+unexport_menu (AppIndicator *self)
408+{
409+ AppIndicatorPrivate *priv = self->priv;
410+
411+ if (priv->connection == NULL) {
412+ return;
413+ }
414+
415+ if (priv->menu_model_export != 0) {
416+ g_dbus_connection_unexport_menu_model(priv->connection, priv->menu_model_export);
417+ priv->menu_model_export = 0;
418+ }
419+
420+ if (priv->menu_groups->len > 0) {
421+ g_array_remove_range(priv->menu_groups, 0, priv->menu_groups->len);
422+ }
423+
424+ g_clear_pointer(&priv->menu_shell_path, g_free);
425+
426+ return;
427+}
428+
429+/* We just met, and I know this is crazy, but export me maybe? */
430+/* Export the menu if we've got everything we need */
431+static void
432+export_me_maybe (AppIndicator *self)
433+{
434+ AppIndicatorPrivate *priv = self->priv;
435+
436+ if (priv->connection == NULL) {
437+ return;
438+ }
439+
440+ if (priv->menu_model == NULL) {
441+ return;
442+ }
443+
444+ if (priv->menu_groups->len == 0) {
445+ return;
446+ }
447+
448+ if (priv->menu_model_export != 0) {
449+ return;
450+ }
451+
452+ GError * error = NULL;
453+ int i;
454+ for (i = 0; i < priv->menu_groups->len; i++) {
455+ ActionInfo * ainfo = &g_array_index(priv->menu_groups, ActionInfo, i);
456+
457+ ainfo->bus = g_object_ref(priv->connection);
458+
459+ ainfo->export = g_dbus_connection_export_action_group(ainfo->bus, ainfo->path, ainfo->group, &error);
460+
461+ if (error != NULL) {
462+ g_warning("Unable to export action group as '%s': %s", ainfo->path, error->message);
463+ g_error_free(error);
464+ error = NULL;
465+ }
466+ }
467+
468+ priv->menu_model_export = g_dbus_connection_export_menu_model(priv->connection, priv->menu_shell_path, priv->menu_model, NULL);
469+
470+ if (error != NULL) {
471+ g_warning("Unable to export menu model as '%s': %s", priv->menu_shell_path, error->message);
472+ g_error_free(error);
473+ error = NULL;
474+ }
475+
476+ return;
477+}
478
479 /* ************************* */
480 /* Public Functions */
481@@ -2072,25 +2263,26 @@
482 setup_dbusmenu (AppIndicator *self)
483 {
484 AppIndicatorPrivate *priv;
485- DbusmenuMenuitem *root = NULL;
486-
487 priv = self->priv;
488
489+ unexport_menu(self);
490+
491+ g_clear_object(&priv->menu_model);
492+
493 if (priv->menu) {
494- root = dbusmenu_gtk_parse_menu_structure(priv->menu);
495- }
496-
497- if (priv->menuservice == NULL) {
498- gchar * path = g_strdup_printf(DEFAULT_ITEM_PATH "/%s/Menu", priv->clean_id);
499- priv->menuservice = dbusmenu_server_new (path);
500- g_free(path);
501- }
502-
503- dbusmenu_server_set_root (priv->menuservice, root);
504-
505- /* Drop our local ref as set_root should get it's own. */
506- if (root != NULL) {
507- g_object_unref(root);
508+ ActionInfo ainfo;
509+
510+ priv->menu_model = G_MENU_MODEL(unity_gtk_menu_shell_new(GTK_MENU_SHELL(priv->menu)));
511+ priv->menu_shell_path = g_strdup_printf(DEFAULT_ITEM_PATH "/%s/Menu", priv->clean_id);
512+
513+ ainfo.group = G_ACTION_GROUP(unity_gtk_action_group_new(NULL));
514+ ainfo.prefix = g_strdup("unity");
515+ ainfo.path = g_strdup(priv->menu_shell_path);
516+ g_array_append_val(priv->menu_groups, ainfo);
517+
518+ unity_gtk_action_group_connect_shell(UNITY_GTK_ACTION_GROUP(ainfo.group), UNITY_GTK_MENU_SHELL(priv->menu_model));
519+
520+ export_me_maybe(self);
521 }
522
523 return;
524@@ -2463,14 +2655,13 @@
525 return GTK_WIDGET(self->priv->sec_activate_target);
526 }
527
528-#define APP_INDICATOR_SHORTY_NICK "app-indicator-shorty-nick"
529-
530 /* Callback when an item from the desktop shortcuts gets
531 called. */
532 static void
533-shorty_activated_cb (DbusmenuMenuitem * mi, guint timestamp, gpointer user_data)
534+shorty_activated_cb (GSimpleAction * action, GVariant * param, gpointer user_data)
535 {
536- gchar * nick = g_object_get_data(G_OBJECT(mi), APP_INDICATOR_SHORTY_NICK);
537+ gchar * nick = NULL;
538+ g_object_get(G_OBJECT(action), "name", &nick, NULL);
539 g_return_if_fail(nick != NULL);
540
541 g_return_if_fail(IS_APP_INDICATOR(user_data));
542@@ -2500,45 +2691,53 @@
543 AppIndicatorPrivate *priv = self->priv;
544
545 /* Build a new shortcuts object */
546- if (priv->shorties != NULL) {
547- g_object_unref(priv->shorties);
548- priv->shorties = NULL;
549- }
550+ g_clear_object(&priv->shorties);
551 priv->shorties = indicator_desktop_shortcuts_new(desktop_file, desktop_profile);
552 g_return_if_fail(priv->shorties != NULL);
553
554+ /* Remove the exported menu */
555+ unexport_menu(self);
556+
557+ g_clear_object(&priv->menu_model);
558+
559+ /* Get the 'nicks' */
560 const gchar ** nicks = indicator_desktop_shortcuts_get_nicks(priv->shorties);
561+
562+ if (nicks[0] == NULL) {
563+ g_warning("Desktop file '%s' doesn't contain any usable actions", desktop_file);
564+ return;
565+ }
566+
567+ /* Build new menus and action groups */
568+ GMenu * menu = g_menu_new();
569+ priv->menu_model = G_MENU_MODEL(menu);
570+ priv->menu_shell_path = g_strdup_printf(DEFAULT_ITEM_PATH "/%s/Menu", priv->clean_id);
571+
572+ ActionInfo ainfo;
573+ GSimpleActionGroup * actions = g_simple_action_group_new();
574+ ainfo.group = G_ACTION_GROUP(actions);
575+ ainfo.prefix = g_strdup("");
576+ ainfo.path = g_strdup(priv->menu_shell_path);
577+ g_array_append_val(priv->menu_groups, ainfo);
578+
579 int nick_num;
580-
581- /* Place the items on a dbusmenu */
582- DbusmenuMenuitem * root = dbusmenu_menuitem_new();
583-
584 for (nick_num = 0; nicks[nick_num] != NULL; nick_num++) {
585- DbusmenuMenuitem * item = dbusmenu_menuitem_new();
586- g_object_set_data(G_OBJECT(item), APP_INDICATOR_SHORTY_NICK, (gpointer)nicks[nick_num]);
587+ GSimpleAction * action = g_simple_action_new(nicks[nick_num], NULL);
588+ g_signal_connect(action, "activate", G_CALLBACK(shorty_activated_cb), self);
589
590 gchar * name = indicator_desktop_shortcuts_nick_get_name(priv->shorties, nicks[nick_num]);
591- dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, name);
592+ GMenuItem * item = g_menu_item_new(name, nicks[nick_num]);
593 g_free(name);
594
595- g_signal_connect(G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(shorty_activated_cb), self);
596-
597- dbusmenu_menuitem_child_append(root, item);
598- }
599-
600- /* Swap it if needed */
601- if (priv->menuservice == NULL) {
602- gchar * path = g_strdup_printf(DEFAULT_ITEM_PATH "/%s/Menu", priv->clean_id);
603- priv->menuservice = dbusmenu_server_new (path);
604- g_free(path);
605- }
606-
607- dbusmenu_server_set_root (priv->menuservice, root);
608-
609- if (priv->menu != NULL) {
610- g_object_unref(G_OBJECT(priv->menu));
611- priv->menu = NULL;
612- }
613+ g_simple_action_group_insert(actions, G_ACTION(action));
614+ g_menu_append_item(menu, item);
615+
616+ g_object_unref(action);
617+ g_object_unref(item);
618+ }
619+
620+ /* Export the menu and action group */
621+ export_me_maybe(self);
622
623 return;
624 }
625
626=== modified file 'src/app-indicator.h'
627--- src/app-indicator.h 2012-02-03 20:37:56 +0000
628+++ src/app-indicator.h 2013-05-08 17:21:26 +0000
629@@ -238,10 +238,6 @@
630 * unique status in the panel for an application. In general, applications
631 * should try to fit in the other indicators that are available on the
632 * panel before using this. But, sometimes it is necissary.
633- *
634- * Private fields
635- * @parent: Parent object.
636- * @priv: Internal data.
637 */
638 struct _AppIndicator {
639 GObject parent;
640
641=== modified file 'src/notification-item.xml'
642--- src/notification-item.xml 2012-02-03 20:37:56 +0000
643+++ src/notification-item.xml 2013-05-08 17:21:26 +0000
644@@ -18,6 +18,8 @@
645 <property name="XAyatanaLabel" type="s" access="read" />
646 <property name="XAyatanaLabelGuide" type="s" access="read" />
647 <property name="XAyatanaOrderingIndex" type="u" access="read" />
648+ <property name="XCanonicalMenuModel" type="o" access="read" />
649+ <property name="XCanonicalActionGroups" type="a(so)" access="read" />
650
651 <!-- Methods -->
652 <method name="Scroll">
653
654=== modified file 'tests/test-libappindicator.c'
655--- tests/test-libappindicator.c 2013-01-10 22:18:55 +0000
656+++ tests/test-libappindicator.c 2013-05-08 17:21:26 +0000
657@@ -22,12 +22,10 @@
658
659 #include <glib.h>
660 #include <glib-object.h>
661+#include <gio/gio.h>
662
663 #include <app-indicator.h>
664
665-#include <libdbusmenu-glib/menuitem.h>
666-#include <libdbusmenu-glib/server.h>
667-
668 static gboolean
669 allow_warnings (const gchar *log_domain, GLogLevelFlags log_level,
670 const gchar *message, gpointer user_data)
671@@ -270,26 +268,26 @@
672
673 g_assert(app_indicator_get_menu(ci) != NULL);
674
675- GValue serverval = {0};
676- g_value_init(&serverval, DBUSMENU_TYPE_SERVER);
677- g_object_get_property(G_OBJECT(ci), "dbus-menu-server", &serverval);
678-
679- DbusmenuServer * server = DBUSMENU_SERVER(g_value_get_object(&serverval));
680- g_assert(server != NULL);
681-
682- GValue rootval = {0};
683- g_value_init(&rootval, DBUSMENU_TYPE_MENUITEM);
684- g_object_get_property(G_OBJECT(server), DBUSMENU_SERVER_PROP_ROOT_NODE, &rootval);
685- DbusmenuMenuitem * root = DBUSMENU_MENUITEM(g_value_get_object(&rootval));
686- g_assert(root != NULL);
687-
688- GList * children = dbusmenu_menuitem_get_children(root);
689- g_assert(children != NULL);
690- g_assert(g_list_length(children) == 1);
691-
692- const gchar * label = dbusmenu_menuitem_property_get(DBUSMENU_MENUITEM(children->data), DBUSMENU_MENUITEM_PROP_LABEL);
693+ GValue modelval = {0};
694+ g_value_init(&modelval, G_TYPE_MENU_MODEL);
695+ g_object_get_property(G_OBJECT(ci), "menu-model", &modelval);
696+
697+ GMenuModel * model = G_MENU_MODEL(g_value_get_object(&modelval));
698+ g_assert(model != NULL);
699+
700+ g_assert_cmpint(g_menu_model_get_n_items(model), ==, 1);
701+
702+ GMenuModel * section = g_menu_model_get_item_link(model, 0, G_MENU_LINK_SECTION);
703+ g_assert(section != NULL);
704+
705+ g_assert_cmpint(g_menu_model_get_n_items(section), ==, 1);
706+
707+ GVariant * label = g_menu_model_get_item_attribute_value(section, 0, G_MENU_ATTRIBUTE_LABEL, G_VARIANT_TYPE_STRING);
708 g_assert(label != NULL);
709- g_assert(g_strcmp0(label, "Test Label") == 0);
710+ g_assert(g_strcmp0("Test Label", g_variant_get_string(label, NULL)) == 0);
711+
712+ g_variant_unref(label);
713+ g_object_unref(model);
714
715 /* Interesting, eh? We need this because we send out events on the bus
716 but they don't come back until the idle is run. So we need those
717@@ -388,24 +386,15 @@
718
719 app_indicator_build_menu_from_desktop(ci, SRCDIR "/test-libappindicator.desktop", "Test Program");
720
721- GValue serverval = {0};
722- g_value_init(&serverval, DBUSMENU_TYPE_SERVER);
723- g_object_get_property(G_OBJECT(ci), "dbus-menu-server", &serverval);
724-
725- DbusmenuServer * server = DBUSMENU_SERVER(g_value_get_object(&serverval));
726- g_assert(server != NULL);
727-
728- GValue rootval = {0};
729- g_value_init(&rootval, DBUSMENU_TYPE_MENUITEM);
730- g_object_get_property(G_OBJECT(server), DBUSMENU_SERVER_PROP_ROOT_NODE, &rootval);
731- DbusmenuMenuitem * root = DBUSMENU_MENUITEM(g_value_get_object(&rootval));
732- g_assert(root != NULL);
733-
734- GList * children = dbusmenu_menuitem_get_children(root);
735- g_assert(children != NULL);
736- g_assert(g_list_length(children) == 3);
737-
738-
739+ GValue modelval = {0};
740+ g_value_init(&modelval, G_TYPE_MENU_MODEL);
741+ g_object_get_property(G_OBJECT(ci), "menu-model", &modelval);
742+
743+ GMenuModel * model = G_MENU_MODEL(g_value_get_object(&modelval));
744+ g_assert(model != NULL);
745+
746+ g_assert(g_menu_model_get_n_items(model) == 3);
747+ g_object_unref(model);
748
749 g_object_unref(G_OBJECT(ci));
750 return;
751@@ -426,21 +415,12 @@
752
753 app_indicator_build_menu_from_desktop(ci, SRCDIR "/test-libappindicator.desktop", "Not Test Program");
754
755- GValue serverval = {0};
756- g_value_init(&serverval, DBUSMENU_TYPE_SERVER);
757- g_object_get_property(G_OBJECT(ci), "dbus-menu-server", &serverval);
758-
759- DbusmenuServer * server = DBUSMENU_SERVER(g_value_get_object(&serverval));
760- g_assert(server != NULL);
761-
762- GValue rootval = {0};
763- g_value_init(&rootval, DBUSMENU_TYPE_MENUITEM);
764- g_object_get_property(G_OBJECT(server), DBUSMENU_SERVER_PROP_ROOT_NODE, &rootval);
765- DbusmenuMenuitem * root = DBUSMENU_MENUITEM(g_value_get_object(&rootval));
766- g_assert(root != NULL);
767-
768- GList * children = dbusmenu_menuitem_get_children(root);
769- g_assert(g_list_length(children) == 0);
770+ GValue modelval = {0};
771+ g_value_init(&modelval, G_TYPE_MENU_MODEL);
772+ g_object_get_property(G_OBJECT(ci), "menu-model", &modelval);
773+
774+ GMenuModel * model = G_MENU_MODEL(g_value_get_object(&modelval));
775+ g_assert(model == NULL);
776
777 g_object_unref(G_OBJECT(ci));
778 return;
779
780=== modified file 'tests/test-simple-app.c'
781--- tests/test-simple-app.c 2013-01-16 19:53:52 +0000
782+++ tests/test-simple-app.c 2013-05-08 17:21:26 +0000
783@@ -20,10 +20,8 @@
784 */
785
786
787-#include <dbus/dbus-glib.h>
788-#include <dbus/dbus-glib-lowlevel.h>
789 #include <glib.h>
790-#include <libdbusmenu-glib/server.h>
791+#include <gio/gio.h>
792 #include <app-indicator.h>
793
794 static GMainLoop * mainloop = NULL;
795@@ -31,15 +29,19 @@
796 int
797 main (int argc, char ** argv)
798 {
799- DbusmenuServer * dms = dbusmenu_server_new("/menu");
800- DbusmenuMenuitem * dmi = dbusmenu_menuitem_new();
801- dbusmenu_menuitem_property_set(dmi, "label", "Bob");
802+ GMenu * menu = g_menu_new();
803+ g_menu_append(menu, "Bob", "action");
804+
805+ GSimpleActionGroup * actions = g_simple_action_group_new();
806+ GSimpleAction * action = g_simple_action_new("action", NULL);
807+ g_simple_action_group_insert(actions, G_ACTION(action));
808
809 AppIndicator * ci = APP_INDICATOR(g_object_new(APP_INDICATOR_TYPE,
810 "id", "test-application",
811 "status-enum", APP_INDICATOR_STATUS_ACTIVE,
812 "icon-name", "system-shutdown",
813- "menu-object", dms,
814+ "menu-model", menu,
815+ "action-group", actions,
816 NULL));
817
818 mainloop = g_main_loop_new(NULL, FALSE);

Subscribers

People subscribed via source and target branches