aboutsummaryrefslogtreecommitdiff
path: root/libdbusmenu-gtk
diff options
context:
space:
mode:
authorTed Gould <ted@canonical.com>2009-05-25 23:57:37 +0200
committerTed Gould <ted@canonical.com>2009-05-25 23:57:37 +0200
commit7ce95932ac8f16dac65fa6b822bf672e54945e6c (patch)
tree806d4c51c5de5992625eac65c10d305b5d29152e /libdbusmenu-gtk
parent8993030df1bcedecdbf7430db9ff2bfb38522b84 (diff)
parent30a97d87f44f64c5a533b244b7e77bb01787ea53 (diff)
downloadlibdbusmenu-7ce95932ac8f16dac65fa6b822bf672e54945e6c.tar.gz
libdbusmenu-7ce95932ac8f16dac65fa6b822bf672e54945e6c.tar.bz2
libdbusmenu-7ce95932ac8f16dac65fa6b822bf672e54945e6c.zip
Bringing in the gtkmenu branch
Diffstat (limited to 'libdbusmenu-gtk')
-rw-r--r--libdbusmenu-gtk/Makefile.am9
-rw-r--r--libdbusmenu-gtk/menu.c304
-rw-r--r--libdbusmenu-gtk/menu.h74
-rw-r--r--libdbusmenu-gtk/test.c4
-rw-r--r--libdbusmenu-gtk/test.h2
5 files changed, 383 insertions, 10 deletions
diff --git a/libdbusmenu-gtk/Makefile.am b/libdbusmenu-gtk/Makefile.am
index 1e36228..80e6058 100644
--- a/libdbusmenu-gtk/Makefile.am
+++ b/libdbusmenu-gtk/Makefile.am
@@ -8,10 +8,10 @@ lib_LTLIBRARIES = \
libdbusmenu_gtkincludedir=$(includedir)/libdbusmenu-0.1/libdbusmenu-gtk/
libdbusmenu_gtkinclude_HEADERS = \
- test.h
+ menu.h
libdbusmenu_gtk_la_SOURCES = \
- test.c
+ menu.c
libdbusmenu_gtk_la_LDFLAGS = \
-version-info $(LIBDBUSMENU_CURRENT):$(LIBDBUSMENU_REVISION):$(LIBDBUSMENU_AGE) \
@@ -19,10 +19,11 @@ libdbusmenu_gtk_la_LDFLAGS = \
-export-symbols-regex "^[^_].*"
libdbusmenu_gtk_la_CFLAGS = \
- $(LIBDBUSMENU_GTK_CFLAGS)
+ $(DBUSMENUGTK_CFLAGS) -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/menu.c b/libdbusmenu-gtk/menu.c
new file mode 100644
index 0000000..dd2df37
--- /dev/null
+++ b/libdbusmenu-gtk/menu.c
@@ -0,0 +1,304 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gtk/gtk.h>
+
+#include "menu.h"
+#include "libdbusmenu-glib/client.h"
+
+/* Properties */
+enum {
+ PROP_0,
+ PROP_DBUSOBJECT,
+ PROP_DBUSNAME
+};
+
+/* Private */
+typedef struct _DbusmenuGtkMenuPrivate DbusmenuGtkMenuPrivate;
+struct _DbusmenuGtkMenuPrivate {
+ DbusmenuClient * 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 const gchar * data_menuitem = "dbusmenugtk-data-gtkmenuitem";
+static const gchar * data_menu = "dbusmenugtk-data-gtkmenu";
+
+static gboolean
+menu_pressed_cb (GtkMenuItem * gmi, DbusmenuMenuitem * mi)
+{
+ dbusmenu_menuitem_activate(mi);
+ return TRUE;
+}
+
+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;
+}
+
+static void
+destoryed_dbusmenuitem_cb (gpointer udata, GObject * dbusmenuitem)
+{
+ /* g_debug("DbusmenuMenuitem was destroyed"); */
+ gtk_widget_destroy(GTK_WIDGET(udata));
+ return;
+}
+
+static void
+connect_menuitem (DbusmenuMenuitem * mi, GtkMenuItem * gmi)
+{
+ g_object_set_data(G_OBJECT(mi), data_menuitem, gmi);
+
+ g_signal_connect(G_OBJECT(mi), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(menu_prop_change_cb), gmi);
+ g_signal_connect(G_OBJECT(gmi), "activate", G_CALLBACK(menu_pressed_cb), mi);
+
+ g_object_weak_ref(G_OBJECT(mi), destoryed_dbusmenuitem_cb, gmi);
+
+ return;
+}
+
+static void
+process_dbusmenu_menuitem (DbusmenuMenuitem * mi, GtkMenu * parentmenu)
+{
+ gpointer unknown_menuitem = g_object_get_data(G_OBJECT(mi), data_menuitem);
+ if (unknown_menuitem == NULL) {
+ /* Oh, a virgin DbusmenuMenuitem, let's fix that. */
+ GtkWidget * menuitem = gtk_menu_item_new();
+ connect_menuitem(mi, GTK_MENU_ITEM(menuitem));
+ unknown_menuitem = menuitem;
+ gtk_menu_shell_append(GTK_MENU_SHELL(parentmenu), menuitem);
+ }
+
+ GList * children = dbusmenu_menuitem_get_children(mi);
+ if (children == NULL) {
+ /* If there are no children to process we are
+ done and we can move along */
+ return;
+ }
+
+ /* Phase 0: Make a submenu if we don't have one */
+ gpointer unknown_menu = g_object_get_data(G_OBJECT(mi), data_menu);
+ if (unknown_menu == NULL) {
+ GtkWidget * gtkmenu = gtk_menu_new();
+ g_object_ref(gtkmenu);
+ g_object_set_data_full(G_OBJECT(mi), data_menu, gtkmenu, g_object_unref);
+ unknown_menu = gtkmenu;
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(unknown_menuitem), gtkmenu);
+ gtk_widget_show(gtkmenu);
+ }
+
+ /* Phase 1: Add missing children */
+ GList * child = NULL;
+ for (child = children; child != NULL; child = g_list_next(child)) {
+ process_dbusmenu_menuitem(DBUSMENU_MENUITEM(child->data), GTK_MENU(unknown_menu));
+ }
+
+ /* Phase 2: Delete removed children */
+ /* Actually, we don't need to do this because of the weak
+ reference that we've added above. When the DbusmenuMenuitem
+ gets destroyed it takes its GtkMenuItem with it. Bye bye. */
+
+ /* Phase 3: Profit! */
+ return;
+}
+
+/* Processing the layout being updated and handling
+ that and making it into a menu */
+static void
+process_layout_change (DbusmenuClient * client, DbusmenuGtkMenu * gtkmenu)
+{
+ DbusmenuMenuitem * root = dbusmenu_client_get_root(client);
+
+ GList * children = dbusmenu_menuitem_get_children(root);
+ if (children == NULL) {
+ return;
+ }
+
+ GList * child = NULL;
+ for (child = children; child != NULL; child = g_list_next(child)) {
+ process_dbusmenu_menuitem(DBUSMENU_MENUITEM(child->data), GTK_MENU(gtkmenu));
+ }
+
+ 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_client_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_CLIENT_SIGNAL_LAYOUT_UPDATED, G_CALLBACK(process_layout_change), 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..dd5bdd1
--- /dev/null
+++ b/libdbusmenu-gtk/menu.h
@@ -0,0 +1,74 @@
+#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);