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

Proposed by Ted Gould
Status: Work in progress
Proposed branch: lp:~ted/libappindicator/unity-parser
Merge into: lp:libappindicator/13.10
Prerequisite: lp:~ted/libappindicator/saucy-fix
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 Approve
Indicator Applet Developers Pending
Review via email: mp+168286@code.launchpad.net

This proposal supersedes a proposal from 2013-05-02.

Commit message

Convert from DBusMenu to GMenu

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 : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Charles Kerr (charlesk) wrote : Posted in a previous version of this proposal

> 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

Revision history for this message
Ted Gould (ted) wrote : Posted in a previous version of this proposal

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 : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Ted Gould (ted) wrote : Posted in a previous version of this proposal

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 : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Ted Gould (ted) wrote :

Rebased on the saucy fix to see if we can make Jenkins happy.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (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
=== modified file 'configure.ac'
--- configure.ac 2013-01-29 17:50:13 +0000
+++ configure.ac 2013-06-09 14:13:32 +0000
@@ -58,7 +58,7 @@
58 glib-2.0 >= $GLIB_REQUIRED_VERSION58 glib-2.0 >= $GLIB_REQUIRED_VERSION
59 gio-2.0 >= $GIO_REQUIRED_VERSION59 gio-2.0 >= $GIO_REQUIRED_VERSION
60 indicator3-0.4 >= $INDICATOR_REQUIRED_VERSION60 indicator3-0.4 >= $INDICATOR_REQUIRED_VERSION
61 dbusmenu-gtk3-0.4 >= $DBUSMENUGTK_REQUIRED_VERSION)61 unity-gtk3-parser)
62 AC_DEFINE(HAVE_GTK3, 1, [whether gtk3 is available])62 AC_DEFINE(HAVE_GTK3, 1, [whether gtk3 is available])
63 ],63 ],
64 [test "x$with_gtk" = x2],64 [test "x$with_gtk" = x2],
@@ -66,7 +66,7 @@
66 glib-2.0 >= $GLIB_REQUIRED_VERSION66 glib-2.0 >= $GLIB_REQUIRED_VERSION
67 gio-2.0 >= $GIO_REQUIRED_VERSION67 gio-2.0 >= $GIO_REQUIRED_VERSION
68 indicator-0.4 >= $INDICATOR_REQUIRED_VERSION68 indicator-0.4 >= $INDICATOR_REQUIRED_VERSION
69 dbusmenu-gtk-0.4 >= $DBUSMENUGTK_REQUIRED_VERSION)69 unity-gtk2-parser)
70 ],70 ],
71 [AC_MSG_FAILURE([Value for --with-gtk was neither 2 nor 3])]71 [AC_MSG_FAILURE([Value for --with-gtk was neither 2 nor 3])]
72)72)
7373
=== modified file 'debian/control'
--- debian/control 2013-03-11 12:59:43 +0000
+++ debian/control 2013-06-09 14:13:32 +0000
@@ -26,9 +26,8 @@
26 libdbus-glib-1-dev (>= 0.82),26 libdbus-glib-1-dev (>= 0.82),
27 libindicator-dev (>= 0.3.90),27 libindicator-dev (>= 0.3.90),
28 libindicator3-dev (>= 0.3.90),28 libindicator3-dev (>= 0.3.90),
29 libdbusmenu-glib-dev (>= 0.5.90),29 libunity-gtk2-parser-dev,
30 libdbusmenu-gtk-dev (>= 0.5.90),30 libunity-gtk3-parser-dev,
31 libdbusmenu-gtk3-dev (>= 0.5.90),
32 libgirepository1.0-dev,31 libgirepository1.0-dev,
33 gir1.2-glib-2.0,32 gir1.2-glib-2.0,
34 gir1.2-gtk-2.0,33 gir1.2-gtk-2.0,
3534
=== modified file 'example/simple-client.c'
--- example/simple-client.c 2012-01-29 03:38:55 +0000
+++ example/simple-client.c 2013-06-09 14:13:32 +0000
@@ -21,8 +21,6 @@
21*/21*/
2222
23#include "app-indicator.h"23#include "app-indicator.h"
24#include "libdbusmenu-glib/server.h"
25#include "libdbusmenu-glib/menuitem.h"
2624
27GMainLoop * mainloop = NULL;25GMainLoop * mainloop = NULL;
28static gboolean active = TRUE;26static gboolean active = TRUE;
2927
=== modified file 'src/app-indicator.c'
--- src/app-indicator.c 2013-04-19 12:07:21 +0000
+++ src/app-indicator.c 2013-06-09 14:13:32 +0000
@@ -31,10 +31,7 @@
31#include "config.h"31#include "config.h"
32#endif32#endif
3333
34#include <libdbusmenu-glib/menuitem.h>34#include <unity-gtk-parser.h>
35#include <libdbusmenu-glib/server.h>
36#include <libdbusmenu-gtk/client.h>
37#include <libdbusmenu-gtk/parser.h>
3835
39#include <libindicator/indicator-desktop-shortcuts.h>36#include <libindicator/indicator-desktop-shortcuts.h>
4037
@@ -52,16 +49,8 @@
5249
53/**50/**
54 * AppIndicatorPrivate:51 * AppIndicatorPrivate:
52 *
55 * All of the private data in an instance of an application indicator.53 * All of the private data in an instance of an application indicator.
56 *
57 * Private Fields
58 * @id: The ID of the indicator. Maps to AppIndicator:id.
59 * @category: Which category the indicator is. Maps to AppIndicator:category.
60 * @status: The status of the indicator. Maps to AppIndicator:status.
61 * @icon_name: The name of the icon to use. Maps to AppIndicator:icon-name.
62 * @attention_icon_name: The name of the attention icon to use. Maps to AppIndicator:attention-icon-name.
63 * @menu: The menu for this indicator. Maps to AppIndicator:menu
64 * @watcher_proxy: The proxy connection to the watcher we're connected to. If we're not connected to one this will be %NULL.
65 */54 */
66struct _AppIndicatorPrivate {55struct _AppIndicatorPrivate {
67 /*< Private >*/56 /*< Private >*/
@@ -73,7 +62,6 @@
73 gchar *icon_name;62 gchar *icon_name;
74 gchar *attention_icon_name;63 gchar *attention_icon_name;
75 gchar *icon_theme_path;64 gchar *icon_theme_path;
76 DbusmenuServer *menuservice;
77 GtkWidget *menu;65 GtkWidget *menu;
78 GtkWidget *sec_activate_target;66 GtkWidget *sec_activate_target;
79 gboolean sec_activate_enabled;67 gboolean sec_activate_enabled;
@@ -88,6 +76,12 @@
88 GtkStatusIcon * status_icon;76 GtkStatusIcon * status_icon;
89 gint fallback_timer;77 gint fallback_timer;
9078
79 /* Menu Stuff */
80 GMenuModel * menu_model;
81 guint menu_model_export;
82 gchar * menu_shell_path;
83 GArray * menu_groups;
84
91 /* Fun stuff */85 /* Fun stuff */
92 GDBusProxy *watcher_proxy;86 GDBusProxy *watcher_proxy;
93 GDBusConnection *connection;87 GDBusConnection *connection;
@@ -98,6 +92,16 @@
98 IndicatorDesktopShortcuts * shorties;92 IndicatorDesktopShortcuts * shorties;
99};93};
10094
95typedef struct _ActionInfo ActionInfo;
96struct _ActionInfo {
97 gchar * prefix;
98 gchar * path;
99 GActionGroup * group;
100
101 GDBusConnection * bus;
102 guint export;
103};
104
101/* Signals Stuff */105/* Signals Stuff */
102enum {106enum {
103 NEW_ICON,107 NEW_ICON,
@@ -129,6 +133,8 @@
129 PROP_LABEL_GUIDE,133 PROP_LABEL_GUIDE,
130 PROP_ORDERING_INDEX,134 PROP_ORDERING_INDEX,
131 PROP_DBUS_MENU_SERVER,135 PROP_DBUS_MENU_SERVER,
136 PROP_MENU_MODEL,
137 PROP_ACTION_GROUPS,
132 PROP_TITLE138 PROP_TITLE
133};139};
134140
@@ -147,6 +153,8 @@
147#define PROP_ORDERING_INDEX_S "ordering-index"153#define PROP_ORDERING_INDEX_S "ordering-index"
148#define PROP_DBUS_MENU_SERVER_S "dbus-menu-server"154#define PROP_DBUS_MENU_SERVER_S "dbus-menu-server"
149#define PROP_TITLE_S "title"155#define PROP_TITLE_S "title"
156#define PROP_MENU_MODEL_S "menu-model"
157#define PROP_ACTION_GROUPS_S "action-groups"
150158
151/* Private macro, shhhh! */159/* Private macro, shhhh! */
152#define APP_INDICATOR_GET_PRIVATE(o) \160#define APP_INDICATOR_GET_PRIVATE(o) \
@@ -194,6 +202,10 @@
194static 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);202static 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);
195static void bus_creation (GObject * obj, GAsyncResult * res, gpointer user_data);203static void bus_creation (GObject * obj, GAsyncResult * res, gpointer user_data);
196static void bus_watcher_ready (GObject * obj, GAsyncResult * res, gpointer user_data);204static void bus_watcher_ready (GObject * obj, GAsyncResult * res, gpointer user_data);
205static void setup_dbusmenu (AppIndicator *self);
206static void unexport_menu (AppIndicator *self);
207static void export_me_maybe (AppIndicator *self);
208static void action_info_clear (gpointer datain);
197209
198static const GDBusInterfaceVTable item_interface_table = {210static const GDBusInterfaceVTable item_interface_table = {
199 method_call: bus_method_call,211 method_call: bus_method_call,
@@ -399,7 +411,6 @@
399 "A way to override the default ordering of the applications by providing a very specific idea of where this entry should be placed.",411 "A way to override the default ordering of the applications by providing a very specific idea of where this entry should be placed.",
400 0, G_MAXUINT32, 0,412 0, G_MAXUINT32, 0,
401 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));413 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
402
403 /**414 /**
404 * AppIndicator:dbus-menu-server:415 * AppIndicator:dbus-menu-server:
405 *416 *
@@ -411,7 +422,7 @@
411 g_param_spec_object (PROP_DBUS_MENU_SERVER_S,422 g_param_spec_object (PROP_DBUS_MENU_SERVER_S,
412 "The internal DBusmenu Server",423 "The internal DBusmenu Server",
413 "DBusmenu server which is available for testing the application indicators.",424 "DBusmenu server which is available for testing the application indicators.",
414 DBUSMENU_TYPE_SERVER,425 G_TYPE_OBJECT,
415 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));426 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
416 /**427 /**
417 * AppIndicator:title:428 * AppIndicator:title:
@@ -429,6 +440,34 @@
429 NULL,440 NULL,
430 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));441 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
431442
443 /**
444 * AppIndicator:menu-model:
445 *
446 * The built menu model. This is only used for testing and should
447 * not be considered stable.
448 */
449 g_object_class_install_property(object_class,
450 PROP_MENU_MODEL,
451 g_param_spec_object (PROP_MENU_MODEL_S,
452 "Internal Menu Model",
453 "TESTING ONLY: Property to get the menu model",
454 G_TYPE_MENU_MODEL,
455 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
456
457 /**
458 * AppIndicator:action-groups:
459 *
460 * The built action group. This is only used for testing and should
461 * not be considered stable.
462 */
463 g_object_class_install_property(object_class,
464 PROP_ACTION_GROUPS,
465 g_param_spec_boxed (PROP_ACTION_GROUPS_S,
466 "Internal Action Group",
467 "TESTING ONLY: Property to get the action group",
468 G_TYPE_ARRAY,
469 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
470
432 /* Signals */471 /* Signals */
433472
434 /**473 /**
@@ -479,7 +518,7 @@
479 * AppIndicator::new-label:518 * AppIndicator::new-label:
480 * @arg0: The #AppIndicator object519 * @arg0: The #AppIndicator object
481 * @arg1: The string for the label520 * @arg1: The string for the label
482 * @arg1: The string for the guide521 * @arg2: The string for the guide
483 *522 *
484 * Emitted when either #AppIndicator:label or #AppIndicator:label-guide are523 * Emitted when either #AppIndicator:label or #AppIndicator:label-guide are
485 * changed.524 * changed.
@@ -591,7 +630,7 @@
591 priv->attention_icon_name = NULL;630 priv->attention_icon_name = NULL;
592 priv->icon_theme_path = NULL;631 priv->icon_theme_path = NULL;
593 priv->menu = NULL;632 priv->menu = NULL;
594 priv->menuservice = NULL;633 priv->menu_shell_path = NULL;
595 priv->ordering_index = 0;634 priv->ordering_index = 0;
596 priv->title = NULL;635 priv->title = NULL;
597 priv->label = NULL;636 priv->label = NULL;
@@ -611,6 +650,9 @@
611 priv->sec_activate_target = NULL;650 priv->sec_activate_target = NULL;
612 priv->sec_activate_enabled = FALSE;651 priv->sec_activate_enabled = FALSE;
613652
653 priv->menu_groups = g_array_new(FALSE /* zero term */, FALSE /* clear */, sizeof(ActionInfo));
654 g_array_set_clear_func(priv->menu_groups, action_info_clear);
655
614 self->priv = priv;656 self->priv = priv;
615657
616 /* Start getting the session bus */658 /* Start getting the session bus */
@@ -663,8 +705,12 @@
663 priv->menu = NULL;705 priv->menu = NULL;
664 }706 }
665707
666 if (priv->menuservice != NULL) {708 unexport_menu(self);
667 g_object_unref (priv->menuservice);709
710 g_clear_object(&priv->menu_model);
711
712 if (priv->menu_groups->len > 0) {
713 g_array_remove_range(priv->menu_groups, 0, priv->menu_groups->len);
668 }714 }
669715
670 if (priv->watcher_proxy != NULL) {716 if (priv->watcher_proxy != NULL) {
@@ -765,10 +811,37 @@
765 priv->path = NULL;811 priv->path = NULL;
766 }812 }
767813
814 g_clear_pointer(&priv->menu_shell_path, g_free);
815
816 if (priv->menu_groups != NULL) {
817 g_array_free(priv->menu_groups, TRUE /* destroy segment */);
818 priv->menu_groups = NULL;
819 }
820
768 G_OBJECT_CLASS (app_indicator_parent_class)->finalize (object);821 G_OBJECT_CLASS (app_indicator_parent_class)->finalize (object);
769 return;822 return;
770}823}
771824
825/* Cleans up an action info struct */
826static void
827action_info_clear (gpointer datain)
828{
829 ActionInfo * ainfo = (ActionInfo *)datain;
830
831 g_clear_pointer(&ainfo->prefix, g_free);
832 g_clear_pointer(&ainfo->path, g_free);
833 g_clear_object(&ainfo->group);
834
835 if (ainfo->export != 0) {
836 g_dbus_connection_unexport_action_group(ainfo->bus, ainfo->export);
837 ainfo->export = 0;
838 }
839
840 g_clear_object(&ainfo->bus);
841
842 return;
843}
844
772#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))845#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))
773846
774/* Set some properties */847/* Set some properties */
@@ -926,10 +999,28 @@
926 break;999 break;
9271000
928 case PROP_DBUS_MENU_SERVER:1001 case PROP_DBUS_MENU_SERVER:
929 g_clear_object (&priv->menuservice);1002 g_warning("DBus Menu Server is a testing parameter. Why are you using it? Please stop.");
930 priv->menuservice = DBUSMENU_SERVER (g_value_dup_object(value));1003 break;
931 break;1004
9321005 case PROP_MENU_MODEL:
1006 unexport_menu(self);
1007
1008 g_clear_object(&priv->menu_model);
1009 priv->menu_model = g_value_dup_object(value);
1010
1011 export_me_maybe(self);
1012 break;
1013 case PROP_ACTION_GROUPS:
1014 if (priv->menu_groups != NULL) {
1015 g_array_free(priv->menu_groups, TRUE /* destroy segment */);
1016 priv->menu_groups = NULL;
1017 }
1018
1019 priv->menu_groups = g_value_get_boxed(value);
1020 g_array_ref(priv->menu_groups);
1021
1022 export_me_maybe(self);
1023 break;
933 default:1024 default:
934 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);1025 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
935 break;1026 break;
@@ -1009,13 +1100,22 @@
1009 break;1100 break;
10101101
1011 case PROP_DBUS_MENU_SERVER:1102 case PROP_DBUS_MENU_SERVER:
1012 g_value_set_object(value, priv->menuservice);1103 g_warning("DBus Menu Server is a testing parameter. Why are you using it? Please stop.");
1104 g_value_set_object(value, NULL);
1013 break;1105 break;
10141106
1015 case PROP_TITLE:1107 case PROP_TITLE:
1016 g_value_set_string(value, priv->title);1108 g_value_set_string(value, priv->title);
1017 break;1109 break;
10181110
1111 case PROP_MENU_MODEL:
1112 g_value_set_object(value, priv->menu_model);
1113 break;
1114
1115 case PROP_ACTION_GROUPS:
1116 g_value_set_boxed(value, priv->menu_groups);
1117 break;
1118
1019 default:1119 default:
1020 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);1120 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1021 break;1121 break;
@@ -1138,16 +1238,7 @@
1138 } else if (g_strcmp0(property, "IconThemePath") == 0) {1238 } else if (g_strcmp0(property, "IconThemePath") == 0) {
1139 return g_variant_new_string(priv->icon_theme_path ? priv->icon_theme_path : "");1239 return g_variant_new_string(priv->icon_theme_path ? priv->icon_theme_path : "");
1140 } else if (g_strcmp0(property, "Menu") == 0) {1240 } else if (g_strcmp0(property, "Menu") == 0) {
1141 if (priv->menuservice != NULL) {1241 return g_variant_new("o", "/");
1142 GValue strval = { 0 };
1143 g_value_init(&strval, G_TYPE_STRING);
1144 g_object_get_property (G_OBJECT (priv->menuservice), DBUSMENU_SERVER_PROP_DBUS_OBJECT, &strval);
1145 GVariant * var = g_variant_new("o", g_value_get_string(&strval));
1146 g_value_unset(&strval);
1147 return var;
1148 } else {
1149 return g_variant_new("o", "/");
1150 }
1151 } else if (g_strcmp0(property, "XAyatanaLabel") == 0) {1242 } else if (g_strcmp0(property, "XAyatanaLabel") == 0) {
1152 return g_variant_new_string(priv->label ? priv->label : "");1243 return g_variant_new_string(priv->label ? priv->label : "");
1153 } else if (g_strcmp0(property, "XAyatanaLabelGuide") == 0) {1244 } else if (g_strcmp0(property, "XAyatanaLabelGuide") == 0) {
@@ -1158,6 +1249,31 @@
1158 return g_variant_new_string(priv->accessible_desc ? priv->accessible_desc : "");1249 return g_variant_new_string(priv->accessible_desc ? priv->accessible_desc : "");
1159 } else if (g_strcmp0(property, "AttentionAccessibleDesc") == 0) {1250 } else if (g_strcmp0(property, "AttentionAccessibleDesc") == 0) {
1160 return g_variant_new_string(priv->att_accessible_desc ? priv->att_accessible_desc : "");1251 return g_variant_new_string(priv->att_accessible_desc ? priv->att_accessible_desc : "");
1252 } else if (g_strcmp0(property, "XCanonicalMenuModel") == 0) {
1253 if (priv->menu_shell_path != NULL) {
1254 return g_variant_new_object_path(priv->menu_shell_path);
1255 } else {
1256 return g_variant_new_object_path("/");
1257 }
1258 } else if (g_strcmp0(property, "XCanonicalActionGroups") == 0) {
1259 if (priv->menu_groups->len != 0) {
1260 GVariantBuilder array;
1261 g_variant_builder_init(&array, G_VARIANT_TYPE_ARRAY);
1262
1263 int i;
1264 for (i = 0; i < priv->menu_groups->len; i++) {
1265 ActionInfo * ainfo = &g_array_index(priv->menu_groups, ActionInfo, i);
1266
1267 g_variant_builder_open(&array, G_VARIANT_TYPE_TUPLE);
1268 g_variant_builder_add_value(&array, g_variant_new_string(ainfo->prefix));
1269 g_variant_builder_add_value(&array, g_variant_new_object_path(ainfo->path));
1270 g_variant_builder_close(&array);
1271 }
1272
1273 return g_variant_builder_end(&array);
1274 } else {
1275 return g_variant_new_array(G_VARIANT_TYPE("(so)"), NULL, 0);
1276 }
1161 }1277 }
11621278
1163 *error = g_error_new(0, 0, "Unknown property: %s", property);1279 *error = g_error_new(0, 0, "Unknown property: %s", property);
@@ -1261,6 +1377,8 @@
1261 }1377 }
1262 }1378 }
12631379
1380 export_me_maybe(self);
1381
1264 /* NOTE: It's really important the order here. We make sure to *publish*1382 /* NOTE: It's really important the order here. We make sure to *publish*
1265 the object on the bus and *then* get the proxy. The reason is that we1383 the object on the bus and *then* get the proxy. The reason is that we
1266 want to ensure all the filters are setup before talking to the watcher1384 want to ensure all the filters are setup before talking to the watcher
@@ -1746,6 +1864,79 @@
1746 self->priv->sec_activate_enabled = widget_is_menu_child(self, menuitem);1864 self->priv->sec_activate_enabled = widget_is_menu_child(self, menuitem);
1747}1865}
17481866
1867/* Unexport the menu, doesn't unref objects */
1868static void
1869unexport_menu (AppIndicator *self)
1870{
1871 AppIndicatorPrivate *priv = self->priv;
1872
1873 if (priv->connection == NULL) {
1874 return;
1875 }
1876
1877 if (priv->menu_model_export != 0) {
1878 g_dbus_connection_unexport_menu_model(priv->connection, priv->menu_model_export);
1879 priv->menu_model_export = 0;
1880 }
1881
1882 if (priv->menu_groups->len > 0) {
1883 g_array_remove_range(priv->menu_groups, 0, priv->menu_groups->len);
1884 }
1885
1886 g_clear_pointer(&priv->menu_shell_path, g_free);
1887
1888 return;
1889}
1890
1891/* We just met, and I know this is crazy, but export me maybe? */
1892/* Export the menu if we've got everything we need */
1893static void
1894export_me_maybe (AppIndicator *self)
1895{
1896 AppIndicatorPrivate *priv = self->priv;
1897
1898 if (priv->connection == NULL) {
1899 return;
1900 }
1901
1902 if (priv->menu_model == NULL) {
1903 return;
1904 }
1905
1906 if (priv->menu_groups->len == 0) {
1907 return;
1908 }
1909
1910 if (priv->menu_model_export != 0) {
1911 return;
1912 }
1913
1914 GError * error = NULL;
1915 int i;
1916 for (i = 0; i < priv->menu_groups->len; i++) {
1917 ActionInfo * ainfo = &g_array_index(priv->menu_groups, ActionInfo, i);
1918
1919 ainfo->bus = g_object_ref(priv->connection);
1920
1921 ainfo->export = g_dbus_connection_export_action_group(ainfo->bus, ainfo->path, ainfo->group, &error);
1922
1923 if (error != NULL) {
1924 g_warning("Unable to export action group as '%s': %s", ainfo->path, error->message);
1925 g_error_free(error);
1926 error = NULL;
1927 }
1928 }
1929
1930 priv->menu_model_export = g_dbus_connection_export_menu_model(priv->connection, priv->menu_shell_path, priv->menu_model, NULL);
1931
1932 if (error != NULL) {
1933 g_warning("Unable to export menu model as '%s': %s", priv->menu_shell_path, error->message);
1934 g_error_free(error);
1935 error = NULL;
1936 }
1937
1938 return;
1939}
17491940
1750/* ************************* */1941/* ************************* */
1751/* Public Functions */1942/* Public Functions */
@@ -2072,25 +2263,26 @@
2072setup_dbusmenu (AppIndicator *self)2263setup_dbusmenu (AppIndicator *self)
2073{2264{
2074 AppIndicatorPrivate *priv;2265 AppIndicatorPrivate *priv;
2075 DbusmenuMenuitem *root = NULL;
2076
2077 priv = self->priv;2266 priv = self->priv;
20782267
2268 unexport_menu(self);
2269
2270 g_clear_object(&priv->menu_model);
2271
2079 if (priv->menu) {2272 if (priv->menu) {
2080 root = dbusmenu_gtk_parse_menu_structure(priv->menu);2273 ActionInfo ainfo;
2081 }2274
20822275 priv->menu_model = G_MENU_MODEL(unity_gtk_menu_shell_new(GTK_MENU_SHELL(priv->menu)));
2083 if (priv->menuservice == NULL) {2276 priv->menu_shell_path = g_strdup_printf(DEFAULT_ITEM_PATH "/%s/Menu", priv->clean_id);
2084 gchar * path = g_strdup_printf(DEFAULT_ITEM_PATH "/%s/Menu", priv->clean_id);2277
2085 priv->menuservice = dbusmenu_server_new (path);2278 ainfo.group = G_ACTION_GROUP(unity_gtk_action_group_new(NULL));
2086 g_free(path);2279 ainfo.prefix = g_strdup("unity");
2087 }2280 ainfo.path = g_strdup(priv->menu_shell_path);
20882281 g_array_append_val(priv->menu_groups, ainfo);
2089 dbusmenu_server_set_root (priv->menuservice, root);2282
20902283 unity_gtk_action_group_connect_shell(UNITY_GTK_ACTION_GROUP(ainfo.group), UNITY_GTK_MENU_SHELL(priv->menu_model));
2091 /* Drop our local ref as set_root should get it's own. */2284
2092 if (root != NULL) {2285 export_me_maybe(self);
2093 g_object_unref(root);
2094 }2286 }
20952287
2096 return;2288 return;
@@ -2463,14 +2655,13 @@
2463 return GTK_WIDGET(self->priv->sec_activate_target);2655 return GTK_WIDGET(self->priv->sec_activate_target);
2464}2656}
24652657
2466#define APP_INDICATOR_SHORTY_NICK "app-indicator-shorty-nick"
2467
2468/* Callback when an item from the desktop shortcuts gets2658/* Callback when an item from the desktop shortcuts gets
2469 called. */2659 called. */
2470static void2660static void
2471shorty_activated_cb (DbusmenuMenuitem * mi, guint timestamp, gpointer user_data)2661shorty_activated_cb (GSimpleAction * action, GVariant * param, gpointer user_data)
2472{2662{
2473 gchar * nick = g_object_get_data(G_OBJECT(mi), APP_INDICATOR_SHORTY_NICK);2663 gchar * nick = NULL;
2664 g_object_get(G_OBJECT(action), "name", &nick, NULL);
2474 g_return_if_fail(nick != NULL);2665 g_return_if_fail(nick != NULL);
24752666
2476 g_return_if_fail(IS_APP_INDICATOR(user_data));2667 g_return_if_fail(IS_APP_INDICATOR(user_data));
@@ -2500,45 +2691,53 @@
2500 AppIndicatorPrivate *priv = self->priv;2691 AppIndicatorPrivate *priv = self->priv;
25012692
2502 /* Build a new shortcuts object */2693 /* Build a new shortcuts object */
2503 if (priv->shorties != NULL) {2694 g_clear_object(&priv->shorties);
2504 g_object_unref(priv->shorties);
2505 priv->shorties = NULL;
2506 }
2507 priv->shorties = indicator_desktop_shortcuts_new(desktop_file, desktop_profile);2695 priv->shorties = indicator_desktop_shortcuts_new(desktop_file, desktop_profile);
2508 g_return_if_fail(priv->shorties != NULL);2696 g_return_if_fail(priv->shorties != NULL);
25092697
2698 /* Remove the exported menu */
2699 unexport_menu(self);
2700
2701 g_clear_object(&priv->menu_model);
2702
2703 /* Get the 'nicks' */
2510 const gchar ** nicks = indicator_desktop_shortcuts_get_nicks(priv->shorties);2704 const gchar ** nicks = indicator_desktop_shortcuts_get_nicks(priv->shorties);
2705
2706 if (nicks[0] == NULL) {
2707 g_warning("Desktop file '%s' doesn't contain any usable actions", desktop_file);
2708 return;
2709 }
2710
2711 /* Build new menus and action groups */
2712 GMenu * menu = g_menu_new();
2713 priv->menu_model = G_MENU_MODEL(menu);
2714 priv->menu_shell_path = g_strdup_printf(DEFAULT_ITEM_PATH "/%s/Menu", priv->clean_id);
2715
2716 ActionInfo ainfo;
2717 GSimpleActionGroup * actions = g_simple_action_group_new();
2718 ainfo.group = G_ACTION_GROUP(actions);
2719 ainfo.prefix = g_strdup("");
2720 ainfo.path = g_strdup(priv->menu_shell_path);
2721 g_array_append_val(priv->menu_groups, ainfo);
2722
2511 int nick_num;2723 int nick_num;
2512
2513 /* Place the items on a dbusmenu */
2514 DbusmenuMenuitem * root = dbusmenu_menuitem_new();
2515
2516 for (nick_num = 0; nicks[nick_num] != NULL; nick_num++) {2724 for (nick_num = 0; nicks[nick_num] != NULL; nick_num++) {
2517 DbusmenuMenuitem * item = dbusmenu_menuitem_new();2725 GSimpleAction * action = g_simple_action_new(nicks[nick_num], NULL);
2518 g_object_set_data(G_OBJECT(item), APP_INDICATOR_SHORTY_NICK, (gpointer)nicks[nick_num]);2726 g_signal_connect(action, "activate", G_CALLBACK(shorty_activated_cb), self);
25192727
2520 gchar * name = indicator_desktop_shortcuts_nick_get_name(priv->shorties, nicks[nick_num]);2728 gchar * name = indicator_desktop_shortcuts_nick_get_name(priv->shorties, nicks[nick_num]);
2521 dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, name);2729 GMenuItem * item = g_menu_item_new(name, nicks[nick_num]);
2522 g_free(name);2730 g_free(name);
25232731
2524 g_signal_connect(G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(shorty_activated_cb), self);2732 g_simple_action_group_insert(actions, G_ACTION(action));
25252733 g_menu_append_item(menu, item);
2526 dbusmenu_menuitem_child_append(root, item);2734
2527 }2735 g_object_unref(action);
25282736 g_object_unref(item);
2529 /* Swap it if needed */2737 }
2530 if (priv->menuservice == NULL) {2738
2531 gchar * path = g_strdup_printf(DEFAULT_ITEM_PATH "/%s/Menu", priv->clean_id);2739 /* Export the menu and action group */
2532 priv->menuservice = dbusmenu_server_new (path);2740 export_me_maybe(self);
2533 g_free(path);
2534 }
2535
2536 dbusmenu_server_set_root (priv->menuservice, root);
2537
2538 if (priv->menu != NULL) {
2539 g_object_unref(G_OBJECT(priv->menu));
2540 priv->menu = NULL;
2541 }
25422741
2543 return;2742 return;
2544}2743}
25452744
=== modified file 'src/app-indicator.h'
--- src/app-indicator.h 2012-02-03 20:37:56 +0000
+++ src/app-indicator.h 2013-06-09 14:13:32 +0000
@@ -238,10 +238,6 @@
238 * unique status in the panel for an application. In general, applications238 * unique status in the panel for an application. In general, applications
239 * should try to fit in the other indicators that are available on the239 * should try to fit in the other indicators that are available on the
240 * panel before using this. But, sometimes it is necissary.240 * panel before using this. But, sometimes it is necissary.
241 *
242 * Private fields
243 * @parent: Parent object.
244 * @priv: Internal data.
245 */241 */
246struct _AppIndicator {242struct _AppIndicator {
247 GObject parent;243 GObject parent;
248244
=== modified file 'src/notification-item.xml'
--- src/notification-item.xml 2012-02-03 20:37:56 +0000
+++ src/notification-item.xml 2013-06-09 14:13:32 +0000
@@ -18,6 +18,8 @@
18 <property name="XAyatanaLabel" type="s" access="read" />18 <property name="XAyatanaLabel" type="s" access="read" />
19 <property name="XAyatanaLabelGuide" type="s" access="read" />19 <property name="XAyatanaLabelGuide" type="s" access="read" />
20 <property name="XAyatanaOrderingIndex" type="u" access="read" />20 <property name="XAyatanaOrderingIndex" type="u" access="read" />
21 <property name="XCanonicalMenuModel" type="o" access="read" />
22 <property name="XCanonicalActionGroups" type="a(so)" access="read" />
2123
22<!-- Methods -->24<!-- Methods -->
23 <method name="Scroll">25 <method name="Scroll">
2426
=== modified file 'tests/test-libappindicator.c'
--- tests/test-libappindicator.c 2013-01-10 22:18:55 +0000
+++ tests/test-libappindicator.c 2013-06-09 14:13:32 +0000
@@ -22,12 +22,10 @@
2222
23#include <glib.h>23#include <glib.h>
24#include <glib-object.h>24#include <glib-object.h>
25#include <gio/gio.h>
2526
26#include <app-indicator.h>27#include <app-indicator.h>
2728
28#include <libdbusmenu-glib/menuitem.h>
29#include <libdbusmenu-glib/server.h>
30
31static gboolean29static gboolean
32allow_warnings (const gchar *log_domain, GLogLevelFlags log_level,30allow_warnings (const gchar *log_domain, GLogLevelFlags log_level,
33 const gchar *message, gpointer user_data)31 const gchar *message, gpointer user_data)
@@ -270,26 +268,26 @@
270268
271 g_assert(app_indicator_get_menu(ci) != NULL);269 g_assert(app_indicator_get_menu(ci) != NULL);
272270
273 GValue serverval = {0};271 GValue modelval = {0};
274 g_value_init(&serverval, DBUSMENU_TYPE_SERVER);272 g_value_init(&modelval, G_TYPE_MENU_MODEL);
275 g_object_get_property(G_OBJECT(ci), "dbus-menu-server", &serverval);273 g_object_get_property(G_OBJECT(ci), "menu-model", &modelval);
276274
277 DbusmenuServer * server = DBUSMENU_SERVER(g_value_get_object(&serverval));275 GMenuModel * model = G_MENU_MODEL(g_value_get_object(&modelval));
278 g_assert(server != NULL);276 g_assert(model != NULL);
279277
280 GValue rootval = {0};278 g_assert_cmpint(g_menu_model_get_n_items(model), ==, 1);
281 g_value_init(&rootval, DBUSMENU_TYPE_MENUITEM);279
282 g_object_get_property(G_OBJECT(server), DBUSMENU_SERVER_PROP_ROOT_NODE, &rootval);280 GMenuModel * section = g_menu_model_get_item_link(model, 0, G_MENU_LINK_SECTION);
283 DbusmenuMenuitem * root = DBUSMENU_MENUITEM(g_value_get_object(&rootval));281 g_assert(section != NULL);
284 g_assert(root != NULL);282
285283 g_assert_cmpint(g_menu_model_get_n_items(section), ==, 1);
286 GList * children = dbusmenu_menuitem_get_children(root);284
287 g_assert(children != NULL);285 GVariant * label = g_menu_model_get_item_attribute_value(section, 0, G_MENU_ATTRIBUTE_LABEL, G_VARIANT_TYPE_STRING);
288 g_assert(g_list_length(children) == 1);
289
290 const gchar * label = dbusmenu_menuitem_property_get(DBUSMENU_MENUITEM(children->data), DBUSMENU_MENUITEM_PROP_LABEL);
291 g_assert(label != NULL);286 g_assert(label != NULL);
292 g_assert(g_strcmp0(label, "Test Label") == 0);287 g_assert(g_strcmp0("Test Label", g_variant_get_string(label, NULL)) == 0);
288
289 g_variant_unref(label);
290 g_object_unref(model);
293291
294 /* Interesting, eh? We need this because we send out events on the bus292 /* Interesting, eh? We need this because we send out events on the bus
295 but they don't come back until the idle is run. So we need those293 but they don't come back until the idle is run. So we need those
@@ -388,24 +386,15 @@
388386
389 app_indicator_build_menu_from_desktop(ci, SRCDIR "/test-libappindicator.desktop", "Test Program");387 app_indicator_build_menu_from_desktop(ci, SRCDIR "/test-libappindicator.desktop", "Test Program");
390388
391 GValue serverval = {0};389 GValue modelval = {0};
392 g_value_init(&serverval, DBUSMENU_TYPE_SERVER);390 g_value_init(&modelval, G_TYPE_MENU_MODEL);
393 g_object_get_property(G_OBJECT(ci), "dbus-menu-server", &serverval);391 g_object_get_property(G_OBJECT(ci), "menu-model", &modelval);
394392
395 DbusmenuServer * server = DBUSMENU_SERVER(g_value_get_object(&serverval));393 GMenuModel * model = G_MENU_MODEL(g_value_get_object(&modelval));
396 g_assert(server != NULL);394 g_assert(model != NULL);
397395
398 GValue rootval = {0};396 g_assert(g_menu_model_get_n_items(model) == 3);
399 g_value_init(&rootval, DBUSMENU_TYPE_MENUITEM);397 g_object_unref(model);
400 g_object_get_property(G_OBJECT(server), DBUSMENU_SERVER_PROP_ROOT_NODE, &rootval);
401 DbusmenuMenuitem * root = DBUSMENU_MENUITEM(g_value_get_object(&rootval));
402 g_assert(root != NULL);
403
404 GList * children = dbusmenu_menuitem_get_children(root);
405 g_assert(children != NULL);
406 g_assert(g_list_length(children) == 3);
407
408
409398
410 g_object_unref(G_OBJECT(ci));399 g_object_unref(G_OBJECT(ci));
411 return;400 return;
@@ -426,21 +415,12 @@
426415
427 app_indicator_build_menu_from_desktop(ci, SRCDIR "/test-libappindicator.desktop", "Not Test Program");416 app_indicator_build_menu_from_desktop(ci, SRCDIR "/test-libappindicator.desktop", "Not Test Program");
428417
429 GValue serverval = {0};418 GValue modelval = {0};
430 g_value_init(&serverval, DBUSMENU_TYPE_SERVER);419 g_value_init(&modelval, G_TYPE_MENU_MODEL);
431 g_object_get_property(G_OBJECT(ci), "dbus-menu-server", &serverval);420 g_object_get_property(G_OBJECT(ci), "menu-model", &modelval);
432421
433 DbusmenuServer * server = DBUSMENU_SERVER(g_value_get_object(&serverval));422 GMenuModel * model = G_MENU_MODEL(g_value_get_object(&modelval));
434 g_assert(server != NULL);423 g_assert(model == NULL);
435
436 GValue rootval = {0};
437 g_value_init(&rootval, DBUSMENU_TYPE_MENUITEM);
438 g_object_get_property(G_OBJECT(server), DBUSMENU_SERVER_PROP_ROOT_NODE, &rootval);
439 DbusmenuMenuitem * root = DBUSMENU_MENUITEM(g_value_get_object(&rootval));
440 g_assert(root != NULL);
441
442 GList * children = dbusmenu_menuitem_get_children(root);
443 g_assert(g_list_length(children) == 0);
444424
445 g_object_unref(G_OBJECT(ci));425 g_object_unref(G_OBJECT(ci));
446 return;426 return;
447427
=== modified file 'tests/test-simple-app.c'
--- tests/test-simple-app.c 2013-01-16 19:53:52 +0000
+++ tests/test-simple-app.c 2013-06-09 14:13:32 +0000
@@ -20,10 +20,8 @@
20*/20*/
2121
2222
23#include <dbus/dbus-glib.h>
24#include <dbus/dbus-glib-lowlevel.h>
25#include <glib.h>23#include <glib.h>
26#include <libdbusmenu-glib/server.h>24#include <gio/gio.h>
27#include <app-indicator.h>25#include <app-indicator.h>
2826
29static GMainLoop * mainloop = NULL;27static GMainLoop * mainloop = NULL;
@@ -31,15 +29,19 @@
31int29int
32main (int argc, char ** argv)30main (int argc, char ** argv)
33{31{
34 DbusmenuServer * dms = dbusmenu_server_new("/menu");32 GMenu * menu = g_menu_new();
35 DbusmenuMenuitem * dmi = dbusmenu_menuitem_new();33 g_menu_append(menu, "Bob", "action");
36 dbusmenu_menuitem_property_set(dmi, "label", "Bob");34
35 GSimpleActionGroup * actions = g_simple_action_group_new();
36 GSimpleAction * action = g_simple_action_new("action", NULL);
37 g_simple_action_group_insert(actions, G_ACTION(action));
3738
38 AppIndicator * ci = APP_INDICATOR(g_object_new(APP_INDICATOR_TYPE, 39 AppIndicator * ci = APP_INDICATOR(g_object_new(APP_INDICATOR_TYPE,
39 "id", "test-application",40 "id", "test-application",
40 "status-enum", APP_INDICATOR_STATUS_ACTIVE,41 "status-enum", APP_INDICATOR_STATUS_ACTIVE,
41 "icon-name", "system-shutdown",42 "icon-name", "system-shutdown",
42 "menu-object", dms,43 "menu-model", menu,
44 "action-group", actions,
43 NULL));45 NULL));
4446
45 mainloop = g_main_loop_new(NULL, FALSE);47 mainloop = g_main_loop_new(NULL, FALSE);

Subscribers

People subscribed via source and target branches