[gtk+/wip/gmenu: 31/87] add GActionMuxer and observer interfaces
- From: Ryan Lortie <ryanl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/gmenu: 31/87] add GActionMuxer and observer interfaces
- Date: Sat, 3 Dec 2011 23:50:45 +0000 (UTC)
commit c8fa4e41a8b21b1b21c5621e8e5b9550e0202a3e
Author: Ryan Lortie <desrt desrt ca>
Date: Wed Nov 30 09:33:03 2011 -0500
add GActionMuxer and observer interfaces
These were destined for GLib, but they don't really make sense as a
public API. Instead, we'll copy/paste them around between the various
codebases that need to render menus.
gtk/Makefile.am | 6 +
gtk/gactionmuxer.c | 505 +++++++++++++++++++++++++++++++++++++++++++++++
gtk/gactionmuxer.h | 53 +++++
gtk/gactionobservable.c | 86 ++++++++
gtk/gactionobservable.h | 64 ++++++
gtk/gactionobserver.c | 171 ++++++++++++++++
gtk/gactionobserver.h | 90 +++++++++
7 files changed, 975 insertions(+), 0 deletions(-)
---
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index dc613aa..3e11d8c 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -384,6 +384,9 @@ endif
# GTK+ header files that don't get installed
gtk_private_h_sources = \
+ gactionmuxer.h \
+ gactionobserver.h \
+ gactionobservable.h \
gtkaccelgroupprivate.h \
gtkanimationdescription.h \
gtkappchooserprivate.h \
@@ -493,6 +496,9 @@ deprecated_c_sources = \
gtk_base_c_sources = \
$(deprecated_c_sources) \
+ gactionmuxer.c \
+ gactionobserver.c \
+ gactionobservable.c \
gtkquery.c \
gtksearchengine.c \
gtksearchenginesimple.c \
diff --git a/gtk/gactionmuxer.c b/gtk/gactionmuxer.c
new file mode 100644
index 0000000..bb3325e
--- /dev/null
+++ b/gtk/gactionmuxer.c
@@ -0,0 +1,505 @@
+/*
+ * Copyright  2011 Canonical Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Ryan Lortie <desrt desrt ca>
+ */
+
+#include "config.h"
+
+#include "gactionmuxer.h"
+
+#include "gactionobservable.h"
+#include "gactionobserver.h"
+
+#include <string.h>
+
+/**
+ * SECTION:gactionmuxer
+ * @short_description: Aggregate and monitor several action groups
+ *
+ * #GActionMuxer is a #GActionGroup and #GActionObservable that is
+ * capable of containing other #GActionGroup instances.
+ *
+ * The typical use is aggrgating all of the actions applicable to a
+ * particular context into a single action group, with namespacing.
+ *
+ * Consider the case of two action groups -- one containing actions
+ * applicable to an entire application (such as 'quit') and one
+ * containing actions applicable to a particular window in the
+ * application (such as 'fullscreen').
+ *
+ * In this case, each of these action groups could be added to a
+ * #GActionMuxer with the prefixes "app" and "win", respectively. This
+ * would expose the actions as "app.quit" and "win.fullscreen" on the
+ * #GActionGroup interface presented by the #GActionMuxer.
+ *
+ * Activations and state change requests on the #GActionMuxer are wired
+ * through to the underlying action group in the expected way.
+ *
+ * This class is typically only used at the site of "consumption" of
+ * actions (eg: when displaying a menu that contains many actions on
+ * different objects).
+ *
+ * Since: 2.32
+ **/
+
+static void g_action_muxer_group_iface_init (GActionGroupInterface *iface);
+static void g_action_muxer_observable_iface_init (GActionObservableInterface *iface);
+
+typedef GObjectClass GActionMuxerClass;
+
+struct _GActionMuxer
+{
+ GObject parent_instance;
+
+ GHashTable *actions;
+ GHashTable *groups;
+};
+
+G_DEFINE_TYPE_WITH_CODE (GActionMuxer, g_action_muxer, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP, g_action_muxer_group_iface_init)
+ G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_OBSERVABLE, g_action_muxer_observable_iface_init))
+
+typedef struct
+{
+ GActionMuxer *muxer;
+ GSList *watchers;
+ gchar *fullname;
+} Action;
+
+typedef struct
+{
+ GActionMuxer *muxer;
+ GActionGroup *group;
+ gchar *prefix;
+ gulong handler_ids[4];
+} Group;
+
+static gchar **
+g_action_muxer_list_actions (GActionGroup *action_group)
+{
+ GActionMuxer *muxer = G_ACTION_MUXER (action_group);
+
+ return (gchar **) muxer->groups;
+}
+
+static Group *
+g_action_muxer_find_group (GActionMuxer *muxer,
+ const gchar **name)
+{
+ const gchar *dot;
+ gchar *prefix;
+ Group *group;
+
+ dot = strchr (*name, '.');
+
+ if (!dot)
+ return NULL;
+
+ prefix = g_strndup (*name, dot - *name);
+ group = g_hash_table_lookup (muxer->groups, prefix);
+ g_free (prefix);
+
+ *name = dot + 1;
+
+ return group;
+}
+
+static Action *
+g_action_muxer_lookup_action (GActionMuxer *muxer,
+ const gchar *prefix,
+ const gchar *action_name,
+ gchar **fullname)
+{
+ Action *action;
+
+ *fullname = g_strconcat (prefix, ".", action_name, NULL);
+ action = g_hash_table_lookup (muxer->actions, *fullname);
+
+ return action;
+}
+
+static void
+g_action_muxer_action_enabled_changed (GActionGroup *action_group,
+ const gchar *action_name,
+ gboolean enabled,
+ gpointer user_data)
+{
+ Group *group = user_data;
+ gchar *fullname;
+ Action *action;
+ GSList *node;
+
+ g_print ("feeling changes\n");
+
+ action = g_action_muxer_lookup_action (group->muxer, group->prefix, action_name, &fullname);
+ for (node = action ? action->watchers : NULL; node; node = node->next)
+ g_action_observer_action_enabled_changed (node->data, G_ACTION_OBSERVABLE (group->muxer), fullname, enabled);
+ g_action_group_action_enabled_changed (G_ACTION_GROUP (group->muxer), fullname, enabled);
+ g_free (fullname);
+}
+
+static void
+g_action_muxer_action_state_changed (GActionGroup *action_group,
+ const gchar *action_name,
+ GVariant *state,
+ gpointer user_data)
+{
+ Group *group = user_data;
+ gchar *fullname;
+ Action *action;
+ GSList *node;
+
+ action = g_action_muxer_lookup_action (group->muxer, group->prefix, action_name, &fullname);
+ for (node = action ? action->watchers : NULL; node; node = node->next)
+ g_action_observer_action_state_changed (node->data, G_ACTION_OBSERVABLE (group->muxer), fullname, state);
+ g_action_group_action_state_changed (G_ACTION_GROUP (group->muxer), fullname, state);
+ g_free (fullname);
+}
+
+static void
+g_action_muxer_action_added (GActionGroup *action_group,
+ const gchar *action_name,
+ gpointer user_data)
+{
+ const GVariantType *parameter_type;
+ Group *group = user_data;
+ gboolean enabled;
+ GVariant *state;
+
+ if (g_action_group_query_action (group->group, action_name, &enabled, ¶meter_type, NULL, NULL, &state))
+ {
+ gchar *fullname;
+ Action *action;
+ GSList *node;
+
+ action = g_action_muxer_lookup_action (group->muxer, group->prefix, action_name, &fullname);
+
+ for (node = action ? action->watchers : NULL; node; node = node->next)
+ g_action_observer_action_added (node->data,
+ G_ACTION_OBSERVABLE (group->muxer),
+ fullname, parameter_type, enabled, state);
+
+ g_action_group_action_added (G_ACTION_GROUP (group->muxer), fullname);
+
+ if (state)
+ g_variant_unref (state);
+
+ g_free (fullname);
+ }
+}
+
+static void
+g_action_muxer_action_removed (GActionGroup *action_group,
+ const gchar *action_name,
+ gpointer user_data)
+{
+ Group *group = user_data;
+ gchar *fullname;
+ Action *action;
+ GSList *node;
+
+ action = g_action_muxer_lookup_action (group->muxer, group->prefix, action_name, &fullname);
+ for (node = action ? action->watchers : NULL; node; node = node->next)
+ g_action_observer_action_removed (node->data, G_ACTION_OBSERVABLE (group->muxer), fullname);
+ g_action_group_action_removed (G_ACTION_GROUP (group->muxer), fullname);
+ g_free (fullname);
+}
+
+static gboolean
+g_action_muxer_query_action (GActionGroup *action_group,
+ const gchar *action_name,
+ gboolean *enabled,
+ const GVariantType **parameter_type,
+ const GVariantType **state_type,
+ GVariant **state_hint,
+ GVariant **state)
+{
+ GActionMuxer *muxer = G_ACTION_MUXER (action_group);
+ Group *group;
+
+ group = g_action_muxer_find_group (muxer, &action_name);
+
+ if (!group)
+ return FALSE;
+
+ return g_action_group_query_action (group->group, action_name, enabled,
+ parameter_type, state_type, state_hint, state);
+}
+
+static void
+g_action_muxer_activate_action (GActionGroup *action_group,
+ const gchar *action_name,
+ GVariant *parameter)
+{
+ GActionMuxer *muxer = G_ACTION_MUXER (action_group);
+ Group *group;
+
+ group = g_action_muxer_find_group (muxer, &action_name);
+
+ if (group)
+ g_action_group_activate_action (group->group, action_name, parameter);
+}
+
+static void
+g_action_muxer_change_action_state (GActionGroup *action_group,
+ const gchar *action_name,
+ GVariant *state)
+{
+ GActionMuxer *muxer = G_ACTION_MUXER (action_group);
+ Group *group;
+
+ group = g_action_muxer_find_group (muxer, &action_name);
+
+ if (group)
+ g_action_group_change_action_state (group->group, action_name, state);
+}
+
+static void
+g_action_muxer_unregister_internal (Action *action,
+ gpointer observer)
+{
+ GActionMuxer *muxer = action->muxer;
+ GSList **ptr;
+
+ for (ptr = &action->watchers; *ptr; ptr = &(*ptr)->next)
+ if ((*ptr)->data == observer)
+ {
+ *ptr = g_slist_remove (*ptr, observer);
+
+ if (action->watchers == NULL)
+ {
+ g_hash_table_remove (muxer->actions, action->fullname);
+ g_free (action->fullname);
+
+ g_slice_free (Action, action);
+
+ g_object_unref (muxer);
+ }
+
+ break;
+ }
+}
+
+static void
+g_action_muxer_weak_notify (gpointer data,
+ GObject *where_the_object_was)
+{
+ Action *action = data;
+
+ g_action_muxer_unregister_internal (action, where_the_object_was);
+}
+
+static void
+g_action_muxer_register_observer (GActionObservable *observable,
+ const gchar *name,
+ GActionObserver *observer)
+{
+ GActionMuxer *muxer = G_ACTION_MUXER (observable);
+ Action *action;
+
+ action = g_hash_table_lookup (muxer->actions, name);
+
+ if (action == NULL)
+ {
+ action = g_slice_new (Action);
+ action->muxer = g_object_ref (muxer);
+ action->fullname = g_strdup (name);
+ action->watchers = NULL;
+
+ g_hash_table_insert (muxer->actions, action->fullname, action);
+ }
+
+ action->watchers = g_slist_prepend (action->watchers, observer);
+ g_object_weak_ref (G_OBJECT (observer), g_action_muxer_weak_notify, action);
+}
+
+static void
+g_action_muxer_unregister_observer (GActionObservable *observable,
+ const gchar *name,
+ GActionObserver *observer)
+{
+ GActionMuxer *muxer = G_ACTION_MUXER (observable);
+ Action *action;
+
+ action = g_hash_table_lookup (muxer->actions, name);
+ g_object_weak_unref (G_OBJECT (observer), g_action_muxer_weak_notify, action);
+ g_action_muxer_unregister_internal (action, observer);
+}
+
+static void
+g_action_muxer_free_group (gpointer data)
+{
+ Group *group = data;
+
+ g_object_unref (group->group);
+ g_free (group->prefix);
+
+ g_slice_free (Group, group);
+}
+
+static void
+g_action_muxer_finalize (GObject *object)
+{
+ GActionMuxer *muxer = G_ACTION_MUXER (object);
+
+ g_assert_cmpint (g_hash_table_size (muxer->actions), ==, 0);
+ g_hash_table_unref (muxer->actions);
+ g_hash_table_unref (muxer->groups);
+
+ G_OBJECT_CLASS (g_action_muxer_parent_class)
+ ->finalize (object);
+}
+
+static void
+g_action_muxer_init (GActionMuxer *muxer)
+{
+ muxer->actions = g_hash_table_new (g_str_hash, g_str_equal);
+ muxer->groups = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_action_muxer_free_group);
+}
+
+static void
+g_action_muxer_observable_iface_init (GActionObservableInterface *iface)
+{
+ iface->register_observer = g_action_muxer_register_observer;
+ iface->unregister_observer = g_action_muxer_unregister_observer;
+}
+
+static void
+g_action_muxer_group_iface_init (GActionGroupInterface *iface)
+{
+ iface->list_actions = g_action_muxer_list_actions;
+ iface->query_action = g_action_muxer_query_action;
+ iface->activate_action = g_action_muxer_activate_action;
+ iface->change_action_state = g_action_muxer_change_action_state;
+}
+
+static void
+g_action_muxer_class_init (GObjectClass *class)
+{
+ class->finalize = g_action_muxer_finalize;
+}
+
+/**
+ * g_action_muxer_insert:
+ * @muxer: a #GActionMuxer
+ * @prefix: the prefix string for the action group
+ * @action_group: a #GActionGroup
+ *
+ * Adds the actions in @action_group to the list of actions provided by
+ * @muxer. @prefix is prefixed to each action name, such that for each
+ * action <varname>x</varname> in @action_group, there is an equivalent
+ * action @prefix<literal>.</literal><varname>x</varname> in @muxer.
+ *
+ * For example, if @prefix is "<literal>app</literal>" and @action_group
+ * contains an action called "<literal>quit</literal>", then @muxer will
+ * now contain an action called "<literal>app.quit</literal>".
+ *
+ * If any #GActionObservers are registered for actions in the group,
+ * "action_added" notifications will be emitted, as appropriate.
+ *
+ * @prefix must not contain a dot ('.').
+ *
+ * Since: 2.32
+ **/
+void
+g_action_muxer_insert (GActionMuxer *muxer,
+ const gchar *prefix,
+ GActionGroup *action_group)
+{
+ gchar **actions;
+ Group *group;
+ gint i;
+
+ /* TODO: diff instead of ripout and replace */
+ g_action_muxer_remove (muxer, prefix);
+
+ group = g_slice_new (Group);
+ group->muxer = muxer;
+ group->group = g_object_ref (action_group);
+ group->prefix = g_strdup (prefix);
+
+ g_hash_table_insert (muxer->groups, group->prefix, group);
+
+ actions = g_action_group_list_actions (group->group);
+ for (i = 0; actions[i]; i++)
+ g_action_muxer_action_added (group->group, actions[i], group);
+ g_strfreev (actions);
+
+ group->handler_ids[0] = g_signal_connect (group->group, "action-added",
+ G_CALLBACK (g_action_muxer_action_added), group);
+ group->handler_ids[1] = g_signal_connect (group->group, "action-removed",
+ G_CALLBACK (g_action_muxer_action_removed), group);
+ group->handler_ids[2] = g_signal_connect (group->group, "action-enabled-changed",
+ G_CALLBACK (g_action_muxer_action_enabled_changed), group);
+ group->handler_ids[3] = g_signal_connect (group->group, "action-state-changed",
+ G_CALLBACK (g_action_muxer_action_state_changed), group);
+}
+
+/**
+ * g_action_muxer_remove:
+ * @muxer: a #GActionMuxer
+ * @prefix: the prefix of the action group to remove
+ *
+ * Removes a #GActionGroup from the #GActionMuxer.
+ *
+ * If any #GActionObservers are registered for actions in the group,
+ * "action_removed" notifications will be emitted, as appropriate.
+ *
+ * Since: 2.32
+ **/
+void
+g_action_muxer_remove (GActionMuxer *muxer,
+ const gchar *prefix)
+{
+ Group *group;
+
+ group = g_hash_table_lookup (muxer->groups, prefix);
+
+ if (group != NULL)
+ {
+ gchar **actions;
+ gint i;
+
+ g_hash_table_steal (muxer->groups, prefix);
+
+ actions = g_action_group_list_actions (group->group);
+ for (i = 0; actions[i]; i++)
+ g_action_muxer_action_removed (group->group, actions[i], group);
+ g_strfreev (actions);
+
+ /* 'for loop' or 'four loop'? */
+ for (i = 0; i < 4; i++)
+ g_signal_handler_disconnect (group->group, group->handler_ids[i]);
+
+ g_action_muxer_free_group (group);
+ }
+}
+
+/**
+ * g_action_muxer_new:
+ *
+ * Creates a new #GActionMuxer.
+ *
+ * Since: 2.32
+ **/
+GActionMuxer *
+g_action_muxer_new (void)
+{
+ return g_object_new (G_TYPE_ACTION_MUXER, NULL);
+}
diff --git a/gtk/gactionmuxer.h b/gtk/gactionmuxer.h
new file mode 100644
index 0000000..adafd03
--- /dev/null
+++ b/gtk/gactionmuxer.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright  2011 Canonical Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Ryan Lortie <desrt desrt ca>
+ */
+
+#ifndef __G_ACTION_MUXER_H__
+#define __G_ACTION_MUXER_H__
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_ACTION_MUXER (g_action_muxer_get_type ())
+#define G_ACTION_MUXER(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
+ G_TYPE_ACTION_MUXER, GActionMuxer))
+#define G_IS_ACTION_MUXER(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
+ G_TYPE_ACTION_MUXER))
+
+typedef struct _GActionMuxer GActionMuxer;
+
+G_GNUC_INTERNAL
+GType g_action_muxer_get_type (void);
+G_GNUC_INTERNAL
+GActionMuxer * g_action_muxer_new (void);
+
+G_GNUC_INTERNAL
+void g_action_muxer_insert (GActionMuxer *muxer,
+ const gchar *prefix,
+ GActionGroup *group);
+
+G_GNUC_INTERNAL
+void g_action_muxer_remove (GActionMuxer *muxer,
+ const gchar *prefix);
+
+G_END_DECLS
+
+#endif /* __G_ACTION_MUXER_H__ */
diff --git a/gtk/gactionobservable.c b/gtk/gactionobservable.c
new file mode 100644
index 0000000..11ed63b
--- /dev/null
+++ b/gtk/gactionobservable.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright  2011 Canonical Limited
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * licence or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ */
+
+#include "config.h"
+
+#include "gactionobservable.h"
+
+G_DEFINE_INTERFACE (GActionObservable, g_action_observable, G_TYPE_OBJECT)
+
+/**
+ * SECTION:gactionobserable
+ * @short_description: an interface implemented by objects that report
+ * changes to actions
+ *
+ * Since: 2.32
+ */
+
+void
+g_action_observable_default_init (GActionObservableInterface *iface)
+{
+}
+
+/**
+ * g_action_observable_register_observer:
+ * @observable: a #GActionObservable
+ * @action_name: the name of the action
+ * @observer: the #GActionObserver to which the events will be reported
+ *
+ * Registers @observer as being interested in changes to @action_name on
+ * @observable.
+ *
+ * Since: 2.32
+ **/
+void
+g_action_observable_register_observer (GActionObservable *observable,
+ const gchar *action_name,
+ GActionObserver *observer)
+{
+ g_return_if_fail (G_IS_ACTION_OBSERVABLE (observable));
+
+ G_ACTION_OBSERVABLE_GET_IFACE (observable)
+ ->register_observer (observable, action_name, observer);
+}
+
+/**
+ * g_action_observable_unregister_observer:
+ * @observable: a #GActionObservable
+ * @action_name: the name of the action
+ * @observer: the #GActionObserver to which the events will be reported
+ *
+ * Removes the registration of @observer as being interested in changes
+ * to @action_name on @observable.
+ *
+ * If the observer was registered multiple times, it must be
+ * unregistered an equal number of times.
+ *
+ * Since: 2.32
+ **/
+void
+g_action_observable_unregister_observer (GActionObservable *observable,
+ const gchar *action_name,
+ GActionObserver *observer)
+{
+ g_return_if_fail (G_IS_ACTION_OBSERVABLE (observable));
+
+ G_ACTION_OBSERVABLE_GET_IFACE (observable)
+ ->unregister_observer (observable, action_name, observer);
+}
diff --git a/gtk/gactionobservable.h b/gtk/gactionobservable.h
new file mode 100644
index 0000000..ae6ac31
--- /dev/null
+++ b/gtk/gactionobservable.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright  2011 Canonical Limited
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * licence or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ */
+
+#ifndef __G_ACTION_OBSERVABLE_H__
+#define __G_ACTION_OBSERVABLE_H__
+
+#include <gtk/gactionobserver.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_ACTION_OBSERVABLE (g_action_observable_get_type ())
+#define G_ACTION_OBSERVABLE(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
+ G_TYPE_ACTION_OBSERVABLE, GActionObservable))
+#define G_IS_ACTION_OBSERVABLE(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
+ G_TYPE_ACTION_OBSERVABLE))
+#define G_ACTION_OBSERVABLE_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), \
+ G_TYPE_ACTION_OBSERVABLE, GActionObservableInterface))
+
+typedef struct _GActionObservableInterface GActionObservableInterface;
+
+struct _GActionObservableInterface
+{
+ GTypeInterface g_iface;
+
+ void (* register_observer) (GActionObservable *observable,
+ const gchar *action_name,
+ GActionObserver *observer);
+ void (* unregister_observer) (GActionObservable *observable,
+ const gchar *action_name,
+ GActionObserver *observer);
+};
+
+G_GNUC_INTERNAL
+GType g_action_observable_get_type (void);
+G_GNUC_INTERNAL
+void g_action_observable_register_observer (GActionObservable *observable,
+ const gchar *action_name,
+ GActionObserver *observer);
+G_GNUC_INTERNAL
+void g_action_observable_unregister_observer (GActionObservable *observable,
+ const gchar *action_name,
+ GActionObserver *observer);
+
+G_END_DECLS
+
+#endif /* __G_ACTION_OBSERVABLE_H__ */
diff --git a/gtk/gactionobserver.c b/gtk/gactionobserver.c
new file mode 100644
index 0000000..c9d4176
--- /dev/null
+++ b/gtk/gactionobserver.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright  2011 Canonical Limited
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * licence or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ */
+
+#include "config.h"
+
+#include "gactionobserver.h"
+
+G_DEFINE_INTERFACE (GActionObserver, g_action_observer, G_TYPE_OBJECT)
+
+/**
+ * SECTION:gactionobserver
+ * @short_description: an interface implemented by objects that are
+ * interested in monitoring actions for changes
+ *
+ * GActionObserver is a simple interface allowing objects that wish to
+ * be notified of changes to actions to be notified of those changes.
+ *
+ * It is also possible to monitor changes to action groups using
+ * #GObject signals, but there are a number of reasons that this
+ * approach could become problematic:
+ *
+ * - there are four separate signals that must be manually connected
+ * and disconnected
+ *
+ * - when a large number of different observers wish to monitor a
+ * (usually disjoint) set of actions within the same action group,
+ * there is only one way to avoid having all notifications delivered
+ * to all observers: signal detail. In order to use signal detail,
+ * each action name must be quarked, which is not always practical.
+ *
+ * - even if quarking is acceptable, #GObject signal details are
+ * implemented by scanning a linked list, so there is no real
+ * decrease in complexity
+ *
+ * Since: 2.32
+ */
+
+void
+g_action_observer_default_init (GActionObserverInterface *class)
+{
+}
+
+/**
+ * g_action_observer_action_added:
+ * @observer: a #GActionObserver
+ * @observable: the source of the event
+ * @action_name: the name of the action
+ * @enabled: %TRUE if the action is now enabled
+ * @parameter_type: the parameter type for action invocations, or %NULL
+ * if no parameter is required
+ * @state: the current state of the action, or %NULL if the action is
+ * stateless
+ *
+ * This function is called when an action that the observer is
+ * registered to receive events for is added.
+ *
+ * This function should only be called by objects with which the
+ * observer has explicitly registered itself to receive events.
+ *
+ * Since: 2.32
+ **/
+void
+g_action_observer_action_added (GActionObserver *observer,
+ GActionObservable *observable,
+ const gchar *action_name,
+ const GVariantType *parameter_type,
+ gboolean enabled,
+ GVariant *state)
+{
+ g_return_if_fail (G_IS_ACTION_OBSERVER (observer));
+
+ G_ACTION_OBSERVER_GET_IFACE (observer)
+ ->action_added (observer, observable, action_name, parameter_type, enabled, state);
+}
+
+/**
+ * g_action_observer_action_enabled_changed:
+ * @observer: a #GActionObserver
+ * @observable: the source of the event
+ * @action_name: the name of the action
+ * @enabled: %TRUE if the action is now enabled
+ *
+ * This function is called when an action that the observer is
+ * registered to receive events for becomes enabled or disabled.
+ *
+ * This function should only be called by objects with which the
+ * observer has explicitly registered itself to receive events.
+ *
+ * Since: 2.32
+ **/
+void
+g_action_observer_action_enabled_changed (GActionObserver *observer,
+ GActionObservable *observable,
+ const gchar *action_name,
+ gboolean enabled)
+{
+ g_return_if_fail (G_IS_ACTION_OBSERVER (observer));
+
+ G_ACTION_OBSERVER_GET_IFACE (observer)
+ ->action_enabled_changed (observer, observable, action_name, enabled);
+}
+
+/**
+ * g_action_observer_action_state_changed:
+ * @observer: a #GActionObserver
+ * @observable: the source of the event
+ * @action_name: the name of the action
+ * @state: the new state of the action
+ *
+ * This function is called when an action that the observer is
+ * registered to receive events for changes its state.
+ *
+ * This function should only be called by objects with which the
+ * observer has explicitly registered itself to receive events.
+ *
+ * Since: 2.32
+ **/
+void
+g_action_observer_action_state_changed (GActionObserver *observer,
+ GActionObservable *observable,
+ const gchar *action_name,
+ GVariant *state)
+{
+ g_return_if_fail (G_IS_ACTION_OBSERVER (observer));
+
+ G_ACTION_OBSERVER_GET_IFACE (observer)
+ ->action_state_changed (observer, observable, action_name, state);
+}
+
+/**
+ * g_action_observer_action_removed:
+ * @observer: a #GActionObserver
+ * @observable: the source of the event
+ * @action_name: the name of the action
+ *
+ * This function is called when an action that the observer is
+ * registered to receive events for is removed.
+ *
+ * This function should only be called by objects with which the
+ * observer has explicitly registered itself to receive events.
+ *
+ * Since: 2.32
+ **/
+void
+g_action_observer_action_removed (GActionObserver *observer,
+ GActionObservable *observable,
+ const gchar *action_name)
+{
+ g_return_if_fail (G_IS_ACTION_OBSERVER (observer));
+
+ G_ACTION_OBSERVER_GET_IFACE (observer)
+ ->action_removed (observer, observable, action_name);
+}
diff --git a/gtk/gactionobserver.h b/gtk/gactionobserver.h
new file mode 100644
index 0000000..eb15c3a
--- /dev/null
+++ b/gtk/gactionobserver.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright  2011 Canonical Limited
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * licence or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ */
+
+#ifndef __G_ACTION_OBSERVER_H__
+#define __G_ACTION_OBSERVER_H__
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_ACTION_OBSERVER (g_action_observer_get_type ())
+#define G_ACTION_OBSERVER(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
+ G_TYPE_ACTION_OBSERVER, GActionObserver))
+#define G_IS_ACTION_OBSERVER(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
+ G_TYPE_ACTION_OBSERVER))
+#define G_ACTION_OBSERVER_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), \
+ G_TYPE_ACTION_OBSERVER, GActionObserverInterface))
+
+typedef struct _GActionObserverInterface GActionObserverInterface;
+typedef struct _GActionObservable GActionObservable;
+typedef struct _GActionObserver GActionObserver;
+
+struct _GActionObserverInterface
+{
+ GTypeInterface g_iface;
+
+ void (* action_added) (GActionObserver *observer,
+ GActionObservable *observable,
+ const gchar *action_name,
+ const GVariantType *parameter_type,
+ gboolean enabled,
+ GVariant *state);
+ void (* action_enabled_changed) (GActionObserver *observer,
+ GActionObservable *observable,
+ const gchar *action_name,
+ gboolean enabled);
+ void (* action_state_changed) (GActionObserver *observer,
+ GActionObservable *observable,
+ const gchar *action_name,
+ GVariant *state);
+ void (* action_removed) (GActionObserver *observer,
+ GActionObservable *observable,
+ const gchar *action_name);
+};
+
+G_GNUC_INTERNAL
+GType g_action_observer_get_type (void);
+G_GNUC_INTERNAL
+void g_action_observer_action_added (GActionObserver *observer,
+ GActionObservable *observable,
+ const gchar *action_name,
+ const GVariantType *parameter_type,
+ gboolean enabled,
+ GVariant *state);
+G_GNUC_INTERNAL
+void g_action_observer_action_enabled_changed (GActionObserver *observer,
+ GActionObservable *observable,
+ const gchar *action_name,
+ gboolean enabled);
+G_GNUC_INTERNAL
+void g_action_observer_action_state_changed (GActionObserver *observer,
+ GActionObservable *observable,
+ const gchar *action_name,
+ GVariant *state);
+G_GNUC_INTERNAL
+void g_action_observer_action_removed (GActionObserver *observer,
+ GActionObservable *observable,
+ const gchar *action_name);
+
+G_END_DECLS
+
+#endif /* __G_ACTION_OBSERVER_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]