23
23
#include <stdlib.h>
25
#include <dbus/dbus.h>
26
#include <dbus/dbus-glib.h>
27
#include <dbus/dbus-glib-lowlevel.h>
28
#include <dbus/dbus-glib-bindings.h>
26
30
#include <gtk/gtk.h>
27
31
#include <gdk/gdkx.h>
30
#include <libdbusmenu-gtk/menuitem.h>
31
#include <libdbusmenu-gtk/parser.h>
33
33
#include <libdbusmenu-glib/menuitem.h>
34
34
#include <libdbusmenu-glib/server.h>
36
36
#include "bridge.h"
37
#include "gen-application-menu-registrar.xml.h"
37
#include "application-menu-registrar-client.h"
39
#define APP_MENU_DBUS_NAME "com.canonical.AppMenu.Registrar"
40
#define APP_MENU_DBUS_OBJECT "/com/canonical/AppMenu/Registrar"
41
#define APP_MENU_INTERFACE "com.canonical.AppMenu.Registrar"
39
#define APP_MENU_DBUS_NAME "org.ayatana.WindowMenu.Registrar"
40
#define APP_MENU_DBUS_OBJECT "/org/ayatana/WindowMenu/Registrar"
41
#define APP_MENU_INTERFACE "org.ayatana.WindowMenu.Registrar"
42
42
#define APP_MENU_PATH "/this/is/a/long/object/path"
44
typedef struct _AppWindowContext AppWindowContext;
46
44
static void app_menu_bridge_insert (UbuntuMenuProxy *proxy,
50
48
static gboolean app_menu_bridge_show_local (UbuntuMenuProxy *proxy);
51
static void toplevel_mapped (GtkWidget *widget,
53
static void mnemonic_shown_cb (GtkWidget *widget,
55
AppWindowContext *context);
56
static void toplevel_notify_parent_cb (GtkWidget *widget,
58
UbuntuMenuProxy *proxy);
59
static void menubar_notify_parent_cb (GtkWidget *widget,
61
UbuntuMenuProxy *proxy);
62
static void rebuild_window_items (AppMenuBridge *bridge,
64
static void rebuild (AppMenuBridge *bridge,
66
static void app_menu_bridge_proxy_vanished (AppMenuBridge *bridge);
67
static void app_menu_bridge_proxy_appeared (AppMenuBridge *bridge);
68
static void appmenuproxy_created_cb (GObject * object,
72
struct _AppWindowContext
50
struct _AppMenuBridgePrivate
52
GHashTable *items; /* <GtkWidget *, DbusmenuMenuitem *> */
75
54
DbusmenuServer *server;
78
AppMenuBridge *bridge;
82
struct _AppMenuBridgePrivate
86
GDBusProxy *appmenuproxy;
90
typedef struct _RecurseContext
92
AppMenuBridge *bridge;
93
AppWindowContext *context;
97
DbusmenuMenuitem *stack[30];
57
static DBusGProxy *dbusproxy = NULL;
58
static gboolean registered = FALSE;
100
60
G_DEFINE_DYNAMIC_TYPE(AppMenuBridge, app_menu_bridge, UBUNTU_TYPE_MENU_PROXY)
102
static GHashTable *rebuild_ids = NULL;
103
static GDBusNodeInfo * registrar_node_info = NULL;
104
static GDBusInterfaceInfo * registrar_interface_info = NULL;
107
activate_menu (AppMenuBridge *bridge,
111
DbusmenuMenuitem *mi = dbusmenu_gtk_parse_get_cached_item (widget);
115
dbusmenu_menuitem_show_to_user (mi, 0);
122
63
app_menu_bridge_init (AppMenuBridge *bridge)
124
65
bridge->priv = G_TYPE_INSTANCE_GET_PRIVATE (bridge, APP_MENU_TYPE_BRIDGE, AppMenuBridgePrivate);
126
bridge->priv->windows = NULL;
128
bridge->priv->appmenuproxy = NULL;
129
g_dbus_proxy_new_for_bus(G_BUS_TYPE_SESSION,
130
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
131
registrar_interface_info,
133
APP_MENU_DBUS_OBJECT,
135
NULL, /* TODO: cancelable */
136
appmenuproxy_created_cb,
139
bridge->priv->online = FALSE;
141
g_signal_connect (bridge,
143
G_CALLBACK (activate_menu),
150
context_dispose (AppWindowContext *context)
152
if (context->cancel != NULL)
154
g_cancellable_cancel (context->cancel);
155
g_object_unref (context->cancel);
156
context->cancel = NULL;
159
if (context->server != NULL)
161
g_object_unref (context->server);
162
context->server = NULL;
165
if (context->window != NULL)
167
g_signal_handlers_disconnect_by_func(context->window, G_CALLBACK(mnemonic_shown_cb), context);
168
g_object_remove_weak_pointer(G_OBJECT(context->window), (gpointer *)&(context->window));
169
context->window = NULL;
174
context_free (AppWindowContext *context)
176
context_dispose (context);
178
if (context->path != NULL)
180
g_free (context->path);
181
context->path = NULL;
188
app_menu_bridge_dispose (GObject *object)
190
AppMenuBridge *bridge = APP_MENU_BRIDGE (object);
192
g_list_foreach (bridge->priv->windows, (GFunc)context_dispose, NULL);
194
if (bridge->priv->appmenuproxy)
196
g_object_unref (bridge->priv->appmenuproxy);
197
bridge->priv->appmenuproxy = NULL;
67
bridge->priv->items = g_hash_table_new (g_direct_hash, g_direct_equal);
68
bridge->priv->items = g_hash_table_new (g_direct_hash, g_direct_equal);
70
bridge->priv->server = dbusmenu_server_new (APP_MENU_PATH);
202
74
app_menu_bridge_finalize (GObject *object)
204
AppMenuBridge *bridge = APP_MENU_BRIDGE (object);
206
g_list_foreach (bridge->priv->windows, (GFunc)context_free, NULL);
207
g_list_free (bridge->priv->windows);
208
bridge->priv->windows = NULL;
210
G_OBJECT_CLASS (app_menu_bridge_parent_class)->finalize (object);
214
toplevel_unmapped (GtkWidget *widget,
217
AppWindowContext *context = (AppWindowContext *)user_data;
219
g_signal_handlers_disconnect_by_func(widget,
220
G_CALLBACK(toplevel_unmapped),
225
context->bridge->priv->windows = g_list_remove (context->bridge->priv->windows, context);
226
context_free (context);
76
g_hash_table_destroy (APP_MENU_BRIDGE (object)->priv->items);
276
app_menu_bridge_set_show_local (AppMenuBridge *bridge,
279
const gchar *env = g_getenv ("APPMENU_DISPLAY_BOTH");
281
if (g_strcmp0 (env, "1") == 0)
284
g_object_set (bridge,
290
register_application_window_cb (GObject *object,
294
GError * error = NULL;
295
AppWindowContext *context = (AppWindowContext *)user_data;
297
GVariant * variants = g_dbus_proxy_call_finish(G_DBUS_PROXY(object), res, &error);
299
if (variants != NULL) {
300
/* Only unref variants if we get some. Doing this hear instead of
301
with the error so that it's clear we don't use it. */
302
g_variant_unref(variants);
306
error->domain == G_IO_ERROR && error->code == G_IO_ERROR_CANCELLED)
308
/* If we were cancelled, we've been disposed (and possibly finalized) and
309
shouldn't trust anything in context. This is because cancel callbacks
310
are done in the idle loop for GIO functions. */
315
if (context->cancel != NULL)
317
g_object_unref (context->cancel);
318
context->cancel = NULL;
323
g_warning("Unable to register window with path '%s': %s", context->path, error->message);
326
context->registered = FALSE;
328
if (context->bridge != NULL)
329
app_menu_bridge_set_show_local (context->bridge, TRUE);
334
context->registered = TRUE;
336
if (context->bridge != NULL)
337
app_menu_bridge_set_show_local (context->bridge, FALSE);
341
register_application_windows (AppMenuBridge *bridge)
345
for (tmp = bridge->priv->windows; tmp != NULL; tmp = tmp->next)
347
AppWindowContext *context = tmp->data;
348
GtkWidget *widget = context->window;
350
if (bridge->priv->appmenuproxy == NULL || bridge->priv->online == FALSE)
352
if (context->bridge != NULL)
354
app_menu_bridge_set_show_local (context->bridge, TRUE);
359
if (!context->registered && context->server != NULL &&
360
context->cancel == NULL && GTK_IS_WINDOW (widget) &&
361
bridge->priv->appmenuproxy != NULL)
363
context->cancel = g_cancellable_new ();
364
g_dbus_proxy_call(bridge->priv->appmenuproxy,
366
g_variant_new("(uo)",
367
GDK_WINDOW_XID(gtk_widget_get_window(widget)),
369
G_DBUS_CALL_FLAGS_NONE,
372
register_application_window_cb,
379
unregister_application_windows (AppMenuBridge *bridge)
383
for (tmp = bridge->priv->windows; tmp != NULL; tmp = tmp->next)
385
AppWindowContext *context = tmp->data;
387
context->registered = FALSE;
390
app_menu_bridge_set_show_local (bridge, TRUE);
394
app_menu_bridge_proxy_vanished (AppMenuBridge *bridge)
396
bridge->priv->online = FALSE;
398
unregister_application_windows (bridge);
402
app_menu_bridge_proxy_appeared (AppMenuBridge *bridge)
404
bridge->priv->online = TRUE;
406
register_application_windows (bridge);
409
/* Gets called anytime the name owner changes, this is typically
410
when the indicator crashes or gets removed. */
412
appmenuproxy_owner_changed (GObject * object, GParamSpec * pspec, gpointer user_data)
414
AppMenuBridge * bridge = APP_MENU_BRIDGE(user_data);
415
g_return_if_fail(bridge != NULL);
417
gchar * name = g_dbus_proxy_get_name_owner(bridge->priv->appmenuproxy);
420
app_menu_bridge_proxy_appeared(bridge);
422
app_menu_bridge_proxy_vanished(bridge);
428
/* Callback for the asyncronous creation of the proxy object.
429
If it is created successfully we act like it just appeared, otherwise
430
we error as if it vanished */
432
appmenuproxy_created_cb (GObject * object, GAsyncResult * res, gpointer user_data)
434
GError * error = NULL;
435
GDBusProxy * proxy = NULL;
437
proxy = g_dbus_proxy_new_for_bus_finish(res, &error);
439
g_warning("Unable to create Ubuntu Menu Proxy: %s", error->message);
441
/* No return, we want to still call vanished */
444
AppMenuBridge * bridge = APP_MENU_BRIDGE(user_data);
445
g_return_if_fail(bridge != NULL);
447
bridge->priv->appmenuproxy = proxy;
451
name = g_dbus_proxy_get_name_owner(proxy);
453
g_signal_connect(G_OBJECT(proxy),
454
"notify::g-name-owner",
455
G_CALLBACK(appmenuproxy_owner_changed),
459
/* Note: name will be NULL if proxy was NULL */
462
app_menu_bridge_proxy_appeared(bridge);
464
app_menu_bridge_proxy_vanished(bridge);
470
typedef struct _RebuildData {
471
AppMenuBridge *bridge;
476
do_rebuild (RebuildData *data)
478
if (data->widget != NULL && gtk_widget_is_toplevel (data->widget))
480
rebuild_window_items (data->bridge,
484
if (data->widget != NULL)
486
g_object_remove_weak_pointer (G_OBJECT (data->widget), (gpointer*)&data->widget);
487
g_hash_table_remove (rebuild_ids, data->widget);
496
rebuild (AppMenuBridge *bridge,
501
if (rebuild_ids != NULL)
503
id = GPOINTER_TO_UINT (g_hash_table_lookup (rebuild_ids, toplevel));
507
g_source_remove (id);
508
g_hash_table_remove (rebuild_ids, toplevel);
513
RebuildData *data = g_new0 (RebuildData, 1);
514
data->bridge = bridge;
515
data->widget = toplevel;
517
id = g_timeout_add (100,
518
(GSourceFunc)do_rebuild,
521
g_object_add_weak_pointer (G_OBJECT (data->widget), (gpointer*)&data->widget);
523
if (rebuild_ids == NULL)
525
rebuild_ids = g_hash_table_new (g_direct_hash, g_direct_equal);
528
g_hash_table_insert (rebuild_ids, toplevel, GUINT_TO_POINTER (id));
531
static DbusmenuMenuitem * find_menu_bar (GtkWidget * widget);
534
find_menu_bar_helper (GtkWidget * widget, gpointer data)
536
DbusmenuMenuitem ** mi = (DbusmenuMenuitem **)data;
538
/* We've already found a menu, let's get through the
539
foreach as quickly as possible */
544
*mi = find_menu_bar(widget);
548
static DbusmenuMenuitem *
549
find_menu_bar (GtkWidget * widget)
551
if (GTK_IS_MENU_BAR(widget) || GTK_IS_MENU_ITEM(widget)) {
552
return dbusmenu_gtk_parse_menu_structure(widget);
555
if (GTK_IS_CONTAINER(widget)) {
556
DbusmenuMenuitem * mi = NULL;
558
gtk_container_foreach(GTK_CONTAINER(widget), find_menu_bar_helper, &mi);
566
/* Respond to changing of the mnemonics shown property to say
567
to the appmenu wether we need to have the menus shown on the
568
panel. If there is no auto-mnemonics in this theme we're just
569
not doing this as we can't tell what the user wanted. */
571
mnemonic_shown_cb (GtkWidget *widget,
104
find_menu_label (GtkWidget *widget)
106
GtkWidget *label = NULL;
108
if (GTK_IS_LABEL (widget))
111
if (GTK_IS_CONTAINER (widget))
116
children = gtk_container_get_children (GTK_CONTAINER (widget));
118
for (l = children; l; l = l->next)
120
label = find_menu_label (l->data);
126
g_list_free (children);
133
get_menu_label_text (GtkWidget *menuitem)
135
GtkWidget *label = find_menu_label (menuitem);
138
return gtk_label_get_text (GTK_LABEL (label));
144
item_activated (DbusmenuMenuitem *item, guint timestamp, gpointer user_data)
148
if (user_data != NULL)
150
child = (GtkWidget *)user_data;
152
if (GTK_IS_MENU_ITEM (child))
154
gtk_menu_item_activate (GTK_MENU_ITEM (child));
160
widget_notify_cb (GtkWidget *widget,
164
DbusmenuMenuitem *child = (DbusmenuMenuitem *)data;
166
if (pspec->name == g_intern_static_string ("sensitive"))
168
dbusmenu_menuitem_property_set_bool (child,
169
DBUSMENU_MENUITEM_PROP_ENABLED,
170
gtk_widget_get_sensitive (widget));
172
else if (pspec->name == g_intern_static_string ("label"))
174
dbusmenu_menuitem_property_set (child,
175
DBUSMENU_MENUITEM_PROP_LABEL,
176
gtk_menu_item_get_label (GTK_MENU_ITEM (widget)));
178
else if (pspec->name == g_intern_static_string ("visible"))
180
dbusmenu_menuitem_property_set_bool (child,
181
DBUSMENU_MENUITEM_PROP_VISIBLE,
182
gtk_widget_get_visible (widget));
187
toplevel_realized (GtkWidget *widget,
190
/* Register the toplevel window now that it's been realized. */
191
org_ayatana_WindowMenu_Registrar_register_window (dbusproxy,
192
GDK_WINDOW_XID (gtk_widget_get_window (widget)),
199
toplevel_notify_cb (GtkWidget *widget,
572
200
GParamSpec *pspec,
573
AppWindowContext *context)
575
DbusmenuStatus dstatus = DBUSMENU_STATUS_NORMAL;
576
if (context->window != NULL) {
577
gboolean mshown = gtk_window_get_mnemonics_visible(GTK_WINDOW(context->window));
580
g_object_get(gtk_widget_get_settings(context->window), "gtk-auto-mnemonics", &autom, NULL);
582
if (autom && mshown) {
583
dstatus = DBUSMENU_STATUS_NOTICE;
587
if (context->server != NULL) {
588
/* g_debug("Setting dbusmenu server status to: %d", dstatus); */
589
dbusmenu_server_set_status(context->server, dstatus);
596
rebuild_window_items (AppMenuBridge *bridge,
600
AppWindowContext *context = NULL;
602
/* Disconnect any "map" signal and reconnect, which guarantees that there is
603
at least one and at most one listener */
604
g_signal_handlers_disconnect_by_func(toplevel,
605
G_CALLBACK(toplevel_mapped),
607
g_signal_connect (toplevel, "map",
608
G_CALLBACK (toplevel_mapped),
611
if (!GTK_IS_WINDOW (toplevel))
613
g_signal_connect (G_OBJECT (toplevel),
615
G_CALLBACK (toplevel_notify_parent_cb),
620
else if (g_object_class_find_property (G_OBJECT_GET_CLASS (toplevel),
621
"ubuntu-no-proxy") != NULL)
626
g_object_get (G_OBJECT (toplevel),
627
"ubuntu-no-proxy", &no_proxy,
636
if (!gtk_widget_get_mapped (toplevel))
641
xid = GDK_WINDOW_XID (gtk_widget_get_window (toplevel));
644
gboolean found = FALSE;
646
for (tmp = bridge->priv->windows; tmp != NULL; tmp = tmp->next)
650
if (context && GTK_IS_WIDGET (context->window))
652
XID xid2 = GDK_WINDOW_XID (gtk_widget_get_window (context->window));
664
context = g_new0 (AppWindowContext, 1);
665
context->bridge = bridge;
666
context->cancel = NULL;
667
bridge->priv->windows = g_list_prepend (bridge->priv->windows, context);
672
if (context->window != toplevel)
674
g_signal_handlers_disconnect_by_func (context->window,
675
G_CALLBACK (toplevel_unmapped),
680
if (context->window != toplevel)
682
if (context->window != NULL) {
683
g_object_remove_weak_pointer(G_OBJECT(context->window), (gpointer *)&(context->window));
684
g_signal_handlers_disconnect_by_func(context->window, G_CALLBACK(mnemonic_shown_cb), context);
687
context->window = toplevel;
689
g_object_add_weak_pointer(G_OBJECT(context->window), (gpointer *)&(context->window));
690
g_signal_connect (toplevel,
692
G_CALLBACK (toplevel_unmapped),
697
context->path = g_strdup_printf ("/com/canonical/menu/%X", (guint)xid);
699
if (!context->server) {
700
context->server = dbusmenu_server_new (context->path);
702
GtkTextDirection dir = gtk_widget_get_default_direction();
703
if (dir != GTK_TEXT_DIR_NONE) {
704
dbusmenu_server_set_text_direction(context->server, dir == GTK_TEXT_DIR_LTR ? DBUSMENU_TEXT_DIRECTION_LTR : DBUSMENU_TEXT_DIRECTION_RTL);
708
if (context->window != NULL) {
709
g_signal_connect (G_OBJECT (toplevel),
710
"notify::mnemonics-visible",
711
G_CALLBACK (mnemonic_shown_cb),
715
DbusmenuMenuitem * mi = find_menu_bar(toplevel);
716
dbusmenu_server_set_root(context->server, mi);
718
g_object_unref(G_OBJECT(mi));
721
register_application_windows (bridge);
725
toplevel_mapped (GtkWidget *widget,
728
AppMenuBridge *bridge = APP_MENU_BRIDGE (user_data);
730
if (GTK_IS_WINDOW (widget))
732
rebuild (bridge, widget);
733
//register_application_windows (bridge);
740
toplevel_notify_parent_cb (GtkWidget *widget,
742
UbuntuMenuProxy *proxy)
744
GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
745
AppMenuBridge *bridge = APP_MENU_BRIDGE (proxy);
747
if (gtk_widget_get_parent (widget) == NULL)
750
if (GTK_IS_WINDOW (toplevel))
752
g_signal_handlers_disconnect_by_func (widget,
753
G_CALLBACK (toplevel_notify_parent_cb),
755
rebuild (bridge, toplevel);
759
g_signal_connect (G_OBJECT (toplevel),
761
G_CALLBACK (toplevel_notify_parent_cb),
767
menubar_notify_parent_cb (GtkWidget *widget,
769
UbuntuMenuProxy *proxy)
771
if (gtk_widget_get_parent (widget) == NULL)
772
return; /* TODO: Should clear all entries (find old context and set root to NULL) */
774
/* Rebuild now or when toplevel window appears */
775
toplevel_notify_parent_cb (widget, NULL, proxy);
779
attach_notify_cb (GtkWidget *widget,
781
AppMenuBridge *bridge)
783
if (pspec->name == g_intern_static_string ("attach-widget"))
785
GtkWidget *attach = NULL;
787
g_object_get (widget, "attach-widget", &attach, NULL);
789
rebuild (bridge, attach);
201
UbuntuMenuProxy *proxy)
203
if (pspec->name == g_intern_static_string ("parent"))
205
AppMenuBridge *bridge = APP_MENU_BRIDGE (proxy);
206
DbusmenuMenuitem *root = g_hash_table_lookup (bridge->priv->items, widget);
210
dbusmenu_server_set_root (bridge->priv->server, root);
215
GtkWidget *parent = gtk_widget_get_toplevel (widget);
217
if (!GTK_IS_WINDOW (parent))
219
/* The current toplevel widget is not our final toplevel widget, as it's
220
* not a GtkWindow. Let's defer registration until we have a real toplevel.
222
g_signal_connect (G_OBJECT (parent),
224
G_CALLBACK (toplevel_notify_cb),
231
/* This is the real toplevel window widget. If it's already
232
* realized then go ahead and register it, otherwise wait until
233
* it's been realized.
235
if (gtk_widget_get_realized (widget)) {
236
org_ayatana_WindowMenu_Registrar_register_window (dbusproxy,
237
GDK_WINDOW_XID (gtk_widget_get_window (widget)),
242
g_signal_connect (parent, "realize",
243
G_CALLBACK (toplevel_realized),
252
checkbox_toggled (GtkWidget *widget, DbusmenuMenuitem *mi)
254
dbusmenu_menuitem_property_set_int (mi,
255
DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,
256
gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)) ? DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED : DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED);
799
265
AppMenuBridge *bridge;
800
GtkWidget *toplevel = NULL;
266
AppMenuBridgePrivate *priv;
267
DbusmenuMenuitem *item;
268
DbusmenuMenuitem *parent_item = NULL;
269
gboolean append = FALSE;
802
271
if (GTK_IS_TEAROFF_MENU_ITEM (child))
805
274
bridge = APP_MENU_BRIDGE (proxy);
807
toplevel = gtk_widget_get_toplevel (parent);
277
if (g_hash_table_lookup (bridge->priv->items, child) != NULL)
809
280
if (GTK_IS_MENU_BAR (parent))
811
/* Watch for toplevel window to appear */
812
if (!GTK_IS_WINDOW (toplevel) &&
813
g_signal_handler_find (toplevel, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
814
toplevel_notify_parent_cb, NULL) == 0)
816
g_signal_connect (toplevel,
818
G_CALLBACK (toplevel_notify_parent_cb),
822
/* Watch for parent changes for the menubar itself */
823
if (g_signal_handler_find (parent, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
824
menubar_notify_parent_cb, NULL) == 0)
826
g_signal_connect (parent,
828
G_CALLBACK (menubar_notify_parent_cb),
282
if (g_hash_table_lookup (bridge->priv->items, parent) == NULL)
284
DbusmenuMenuitem *root = dbusmenu_menuitem_new ();
285
g_hash_table_insert (bridge->priv->items, parent, root);
290
parent_item = g_hash_table_lookup (bridge->priv->items, parent);
293
GtkWidget *toplevel = gtk_widget_get_toplevel (parent);
295
g_signal_connect (G_OBJECT (toplevel),
297
G_CALLBACK (toplevel_notify_cb),
832
302
else if (GTK_IS_MENU (parent))
834
GtkWidget *attach = NULL;
836
306
g_object_get (parent, "attach-widget", &attach, NULL);
838
308
if (attach == NULL)
840
g_signal_connect (G_OBJECT (parent),
311
if (g_hash_table_lookup (bridge->priv->items, parent) != NULL)
313
parent_item = g_hash_table_lookup (bridge->priv->items, parent);
317
if (g_hash_table_lookup (bridge->priv->items, attach) != NULL)
319
parent_item = g_hash_table_lookup (bridge->priv->items, attach);
323
// XXX insert the attach item?
328
if (GTK_IS_MENU_ITEM (child))
330
item = dbusmenu_menuitem_new ();
331
g_hash_table_insert (bridge->priv->items, child, item);
333
if (GTK_IS_SEPARATOR_MENU_ITEM (child))
335
dbusmenu_menuitem_property_set (item,
341
if (GTK_IS_CHECK_MENU_ITEM (child))
343
dbusmenu_menuitem_property_set (item,
344
DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE,
345
GTK_IS_RADIO_MENU_ITEM (child) ? DBUSMENU_MENUITEM_TOGGLE_RADIO : DBUSMENU_MENUITEM_TOGGLE_CHECK);
347
dbusmenu_menuitem_property_set_int (item,
348
DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,
349
gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (child)) ? DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED : DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED);
351
g_signal_connect (child,
353
G_CALLBACK (checkbox_toggled),
357
dbusmenu_menuitem_property_set (item,
359
get_menu_label_text (child));
361
dbusmenu_menuitem_property_set_bool (item,
362
DBUSMENU_MENUITEM_PROP_ENABLED,
363
gtk_widget_get_sensitive (child));
365
g_signal_connect (G_OBJECT (child),
842
G_CALLBACK (attach_notify_cb),
848
DbusmenuMenuitem *mi = dbusmenu_gtk_parse_get_cached_item (attach);
367
G_CALLBACK (widget_notify_cb),
370
g_signal_connect (G_OBJECT (item),
372
G_CALLBACK (item_activated),
852
DbusmenuMenuitem *child_dmi = dbusmenu_gtk_parse_menu_structure (child);
854
g_object_set_data (G_OBJECT (child_dmi), "dbusmenu-parent", mi);
855
dbusmenu_menuitem_child_add_position (mi,
858
g_object_unref (child_dmi);
378
dbusmenu_menuitem_child_append (parent_item, item);
380
dbusmenu_menuitem_child_prepend (parent_item, item);
862
rebuild (bridge, toplevel);
866
if (GTK_IS_WINDOW (toplevel))
868
if (gtk_widget_get_mapped (toplevel))
870
rebuild (bridge, toplevel);
874
g_signal_connect (toplevel, "map",
875
G_CALLBACK (toplevel_mapped),