diff options
author | Ted Gould <ted@canonical.com> | 2009-08-04 16:34:08 +0100 |
---|---|---|
committer | Ted Gould <ted@canonical.com> | 2009-08-04 16:34:08 +0100 |
commit | f5c8526e3bb73345242ea37c337562182351020b (patch) | |
tree | 432cb5de765f8484daa87646c0a60d3bac6b3f4f /libdbusmenu-gtk | |
parent | ec5c382624da19a1a83d1e75d21f74778df01f38 (diff) | |
parent | 92f690257a45e81b86b39fc77ce1fe10c7b4908a (diff) | |
download | libdbusmenu-f5c8526e3bb73345242ea37c337562182351020b.tar.gz libdbusmenu-f5c8526e3bb73345242ea37c337562182351020b.tar.bz2 libdbusmenu-f5c8526e3bb73345242ea37c337562182351020b.zip |
Merging in the development branches
Diffstat (limited to 'libdbusmenu-gtk')
-rw-r--r-- | libdbusmenu-gtk/Makefile.am | 13 | ||||
-rw-r--r-- | libdbusmenu-gtk/client.c | 260 | ||||
-rw-r--r-- | libdbusmenu-gtk/client.h | 109 | ||||
-rw-r--r-- | libdbusmenu-gtk/menu.c | 281 | ||||
-rw-r--r-- | libdbusmenu-gtk/menu.h | 102 | ||||
-rw-r--r-- | libdbusmenu-gtk/test.c | 4 | ||||
-rw-r--r-- | libdbusmenu-gtk/test.h | 2 |
7 files changed, 761 insertions, 10 deletions
diff --git a/libdbusmenu-gtk/Makefile.am b/libdbusmenu-gtk/Makefile.am index 1e36228..c375428 100644 --- a/libdbusmenu-gtk/Makefile.am +++ b/libdbusmenu-gtk/Makefile.am @@ -8,10 +8,14 @@ lib_LTLIBRARIES = \ libdbusmenu_gtkincludedir=$(includedir)/libdbusmenu-0.1/libdbusmenu-gtk/ libdbusmenu_gtkinclude_HEADERS = \ - test.h + client.h \ + menu.h libdbusmenu_gtk_la_SOURCES = \ - test.c + client.h \ + client.c \ + menu.h \ + menu.c libdbusmenu_gtk_la_LDFLAGS = \ -version-info $(LIBDBUSMENU_CURRENT):$(LIBDBUSMENU_REVISION):$(LIBDBUSMENU_AGE) \ @@ -19,10 +23,11 @@ libdbusmenu_gtk_la_LDFLAGS = \ -export-symbols-regex "^[^_].*" libdbusmenu_gtk_la_CFLAGS = \ - $(LIBDBUSMENU_GTK_CFLAGS) + $(DBUSMENUGTK_CFLAGS) -I$(srcdir)/.. -Wall -Werror libdbusmenu_gtk_la_LIBADD = \ - $(LIBDBUSMENU_GTK_LIBS) + ../libdbusmenu-glib/libdbusmenu-glib.la \ + $(DBUSMENUGTK_LIBS) pkgconfig_DATA = dbusmenu-gtk.pc pkgconfigdir = $(libdir)/pkgconfig diff --git a/libdbusmenu-gtk/client.c b/libdbusmenu-gtk/client.c new file mode 100644 index 0000000..a236123 --- /dev/null +++ b/libdbusmenu-gtk/client.c @@ -0,0 +1,260 @@ +/* +A library to take the object model made consistent by libdbusmenu-glib +and visualize it in GTK. + +Copyright 2009 Canonical Ltd. + +Authors: + Ted Gould <ted@canonical.com> + +This program is free software: you can redistribute it and/or modify it +under the terms of either or both of the following licenses: + +1) the GNU Lesser General Public License version 3, as published by the +Free Software Foundation; and/or +2) the GNU Lesser General Public License version 2.1, as published by +the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranties of +MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR +PURPOSE. See the applicable version of the GNU Lesser General Public +License for more details. + +You should have received a copy of both the GNU Lesser General Public +License version 3 and version 2.1 along with this program. If not, see +<http://www.gnu.org/licenses/> +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gtk/gtk.h> + +#include "client.h" + +/* Prototypes */ +static void dbusmenu_gtkclient_class_init (DbusmenuGtkClientClass *klass); +static void dbusmenu_gtkclient_init (DbusmenuGtkClient *self); +static void dbusmenu_gtkclient_dispose (GObject *object); +static void dbusmenu_gtkclient_finalize (GObject *object); +static void new_menuitem (DbusmenuClient * client, DbusmenuMenuitem * mi, gpointer userdata); +static void new_child (DbusmenuMenuitem * mi, DbusmenuMenuitem * child, guint position, DbusmenuGtkClient * gtkclient); +static void delete_child (DbusmenuMenuitem * mi, DbusmenuMenuitem * child, DbusmenuGtkClient * gtkclient); +static void move_child (DbusmenuMenuitem * mi, DbusmenuMenuitem * child, guint new, guint old, DbusmenuGtkClient * gtkclient); + +/* GObject Stuff */ +G_DEFINE_TYPE (DbusmenuGtkClient, dbusmenu_gtkclient, DBUSMENU_TYPE_CLIENT); + +static void +dbusmenu_gtkclient_class_init (DbusmenuGtkClientClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = dbusmenu_gtkclient_dispose; + object_class->finalize = dbusmenu_gtkclient_finalize; + + return; +} + +static void +dbusmenu_gtkclient_init (DbusmenuGtkClient *self) +{ + g_signal_connect(G_OBJECT(self), DBUSMENU_CLIENT_SIGNAL_NEW_MENUITEM, G_CALLBACK(new_menuitem), NULL); + return; +} + +static void +dbusmenu_gtkclient_dispose (GObject *object) +{ + + G_OBJECT_CLASS (dbusmenu_gtkclient_parent_class)->dispose (object); + return; +} + +static void +dbusmenu_gtkclient_finalize (GObject *object) +{ + + G_OBJECT_CLASS (dbusmenu_gtkclient_parent_class)->finalize (object); + return; +} + +/* Internal Functions */ + +static const gchar * data_menuitem = "dbusmenugtk-data-gtkmenuitem"; +static const gchar * data_menu = "dbusmenugtk-data-gtkmenu"; + +/* This is the call back for the GTK widget for when it gets + clicked on by the user to send it back across the bus. */ +static gboolean +menu_pressed_cb (GtkMenuItem * gmi, DbusmenuMenuitem * mi) +{ + dbusmenu_menuitem_activate(mi); + return TRUE; +} + +/* Whenever we have a property change on a DbusmenuMenuitem + we need to be responsive to that. */ +static void +menu_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, gchar * value, GtkMenuItem * gmi) +{ + if (!g_strcmp0(prop, "label")) { + gtk_menu_item_set_label(gmi, value); + gtk_widget_show(GTK_WIDGET(gmi)); + } + + return; +} + +/* Call back that happens when the DbusmenuMenuitem + is destroyed. We're making sure to clean up everything + else down the pipe. */ +static void +destoryed_dbusmenuitem_cb (gpointer udata, GObject * dbusmenuitem) +{ + /* g_debug("DbusmenuMenuitem was destroyed"); */ + gtk_widget_destroy(GTK_WIDGET(udata)); + return; +} + +/* This takes a new DbusmenuMenuitem and attaches the + various things that we need to make it work in a + GTK World. */ +static void +new_menuitem (DbusmenuClient * client, DbusmenuMenuitem * mi, gpointer userdata) +{ + gpointer ann_mi = g_object_get_data(G_OBJECT(mi), data_menuitem); + GtkMenuItem * gmi = GTK_MENU_ITEM(ann_mi); + + if (gmi != NULL) { + /* It's possible we've already been looked at, that's + okay, but we can just ignore this signal then. */ + return; + } + + gmi = GTK_MENU_ITEM(gtk_menu_item_new()); + + /* Attach these two */ + g_object_set_data(G_OBJECT(mi), data_menuitem, gmi); + + /* DbusmenuMenuitem signals */ + g_signal_connect(G_OBJECT(mi), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(menu_prop_change_cb), gmi); + g_signal_connect(G_OBJECT(mi), DBUSMENU_MENUITEM_SIGNAL_CHILD_ADDED, G_CALLBACK(new_child), client); + g_signal_connect(G_OBJECT(mi), DBUSMENU_MENUITEM_SIGNAL_CHILD_REMOVED, G_CALLBACK(delete_child), client); + g_signal_connect(G_OBJECT(mi), DBUSMENU_MENUITEM_SIGNAL_CHILD_MOVED, G_CALLBACK(move_child), client); + + /* GtkMenuitem signals */ + g_signal_connect(G_OBJECT(gmi), "activate", G_CALLBACK(menu_pressed_cb), mi); + + /* Life insurance */ + g_object_weak_ref(G_OBJECT(mi), destoryed_dbusmenuitem_cb, gmi); + + return; +} + +static void +new_child (DbusmenuMenuitem * mi, DbusmenuMenuitem * child, guint position, DbusmenuGtkClient * gtkclient) +{ + if (dbusmenu_menuitem_get_root(mi)) { return; } + + gpointer ann_menu = g_object_get_data(G_OBJECT(mi), data_menu); + GtkMenu * menu = GTK_MENU(ann_menu); + if (menu == NULL) { + /* Oh, we don't have a submenu, build one! */ + menu = GTK_MENU(gtk_menu_new()); + g_object_set_data(G_OBJECT(mi), data_menu, menu); + + GtkMenuItem * parent = dbusmenu_gtkclient_menuitem_get(gtkclient, mi); + gtk_menu_item_set_submenu(parent, GTK_WIDGET(menu)); + } + + GtkMenuItem * childmi = dbusmenu_gtkclient_menuitem_get(gtkclient, child); + gtk_menu_shell_insert(GTK_MENU_SHELL(menu), GTK_WIDGET(childmi), position); + gtk_widget_show(GTK_WIDGET(menu)); + + return; +} + +static void +delete_child (DbusmenuMenuitem * mi, DbusmenuMenuitem * child, DbusmenuGtkClient * gtkclient) +{ + if (dbusmenu_menuitem_get_root(mi)) { return; } + + if (g_list_length(dbusmenu_menuitem_get_children(mi)) == 0) { + gpointer ann_menu = g_object_get_data(G_OBJECT(mi), data_menu); + GtkMenu * menu = GTK_MENU(ann_menu); + + if (menu != NULL) { + gtk_widget_destroy(GTK_WIDGET(menu)); + g_object_set_data(G_OBJECT(mi), data_menu, NULL); + } + } + + return; +} + +static void +move_child (DbusmenuMenuitem * mi, DbusmenuMenuitem * child, guint new, guint old, DbusmenuGtkClient * gtkclient) +{ + if (dbusmenu_menuitem_get_root(mi)) { return; } + + gpointer ann_menu = g_object_get_data(G_OBJECT(mi), data_menu); + if (ann_menu == NULL) { + g_warning("Moving a child when we don't have a submenu!"); + return; + } + + GtkMenuItem * childmi = dbusmenu_gtkclient_menuitem_get(gtkclient, child); + gtk_menu_reorder_child(GTK_MENU(ann_menu), GTK_WIDGET(childmi), new); + + return; +} + +/* Public API */ + +/** + dbusmenu_gtkclient_new: + @dbus_name: Name of the #DbusmenuServer on DBus + @dbus_name: Name of the object on the #DbusmenuServer + + Creates a new #DbusmenuGtkClient object and creates a #DbusmenuClient + that connects across DBus to a #DbusmenuServer. + + Return value: A new #DbusmenuGtkClient sync'd with a server +*/ +DbusmenuGtkClient * +dbusmenu_gtkclient_new (gchar * dbus_name, gchar * dbus_object) +{ + return g_object_new(DBUSMENU_GTKCLIENT_TYPE, + DBUSMENU_CLIENT_PROP_DBUS_OBJECT, dbus_object, + DBUSMENU_CLIENT_PROP_DBUS_NAME, dbus_name, + NULL); +} + +/** + dbusmenu_gtkclient_menuitem_get: + @client: A #DbusmenuGtkClient with the item in it. + @item: #DbusmenuMenuitem to get associated #GtkMenuItem on. + + This grabs the #GtkMenuItem that is associated with the + #DbusmenuMenuitem. + + Return value: The #GtkMenuItem that can be played with. +*/ +GtkMenuItem * +dbusmenu_gtkclient_menuitem_get (DbusmenuGtkClient * client, DbusmenuMenuitem * item) +{ + g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), NULL); + g_return_val_if_fail(DBUSMENU_IS_MENUITEM(item), NULL); + + GtkMenuItem * mi = GTK_MENU_ITEM(g_object_get_data(G_OBJECT(item), data_menuitem)); + if (mi == NULL) { + new_menuitem(DBUSMENU_CLIENT(client), item, NULL); + mi = GTK_MENU_ITEM(g_object_get_data(G_OBJECT(item), data_menuitem)); + } + + return mi; +} + diff --git a/libdbusmenu-gtk/client.h b/libdbusmenu-gtk/client.h new file mode 100644 index 0000000..a549fe0 --- /dev/null +++ b/libdbusmenu-gtk/client.h @@ -0,0 +1,109 @@ +/* +A library to take the object model made consistent by libdbusmenu-glib +and visualize it in GTK. + +Copyright 2009 Canonical Ltd. + +Authors: + Ted Gould <ted@canonical.com> + +This program is free software: you can redistribute it and/or modify it +under the terms of either or both of the following licenses: + +1) the GNU Lesser General Public License version 3, as published by the +Free Software Foundation; and/or +2) the GNU Lesser General Public License version 2.1, as published by +the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranties of +MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR +PURPOSE. See the applicable version of the GNU Lesser General Public +License for more details. + +You should have received a copy of both the GNU Lesser General Public +License version 3 and version 2.1 along with this program. If not, see +<http://www.gnu.org/licenses/> +*/ + +#ifndef __DBUSMENU_GTKCLIENT_H__ +#define __DBUSMENU_GTKCLIENT_H__ + +#include <glib.h> +#include <glib-object.h> +#include <libdbusmenu-glib/client.h> + +G_BEGIN_DECLS + +#define DBUSMENU_GTKCLIENT_TYPE (dbusmenu_gtkclient_get_type ()) +#define DBUSMENU_GTKCLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DBUSMENU_GTKCLIENT_TYPE, DbusmenuGtkClient)) +#define DBUSMENU_GTKCLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), DBUSMENU_GTKCLIENT_TYPE, DbusmenuGtkClientClass)) +#define DBUSMENU_IS_GTKCLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DBUSMENU_GTKCLIENT_TYPE)) +#define DBUSMENU_IS_GTKCLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DBUSMENU_GTKCLIENT_TYPE)) +#define DBUSMENU_GTKCLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DBUSMENU_GTKCLIENT_TYPE, DbusmenuGtkClientClass)) + +#define DBUSMENU_GTKCLIENT_SIGNAL_ROOT_CHANGED DBUSMENU_CLIENT_SIGNAL_ROOT_CHANGED + +/** + DbusmenuGtkClientClass: + @parent_class: #GtkMenuClass + @reserved1: Reserved for future use. + @reserved2: Reserved for future use. + @reserved3: Reserved for future use. + @reserved4: Reserved for future use. +*/ +typedef struct _DbusmenuGtkClientClass DbusmenuGtkClientClass; +struct _DbusmenuGtkClientClass { + DbusmenuClientClass parent_class; + + /* Signals */ + void (*root_changed) (DbusmenuMenuitem * newroot); + + /* Reserved */ + void (*reserved1) (void); + void (*reserved2) (void); + void (*reserved3) (void); + void (*reserved4) (void); +}; + +/** + DbusmenuGtkClient: + @parent: #GtkMenu +*/ +typedef struct _DbusmenuGtkClient DbusmenuGtkClient; +struct _DbusmenuGtkClient { + DbusmenuClient parent; +}; + +GType dbusmenu_gtkclient_get_type (void); +DbusmenuGtkClient * dbusmenu_gtkclient_new (gchar * dbus_name, gchar * dbus_object); +GtkMenuItem * dbusmenu_gtkclient_menuitem_get (DbusmenuGtkClient * client, DbusmenuMenuitem * item); + +/** + SECTION:gtkmenu + @short_description: A GTK Menu Object that syncronizes over DBus + @stability: Unstable + @include: libdbusmenu-gtk/menu.h + + In general, this is just a #GtkMenu, why else would you care? Oh, + because this menu is created by someone else on a server that exists + on the other side of DBus. You need a #DbusmenuServer to be able + push the data into this menu. + + The first thing you need to know is how to find that #DbusmenuServer + on DBus. This involves both the DBus name and the DBus object that + the menu interface can be found on. Those two value should be set + when creating the object using dbusmenu_gtkmenu_new(). They are then + stored on two properties #DbusmenuGtkClient:dbus-name and #DbusmenuGtkClient:dbus-object. + + After creation the #DbusmenuGtkClient it will continue to keep in + synchronization with the #DbusmenuServer object across Dbus. If the + number of entries change, the menus change, if they change thier + properties change, they update in the items. All of this should + be handled transparently to the user of this object. + + TODO: Document properties. +*/ +G_END_DECLS + +#endif diff --git a/libdbusmenu-gtk/menu.c b/libdbusmenu-gtk/menu.c new file mode 100644 index 0000000..bc7458c --- /dev/null +++ b/libdbusmenu-gtk/menu.c @@ -0,0 +1,281 @@ +/* +A library to take the object model made consistent by libdbusmenu-glib +and visualize it in GTK. + +Copyright 2009 Canonical Ltd. + +Authors: + Ted Gould <ted@canonical.com> + +This program is free software: you can redistribute it and/or modify it +under the terms of either or both of the following licenses: + +1) the GNU Lesser General Public License version 3, as published by the +Free Software Foundation; and/or +2) the GNU Lesser General Public License version 2.1, as published by +the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranties of +MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR +PURPOSE. See the applicable version of the GNU Lesser General Public +License for more details. + +You should have received a copy of both the GNU Lesser General Public +License version 3 and version 2.1 along with this program. If not, see +<http://www.gnu.org/licenses/> +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gtk/gtk.h> + +#include "menu.h" +#include "libdbusmenu-glib/client.h" +#include "client.h" + +/* Properties */ +enum { + PROP_0, + PROP_DBUSOBJECT, + PROP_DBUSNAME +}; + +/* Private */ +typedef struct _DbusmenuGtkMenuPrivate DbusmenuGtkMenuPrivate; +struct _DbusmenuGtkMenuPrivate { + DbusmenuGtkClient * client; + + gchar * dbus_object; + gchar * dbus_name; +}; + +#define DBUSMENU_GTKMENU_GET_PRIVATE(o) \ +(G_TYPE_INSTANCE_GET_PRIVATE ((o), DBUSMENU_GTKMENU_TYPE, DbusmenuGtkMenuPrivate)) + +/* Prototypes */ +static void dbusmenu_gtkmenu_class_init (DbusmenuGtkMenuClass *klass); +static void dbusmenu_gtkmenu_init (DbusmenuGtkMenu *self); +static void dbusmenu_gtkmenu_dispose (GObject *object); +static void dbusmenu_gtkmenu_finalize (GObject *object); +static void set_property (GObject * obj, guint id, const GValue * value, GParamSpec * pspec); +static void get_property (GObject * obj, guint id, GValue * value, GParamSpec * pspec); +/* Internal */ +static void build_client (DbusmenuGtkMenu * self); + +/* GObject Stuff */ +G_DEFINE_TYPE (DbusmenuGtkMenu, dbusmenu_gtkmenu, GTK_TYPE_MENU); + +static void +dbusmenu_gtkmenu_class_init (DbusmenuGtkMenuClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (DbusmenuGtkMenuPrivate)); + + object_class->dispose = dbusmenu_gtkmenu_dispose; + object_class->finalize = dbusmenu_gtkmenu_finalize; + object_class->set_property = set_property; + object_class->get_property = get_property; + + g_object_class_install_property (object_class, PROP_DBUSOBJECT, + g_param_spec_string(DBUSMENU_CLIENT_PROP_DBUS_OBJECT, "DBus Object we represent", + "The Object on the client that we're getting our data from.", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (object_class, PROP_DBUSNAME, + g_param_spec_string(DBUSMENU_CLIENT_PROP_DBUS_NAME, "DBus Client we connect to", + "Name of the DBus client we're connecting to.", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + + return; +} + +static void +dbusmenu_gtkmenu_init (DbusmenuGtkMenu *self) +{ + DbusmenuGtkMenuPrivate * priv = DBUSMENU_GTKMENU_GET_PRIVATE(self); + + priv->client = NULL; + + priv->dbus_object = NULL; + priv->dbus_name = NULL; + + return; +} + +static void +dbusmenu_gtkmenu_dispose (GObject *object) +{ + DbusmenuGtkMenuPrivate * priv = DBUSMENU_GTKMENU_GET_PRIVATE(object); + + if (priv->client != NULL) { + g_object_unref(G_OBJECT(priv->client)); + priv->client = NULL; + } + + G_OBJECT_CLASS (dbusmenu_gtkmenu_parent_class)->dispose (object); + return; +} + +static void +dbusmenu_gtkmenu_finalize (GObject *object) +{ + DbusmenuGtkMenuPrivate * priv = DBUSMENU_GTKMENU_GET_PRIVATE(object); + + g_free(priv->dbus_object); + priv->dbus_object = NULL; + + g_free(priv->dbus_name); + priv->dbus_name = NULL; + + G_OBJECT_CLASS (dbusmenu_gtkmenu_parent_class)->finalize (object); + return; +} + +static void +set_property (GObject * obj, guint id, const GValue * value, GParamSpec * pspec) +{ + DbusmenuGtkMenuPrivate * priv = DBUSMENU_GTKMENU_GET_PRIVATE(obj); + + switch (id) { + case PROP_DBUSNAME: + priv->dbus_name = g_value_dup_string(value); + if (priv->dbus_name != NULL && priv->dbus_object != NULL) { + build_client(DBUSMENU_GTKMENU(obj)); + } + break; + case PROP_DBUSOBJECT: + priv->dbus_object = g_value_dup_string(value); + if (priv->dbus_name != NULL && priv->dbus_object != NULL) { + build_client(DBUSMENU_GTKMENU(obj)); + } + break; + default: + g_warning("Unknown property %d.", id); + return; + } + + return; +} + +static void +get_property (GObject * obj, guint id, GValue * value, GParamSpec * pspec) +{ + DbusmenuGtkMenuPrivate * priv = DBUSMENU_GTKMENU_GET_PRIVATE(obj); + + switch (id) { + case PROP_DBUSNAME: + g_value_set_string(value, priv->dbus_name); + break; + case PROP_DBUSOBJECT: + g_value_set_string(value, priv->dbus_object); + break; + default: + g_warning("Unknown property %d.", id); + return; + } + + return; +} + +/* Internal Functions */ + +static void +root_child_added (DbusmenuMenuitem * root, DbusmenuMenuitem * child, guint position, DbusmenuGtkMenu * menu) +{ + g_debug("Root new child"); + DbusmenuGtkMenuPrivate * priv = DBUSMENU_GTKMENU_GET_PRIVATE(menu); + gtk_menu_shell_insert(GTK_MENU_SHELL(menu), GTK_WIDGET(dbusmenu_gtkclient_menuitem_get(priv->client, child)), position); + gtk_widget_show(GTK_WIDGET(menu)); + return; +} + +static void +root_child_moved (DbusmenuMenuitem * root, DbusmenuMenuitem * child, guint newposition, guint oldposition, DbusmenuGtkMenu * menu) +{ + g_debug("Root child moved"); + DbusmenuGtkMenuPrivate * priv = DBUSMENU_GTKMENU_GET_PRIVATE(menu); + gtk_menu_reorder_child(GTK_MENU(menu), GTK_WIDGET(dbusmenu_gtkclient_menuitem_get(priv->client, child)), newposition); + return; +} + +static void +root_child_delete (DbusmenuMenuitem * root, DbusmenuMenuitem * child, DbusmenuGtkMenu * menu) +{ + g_debug("Root child deleted"); + if (g_list_length(dbusmenu_menuitem_get_children(root)) == 0) { + gtk_widget_hide(GTK_WIDGET(menu)); + } + return; +} + +static void +root_changed (DbusmenuGtkClient * client, DbusmenuMenuitem * newroot, DbusmenuGtkMenu * menu) { + if (newroot == NULL) { + gtk_widget_hide(GTK_WIDGET(menu)); + return; + } + + g_signal_connect(G_OBJECT(newroot), DBUSMENU_MENUITEM_SIGNAL_CHILD_ADDED, G_CALLBACK(root_child_added), menu); + g_signal_connect(G_OBJECT(newroot), DBUSMENU_MENUITEM_SIGNAL_CHILD_MOVED, G_CALLBACK(root_child_moved), menu); + g_signal_connect(G_OBJECT(newroot), DBUSMENU_MENUITEM_SIGNAL_CHILD_REMOVED, G_CALLBACK(root_child_delete), menu); + + GList * child = NULL; + guint count = 0; + for (child = dbusmenu_menuitem_get_children(newroot); child != NULL; child = g_list_next(child)) { + gtk_menu_append(menu, GTK_WIDGET(dbusmenu_gtkclient_menuitem_get(client, child->data))); + count++; + } + + if (count > 0) { + gtk_widget_show(GTK_WIDGET(menu)); + } else { + gtk_widget_hide(GTK_WIDGET(menu)); + } + + return; +} + +/* Builds the client and connects all of the signals + up for it so that it's happy-happy */ +static void +build_client (DbusmenuGtkMenu * self) +{ + DbusmenuGtkMenuPrivate * priv = DBUSMENU_GTKMENU_GET_PRIVATE(self); + + if (priv->client == NULL) { + priv->client = dbusmenu_gtkclient_new(priv->dbus_name, priv->dbus_object); + + /* Register for layout changes, this should come after the + creation of the client pulls it from DBus */ + g_signal_connect(G_OBJECT(priv->client), DBUSMENU_GTKCLIENT_SIGNAL_ROOT_CHANGED, G_CALLBACK(root_changed), self); + } + + return; +} + +/* Public API */ + +/** + dbusmenu_gtkmenu_new: + @dbus_name: Name of the #DbusmenuServer on DBus + @dbus_name: Name of the object on the #DbusmenuServer + + Creates a new #DbusmenuGtkMenu object and creates a #DbusmenuClient + that connects across DBus to a #DbusmenuServer. + + Return value: A new #DbusmenuGtkMenu sync'd with a server +*/ +DbusmenuGtkMenu * +dbusmenu_gtkmenu_new (gchar * dbus_name, gchar * dbus_object) +{ + return g_object_new(DBUSMENU_GTKMENU_TYPE, + DBUSMENU_CLIENT_PROP_DBUS_OBJECT, dbus_object, + DBUSMENU_CLIENT_PROP_DBUS_NAME, dbus_name, + NULL); +} + diff --git a/libdbusmenu-gtk/menu.h b/libdbusmenu-gtk/menu.h new file mode 100644 index 0000000..73804c5 --- /dev/null +++ b/libdbusmenu-gtk/menu.h @@ -0,0 +1,102 @@ +/* +A library to take the object model made consistent by libdbusmenu-glib +and visualize it in GTK. + +Copyright 2009 Canonical Ltd. + +Authors: + Ted Gould <ted@canonical.com> + +This program is free software: you can redistribute it and/or modify it +under the terms of either or both of the following licenses: + +1) the GNU Lesser General Public License version 3, as published by the +Free Software Foundation; and/or +2) the GNU Lesser General Public License version 2.1, as published by +the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranties of +MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR +PURPOSE. See the applicable version of the GNU Lesser General Public +License for more details. + +You should have received a copy of both the GNU Lesser General Public +License version 3 and version 2.1 along with this program. If not, see +<http://www.gnu.org/licenses/> +*/ + +#ifndef __DBUSMENU_GTKMENU_H__ +#define __DBUSMENU_GTKMENU_H__ + +#include <glib.h> +#include <glib-object.h> + +G_BEGIN_DECLS + +#define DBUSMENU_GTKMENU_TYPE (dbusmenu_gtkmenu_get_type ()) +#define DBUSMENU_GTKMENU(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DBUSMENU_GTKMENU_TYPE, DbusmenuGtkMenu)) +#define DBUSMENU_GTKMENU_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), DBUSMENU_GTKMENU_TYPE, DbusmenuGtkMenuClass)) +#define DBUSMENU_IS_GTKMENU(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DBUSMENU_GTKMENU_TYPE)) +#define DBUSMENU_IS_GTKMENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DBUSMENU_GTKMENU_TYPE)) +#define DBUSMENU_GTKMENU_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DBUSMENU_GTKMENU_TYPE, DbusmenuGtkMenuClass)) + +/** + DbusmenuGtkMenuClass: + @parent_class: #GtkMenuClass + @reserved1: Reserved for future use. + @reserved2: Reserved for future use. + @reserved3: Reserved for future use. + @reserved4: Reserved for future use. +*/ +typedef struct _DbusmenuGtkMenuClass DbusmenuGtkMenuClass; +struct _DbusmenuGtkMenuClass { + GtkMenuClass parent_class; + + /* Reserved */ + void (*reserved1) (void); + void (*reserved2) (void); + void (*reserved3) (void); + void (*reserved4) (void); +}; + +/** + DbusmenuGtkMenu: + @parent: #GtkMenu +*/ +typedef struct _DbusmenuGtkMenu DbusmenuGtkMenu; +struct _DbusmenuGtkMenu { + GtkMenu parent; +}; + +GType dbusmenu_gtkmenu_get_type (void); +DbusmenuGtkMenu * dbusmenu_gtkmenu_new (gchar * dbus_name, gchar * dbus_object); + +/** + SECTION:gtkmenu + @short_description: A GTK Menu Object that syncronizes over DBus + @stability: Unstable + @include: libdbusmenu-gtk/menu.h + + In general, this is just a #GtkMenu, why else would you care? Oh, + because this menu is created by someone else on a server that exists + on the other side of DBus. You need a #DbusmenuServer to be able + push the data into this menu. + + The first thing you need to know is how to find that #DbusmenuServer + on DBus. This involves both the DBus name and the DBus object that + the menu interface can be found on. Those two value should be set + when creating the object using dbusmenu_gtkmenu_new(). They are then + stored on two properties #DbusmenuGtkMenu:dbus-name and #DbusmenuGtkMenu:dbus-object. + + After creation the #DbusmenuGtkMenu it will continue to keep in + synchronization with the #DbusmenuServer object across Dbus. If the + number of entries change, the menus change, if they change thier + properties change, they update in the items. All of this should + be handled transparently to the user of this object. + + TODO: Document properties. +*/ +G_END_DECLS + +#endif diff --git a/libdbusmenu-gtk/test.c b/libdbusmenu-gtk/test.c deleted file mode 100644 index 8ebb3f7..0000000 --- a/libdbusmenu-gtk/test.c +++ /dev/null @@ -1,4 +0,0 @@ - -void mysymbol (void) { - return; -} diff --git a/libdbusmenu-gtk/test.h b/libdbusmenu-gtk/test.h deleted file mode 100644 index ad000af..0000000 --- a/libdbusmenu-gtk/test.h +++ /dev/null @@ -1,2 +0,0 @@ - -void mysymbol (void); |