aboutsummaryrefslogtreecommitdiff
path: root/libdbusmenu-glib/menuitem.c
diff options
context:
space:
mode:
authorTed Gould <ted@canonical.com>2009-05-19 04:53:43 +0200
committerTed Gould <ted@canonical.com>2009-05-19 04:53:43 +0200
commit4a9246ce21cd54b686e6885c1423de83e3240f6d (patch)
tree50609f03ba200a980c07646e5b9bd19831f07508 /libdbusmenu-glib/menuitem.c
parent3d0e0276fd7856831dcc845a24a252ad304b3bad (diff)
parent8d503ab2a495ffec09b84bfa376f1771ba47138c (diff)
downloadlibdbusmenu-4a9246ce21cd54b686e6885c1423de83e3240f6d.tar.gz
libdbusmenu-4a9246ce21cd54b686e6885c1423de83e3240f6d.tar.bz2
libdbusmenu-4a9246ce21cd54b686e6885c1423de83e3240f6d.zip
Merging in the properties branch to provide some basis to work with.
Diffstat (limited to 'libdbusmenu-glib/menuitem.c')
-rw-r--r--libdbusmenu-glib/menuitem.c324
1 files changed, 320 insertions, 4 deletions
diff --git a/libdbusmenu-glib/menuitem.c b/libdbusmenu-glib/menuitem.c
index 0894d2c..9506cad 100644
--- a/libdbusmenu-glib/menuitem.c
+++ b/libdbusmenu-glib/menuitem.c
@@ -30,6 +30,7 @@ License version 3 and version 2.1 along with this program. If not, see
#include "config.h"
#endif
#include "menuitem.h"
+#include "menuitem-marshal.h"
/* Private */
/**
@@ -37,6 +38,7 @@ License version 3 and version 2.1 along with this program. If not, see
@id: The ID of this menu item
@children: A list of #DbusmenuMenuitem objects that are
children to this one.
+ @properties: All of the properties on this menu item.
These are the little secrets that we don't want getting
out of data that we have. They can still be gotten using
@@ -47,8 +49,20 @@ struct _DbusmenuMenuitemPrivate
{
guint id;
GList * children;
+ GHashTable * properties;
};
+/* Signals */
+enum {
+ PROPERTY_CHANGED,
+ ITEM_ACTIVATED,
+ CHILD_ADDED,
+ CHILD_REMOVED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
/* Properties */
enum {
PROP_0,
@@ -81,6 +95,69 @@ dbusmenu_menuitem_class_init (DbusmenuMenuitemClass *klass)
object_class->set_property = set_property;
object_class->get_property = get_property;
+ /**
+ DbusmenuMenuitem::property-changed:
+ @arg0: The #DbusmenuMenuitem object.
+ @arg1: The name of the property that changed
+ @arg2: The new value of the property
+
+ Emitted everytime a property on a menuitem is either
+ updated or added.
+ */
+ signals[PROPERTY_CHANGED] = g_signal_new(DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED,
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(DbusmenuMenuitemClass, property_changed),
+ NULL, NULL,
+ _dbusmenu_menuitem_marshal_VOID__STRING_STRING,
+ G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
+ /**
+ DbusmenuMenuitem::item-activated:
+ @arg0: The #DbusmenuMenuitem object.
+
+ Emitted on the objects on the server side when
+ they are signaled on the client side.
+ */
+ signals[ITEM_ACTIVATED] = g_signal_new(DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(DbusmenuMenuitemClass, item_activated),
+ NULL, NULL,
+ _dbusmenu_menuitem_marshal_VOID__VOID,
+ G_TYPE_NONE, 0, G_TYPE_NONE);
+ /**
+ DbusmenuMenuitem::child-added:
+ @arg0: The #DbusmenuMenuitem which is the parent.
+ @arg1: The #DbusmenuMenuitem which is the child.
+
+ Signaled when the child menuitem has been added to
+ the parent.
+ */
+ signals[CHILD_ADDED] = g_signal_new(DBUSMENU_MENUITEM_SIGNAL_CHILD_ADDED,
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(DbusmenuMenuitemClass, child_added),
+ NULL, NULL,
+ _dbusmenu_menuitem_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 2, G_TYPE_OBJECT);
+ /**
+ DbusmenuMenuitem::child-removed:
+ @arg0: The #DbusmenuMenuitem which was the parent.
+ @arg1: The #DbusmenuMenuitem which was the child.
+
+ Signaled when the child menuitem has been requested to
+ be removed from the parent. This signal is called when
+ it has been removed from the list but not yet had
+ #g_object_unref called on it.
+ */
+ signals[CHILD_REMOVED] = g_signal_new(DBUSMENU_MENUITEM_SIGNAL_CHILD_REMOVED,
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(DbusmenuMenuitemClass, child_removed),
+ NULL, NULL,
+ _dbusmenu_menuitem_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 2, G_TYPE_OBJECT);
+
g_object_class_install_property (object_class, PROP_ID,
g_param_spec_uint("id", "ID for the menu item",
"This is a unique indentifier for the menu item.",
@@ -99,6 +176,8 @@ dbusmenu_menuitem_init (DbusmenuMenuitem *self)
priv->id = 0;
priv->children = NULL;
+
+ priv->properties = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
return;
}
@@ -114,6 +193,12 @@ dbusmenu_menuitem_dispose (GObject *object)
static void
dbusmenu_menuitem_finalize (GObject *object)
{
+ DbusmenuMenuitemPrivate * priv = DBUSMENU_MENUITEM_GET_PRIVATE(object);
+
+ if (priv->properties != NULL) {
+ g_hash_table_destroy(priv->properties);
+ priv->properties = NULL;
+ }
G_OBJECT_CLASS (dbusmenu_menuitem_parent_class)->finalize (object);
return;
@@ -181,7 +266,7 @@ DbusmenuMenuitem *
dbusmenu_menuitem_new_with_id (guint id)
{
DbusmenuMenuitem * mi = g_object_new(DBUSMENU_TYPE_MENUITEM, "id", id, NULL);
- g_debug("New Menuitem id %d goal id %d", dbusmenu_menuitem_get_id(mi), id);
+ /* g_debug("New Menuitem id %d goal id %d", dbusmenu_menuitem_get_id(mi), id); */
return mi;
}
@@ -223,6 +308,15 @@ dbusmenu_menuitem_get_children (DbusmenuMenuitem * mi)
return priv->children;
}
+/* For all the taken children we need to signal
+ that they were removed */
+static void
+take_children_signal (gpointer data, gpointer user_data)
+{
+ g_signal_emit(G_OBJECT(user_data), signals[CHILD_REMOVED], 0, DBUSMENU_MENUITEM(data), TRUE);
+ return;
+}
+
/**
dbusmenu_menuitem_take_children:
@mi: The #DbusmenMenuitem to take the children from.
@@ -243,6 +337,7 @@ dbusmenu_menuitem_take_children (DbusmenuMenuitem * mi)
DbusmenuMenuitemPrivate * priv = DBUSMENU_MENUITEM_GET_PRIVATE(mi);
GList * children = priv->children;
priv->children = NULL;
+ g_list_foreach(children, take_children_signal, mi);
return children;
}
@@ -294,6 +389,7 @@ dbusmenu_menuitem_child_append (DbusmenuMenuitem * mi, DbusmenuMenuitem * child)
DbusmenuMenuitemPrivate * priv = DBUSMENU_MENUITEM_GET_PRIVATE(mi);
priv->children = g_list_append(priv->children, child);
+ g_signal_emit(G_OBJECT(mi), signals[CHILD_ADDED], 0, child, TRUE);
return TRUE;
}
@@ -316,6 +412,7 @@ dbusmenu_menuitem_child_delete (DbusmenuMenuitem * mi, DbusmenuMenuitem * child)
DbusmenuMenuitemPrivate * priv = DBUSMENU_MENUITEM_GET_PRIVATE(mi);
priv->children = g_list_remove(priv->children, child);
+ g_signal_emit(G_OBJECT(mi), signals[CHILD_REMOVED], 0, child, TRUE);
return TRUE;
}
@@ -339,6 +436,7 @@ dbusmenu_menuitem_child_add_position (DbusmenuMenuitem * mi, DbusmenuMenuitem *
DbusmenuMenuitemPrivate * priv = DBUSMENU_MENUITEM_GET_PRIVATE(mi);
priv->children = g_list_insert(priv->children, child, position);
+ g_signal_emit(G_OBJECT(mi), signals[CHILD_ADDED], 0, child, TRUE);
return TRUE;
}
@@ -371,25 +469,192 @@ dbusmenu_menuitem_child_find (DbusmenuMenuitem * mi, guint id)
return NULL;
}
+typedef struct {
+ DbusmenuMenuitem * mi;
+ guint id;
+} find_id_t;
+
+/* Basically the heart of the find_id that matches the
+ API of GFunc. Unfortunately, this goes through all the
+ children, but it rejects them quickly. */
+static void
+find_id_helper (gpointer in_mi, gpointer in_find_id)
+{
+ DbusmenuMenuitem * mi = (DbusmenuMenuitem *)in_mi;
+ find_id_t * find_id = (find_id_t *)in_find_id;
+
+ if (find_id->mi != NULL) return;
+ if (find_id->id == dbusmenu_menuitem_get_id(mi)) {
+ find_id->mi = mi;
+ return;
+ }
+
+ g_list_foreach(dbusmenu_menuitem_get_children(mi), find_id_helper, in_find_id);
+ return;
+}
+
+/**
+ dbusmenu_menuitem_find_id:
+ @mi: #DbusmenuMenuitem at the top of the tree to search
+ @id: ID of the #DbusmenuMenuitem to search for
+
+ This function searchs the whole tree of children that
+ are attached to @mi. This could be quite a few nodes, all
+ the way down the tree. It is a depth first search.
+
+ Return value: The #DbusmenuMenuitem with the ID of @id
+ or #NULL if there isn't such a menu item in the tree
+ represented by @mi.
+*/
+DbusmenuMenuitem *
+dbusmenu_menuitem_find_id (DbusmenuMenuitem * mi, guint id)
+{
+ g_return_val_if_fail(DBUSMENU_IS_MENUITEM(mi), NULL);
+ find_id_t find_id = {mi: NULL, id: id};
+ find_id_helper(mi, &find_id);
+ return find_id.mi;
+}
+
+/**
+ dbusmenu_menuitem_property_set:
+ @mi: The #DbusmenuMenuitem to set the property on.
+ @property: Name of the property to set.
+ @value: The value of the property.
+
+ Takes the pair of @property and @value and places them as a
+ property on @mi. If a property already exists by that name,
+ then the value is set to the new value. If not, the property
+ is added. If the value is changed or the property was previously
+ unset then the signal #DbusmenuMenuitem::prop-changed will be
+ emitted by this function.
+
+ Return value: A boolean representing if the property value was set.
+*/
gboolean
dbusmenu_menuitem_property_set (DbusmenuMenuitem * mi, const gchar * property, const gchar * value)
{
+ g_return_val_if_fail(DBUSMENU_IS_MENUITEM(mi), FALSE);
+ g_return_val_if_fail(property != NULL, FALSE);
+
+ DbusmenuMenuitemPrivate * priv = DBUSMENU_MENUITEM_GET_PRIVATE(mi);
+ /* g_debug("Setting a property. ID: %d Prop: %s Value: %s", priv->id, property, value); */
+
+ gpointer lookup = g_hash_table_lookup(priv->properties, property);
+ if (g_strcmp0((gchar *)lookup, value) == 0) {
+ /* The value is the same as the value currently in the
+ table so we don't really care. Just say everything's okay */
+ return TRUE;
+ }
+
+ gchar * lprop = g_strdup(property);
+ gchar * lval = g_strdup(value);
+
+ g_hash_table_insert(priv->properties, lprop, lval);
+ g_signal_emit(G_OBJECT(mi), signals[PROPERTY_CHANGED], 0, property, value, TRUE);
- return FALSE;
+ return TRUE;
}
+/**
+ dbusmenu_menuitem_property_get:
+ @mi: The #DbusmenuMenuitem to look for the property on.
+ @property: The property to grab.
+
+ Look up a property on @mi and return the value of it if
+ it exits. #NULL will be returned if the property doesn't
+ exist.
+
+ Return value: A string with the value of the property
+ that shouldn't be free'd. Or #NULL if the property
+ is not set.
+*/
const gchar *
dbusmenu_menuitem_property_get (DbusmenuMenuitem * mi, const gchar * property)
{
+ g_return_val_if_fail(DBUSMENU_IS_MENUITEM(mi), NULL);
+ g_return_val_if_fail(property != NULL, NULL);
- return NULL;
+ DbusmenuMenuitemPrivate * priv = DBUSMENU_MENUITEM_GET_PRIVATE(mi);
+
+ return (const gchar *)g_hash_table_lookup(priv->properties, property);
}
+/**
+ dbusmenu_menuitem_property_exit:
+ @mi: The #DbusmenuMenuitem to look for the property on.
+ @property: The property to look for.
+
+ Checkes to see if a particular property exists on @mi and
+ returns #TRUE if so.
+
+ Return value: A boolean checking to see if the property is available
+*/
gboolean
dbusmenu_menuitem_property_exist (DbusmenuMenuitem * mi, const gchar * property)
{
+ g_return_val_if_fail(DBUSMENU_IS_MENUITEM(mi), FALSE);
+ g_return_val_if_fail(property != NULL, FALSE);
+
+ DbusmenuMenuitemPrivate * priv = DBUSMENU_MENUITEM_GET_PRIVATE(mi);
+
+ gpointer value = g_hash_table_lookup(priv->properties, property);
- return FALSE;
+ return value != NULL;
+}
+
+/**
+ dbusmenu_menuitem_properties_list:
+ @mi: #DbusmenuMenuitem to list the properties on
+
+ This functiong gets a list of the names of all the properties
+ that are set on this menu item. This data on the list is owned
+ by the menuitem but the list is not and should be freed using
+ g_list_free() when the calling function is done with it.
+
+ Return value: A list of strings or NULL if there are none.
+*/
+GList *
+dbusmenu_menuitem_properties_list (DbusmenuMenuitem * mi)
+{
+ g_return_val_if_fail(DBUSMENU_IS_MENUITEM(mi), NULL);
+
+ DbusmenuMenuitemPrivate * priv = DBUSMENU_MENUITEM_GET_PRIVATE(mi);
+ return g_hash_table_get_keys(priv->properties);
+}
+
+static void
+copy_helper (gpointer in_key, gpointer in_value, gpointer in_data)
+{
+ GHashTable * table = (GHashTable *)in_data;
+ g_hash_table_insert(table, in_key, in_value);
+ return;
+}
+
+/**
+ dbusmenu_menuitem_properties_copy:
+ @mi: #DbusmenuMenuitem that we're interested in the properties of
+
+ This function takes the properties of a #DbusmenuMenuitem
+ and puts them into a #GHashTable that is referenced by the
+ key of a string and has the value of a string. The hash
+ table may not have any entries if there aren't any or there
+ is an error in processing. It is the caller's responsibility
+ to destroy the created #GHashTable.
+
+ Return value: A brand new #GHashTable that contains all of the
+ properties that are on this #DbusmenuMenuitem @mi.
+*/
+GHashTable *
+dbusmenu_menuitem_properties_copy (DbusmenuMenuitem * mi)
+{
+ GHashTable * ret = g_hash_table_new(g_str_hash, g_str_equal);
+
+ g_return_val_if_fail(DBUSMENU_IS_MENUITEM(mi), ret);
+
+ DbusmenuMenuitemPrivate * priv = DBUSMENU_MENUITEM_GET_PRIVATE(mi);
+ g_hash_table_foreach(priv->properties, copy_helper, ret);
+
+ return ret;
}
/**
@@ -422,3 +687,54 @@ dbusmenu_menuitem_buildxml (DbusmenuMenuitem * mi, GPtrArray * array)
return;
}
+typedef struct {
+ void (*func) (DbusmenuMenuitem * mi, gpointer data);
+ gpointer data;
+} foreach_struct_t;
+
+static void
+foreach_helper (gpointer data, gpointer user_data)
+{
+ dbusmenu_menuitem_foreach(DBUSMENU_MENUITEM(data), ((foreach_struct_t *)user_data)->func, ((foreach_struct_t *)user_data)->data);
+ return;
+}
+
+/**
+ dbusmenu_menuitem_foreach:
+ @mi: The #DbusmenItem to start from
+ @func: Function to call on every node in the tree
+ @data: User data to pass to the function
+
+ This calls the function @func on this menu item and all
+ of the children of this item. And their children. And
+ their children. And... you get the point. It will get
+ called on the whole tree.
+*/
+void
+dbusmenu_menuitem_foreach (DbusmenuMenuitem * mi, void (*func) (DbusmenuMenuitem * mi, gpointer data), gpointer data)
+{
+ g_return_if_fail(DBUSMENU_IS_MENUITEM(mi));
+ g_return_if_fail(func != NULL);
+
+ func(mi, data);
+ GList * children = dbusmenu_menuitem_get_children(mi);
+ foreach_struct_t foreach_data = {func: func, data: data};
+ g_list_foreach(children, foreach_helper, &foreach_data);
+ return;
+}
+
+/**
+ dbusmenu_menuitem_activate:
+ @mi: The #DbusmenuMenuitem to send the signal on.
+
+ Emits the #DbusmenuMenuitem::item-activate signal on this
+ menu item. Called by server objects when they get the
+ appropriate DBus signals from the client.
+*/
+void
+dbusmenu_menuitem_activate (DbusmenuMenuitem * mi)
+{
+ g_return_if_fail(DBUSMENU_IS_MENUITEM(mi));
+ g_signal_emit(G_OBJECT(mi), signals[ITEM_ACTIVATED], 0, TRUE);
+ return;
+}