[glib/wip/gmenu] GDBusActionGroup: make API just like GDBusMenuModel
- From: Ryan Lortie <ryanl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/wip/gmenu] GDBusActionGroup: make API just like GDBusMenuModel
- Date: Thu, 8 Dec 2011 22:52:20 +0000 (UTC)
commit 7e2bfe03d8c51643ba1e4b58c02ee04f49a3a0cd
Author: Ryan Lortie <desrt desrt ca>
Date: Thu Dec 8 17:49:01 2011 -0500
GDBusActionGroup: make API just like GDBusMenuModel
Have one simple _get() API that returns the group immediately, in an
empty state. The group is initialised on the first attempt to interact
with it.
Leave a secret 'back door' for GApplication to do a blocking
initialisation.
gio/gapplicationimpl-dbus.c | 12 +-
gio/gdbusactiongroup.c | 431 ++++++++++++++++++++-----------------------
gio/gdbusactiongroup.h | 16 +--
gio/tests/actions.c | 18 +--
4 files changed, 217 insertions(+), 260 deletions(-)
---
diff --git a/gio/gapplicationimpl-dbus.c b/gio/gapplicationimpl-dbus.c
index 9edac53..3d15f52 100644
--- a/gio/gapplicationimpl-dbus.c
+++ b/gio/gapplicationimpl-dbus.c
@@ -37,6 +37,12 @@
#include "gapplicationcommandline.h"
#include "gdbusmethodinvocation.h"
+G_GNUC_INTERNAL gboolean
+g_dbus_action_group_sync (GDBusActionGroup *group,
+ GCancellable *cancellable,
+ GError **error);
+
+
/* DBus Interface definition {{{1 */
static const gchar org_gtk_Application_xml[] =
"<node>"
@@ -526,12 +532,12 @@ g_application_impl_register (GApplication *application,
* This also serves as a mechanism to ensure that the primary exists
* (ie: DBus service files installed correctly, etc).
*/
- actions = g_dbus_action_group_new_sync (impl->session_bus, impl->bus_name, impl->object_path, cancellable, error);
-
- if (actions == NULL)
+ actions = g_dbus_action_group_get (impl->session_bus, impl->bus_name, impl->object_path);
+ if (!g_dbus_action_group_sync (actions, cancellable, error))
{
/* The primary appears not to exist. Fail the registration. */
g_application_impl_destroy (impl);
+ g_object_unref (actions);
return NULL;
}
diff --git a/gio/gdbusactiongroup.c b/gio/gdbusactiongroup.c
index 7dde041..dd6646e 100644
--- a/gio/gdbusactiongroup.c
+++ b/gio/gdbusactiongroup.c
@@ -22,13 +22,11 @@
#include "config.h"
-#include "gsimpleasyncresult.h"
#include "gdbusactiongroup.h"
+
#include "gdbusconnection.h"
-#include "gasyncinitable.h"
#include "gactiongroup.h"
-
/**
* SECTION:gdbusactiongroup
* @title: GDBusActionGroup
@@ -128,136 +126,6 @@ static void g_dbus_action_group_iface_init (GActionGroupInterface *);
G_DEFINE_TYPE_WITH_CODE (GDBusActionGroup, g_dbus_action_group, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP, g_dbus_action_group_iface_init))
-static gchar **
-g_dbus_action_group_list_actions (GActionGroup *g_group)
-{
- GDBusActionGroup *group = G_DBUS_ACTION_GROUP (g_group);
- GHashTableIter iter;
- gint n, i = 0;
- gchar **keys;
- gpointer key;
-
- n = g_hash_table_size (group->actions);
- keys = g_new (gchar *, n + 1);
-
- g_hash_table_iter_init (&iter, group->actions);
- while (g_hash_table_iter_next (&iter, &key, NULL))
- keys[i++] = g_strdup (key);
- g_assert_cmpint (i, ==, n);
- keys[n] = NULL;
-
- group->strict = TRUE;
-
- return keys;
-}
-
-static gboolean
-g_dbus_action_group_query_action (GActionGroup *g_group,
- const gchar *action_name,
- gboolean *enabled,
- const GVariantType **parameter_type,
- const GVariantType **state_type,
- GVariant **state_hint,
- GVariant **state)
-{
- GDBusActionGroup *group = G_DBUS_ACTION_GROUP (g_group);
- ActionInfo *info;
-
- info = g_hash_table_lookup (group->actions, action_name);
-
- if (info == NULL)
- {
- group->strict = TRUE;
- return FALSE;
- }
-
- if (enabled)
- *enabled = info->enabled;
-
- if (parameter_type)
- *parameter_type = info->parameter_type;
-
- if (state_type)
- *state_type = info->state ? g_variant_get_type (info->state) : NULL;
-
- if (state_hint)
- *state_hint = NULL;
-
- if (state)
- *state = info->state ? g_variant_ref (info->state) : NULL;
-
- return TRUE;
-}
-
-static void
-g_dbus_action_group_change_state (GActionGroup *g_group,
- const gchar *action_name,
- GVariant *value)
-{
- GDBusActionGroup *group = G_DBUS_ACTION_GROUP (g_group);
-
- /* Don't bother with the checks. The other side will do it again. */
- g_dbus_connection_call (group->connection, group->bus_name, group->object_path, "org.gtk.Actions", "SetState",
- g_variant_new ("(sva{sv})", action_name, value, NULL),
- NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
-}
-
-static void
-g_dbus_action_group_activate (GActionGroup *g_group,
- const gchar *action_name,
- GVariant *parameter)
-{
- GDBusActionGroup *group = G_DBUS_ACTION_GROUP (g_group);
- GVariantBuilder builder;
-
- g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
-
- if (parameter)
- g_variant_builder_add (&builder, "v", parameter);
-
- g_dbus_connection_call (group->connection, group->bus_name, group->object_path, "org.gtk.Actions", "Activate",
- g_variant_new ("(sava{sv})", action_name, &builder, NULL),
- NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
-}
-
-static void
-g_dbus_action_group_finalize (GObject *object)
-{
- GDBusActionGroup *group = G_DBUS_ACTION_GROUP (object);
-
- g_dbus_connection_signal_unsubscribe (group->connection, group->subscription_id);
- g_hash_table_unref (group->actions);
- g_object_unref (group->connection);
- g_free (group->object_path);
- g_free (group->bus_name);
-
- G_OBJECT_CLASS (g_dbus_action_group_parent_class)
- ->finalize (object);
-}
-
-static void
-g_dbus_action_group_init (GDBusActionGroup *group)
-{
- group->actions = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, action_info_free);
-}
-
-static void
-g_dbus_action_group_class_init (GDBusActionGroupClass *class)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (class);
-
- object_class->finalize = g_dbus_action_group_finalize;
-}
-
-static void
-g_dbus_action_group_iface_init (GActionGroupInterface *iface)
-{
- iface->list_actions = g_dbus_action_group_list_actions;
- iface->query_action = g_dbus_action_group_query_action;
- iface->change_action_state = g_dbus_action_group_change_state;
- iface->activate_action = g_dbus_action_group_activate;
-}
-
static void
g_dbus_action_group_changed (GDBusConnection *connection,
const gchar *sender,
@@ -270,6 +138,10 @@ g_dbus_action_group_changed (GDBusConnection *connection,
GDBusActionGroup *group = user_data;
GActionGroup *g_group = user_data;
+ /* make sure that we've been fully initialised */
+ if (group->actions == NULL)
+ return;
+
if (g_str_equal (signal_name, "Changed") &&
g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(asa{sb}a{sv}a{s(bgav)})")))
{
@@ -361,20 +233,20 @@ g_dbus_action_group_changed (GDBusConnection *connection,
}
}
+
static void
g_dbus_action_group_describe_all_done (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
- GSimpleAsyncResult *my_result = user_data;
- GDBusActionGroup *group;
- GError *error = NULL;
+ GDBusActionGroup *group= user_data;
GVariant *reply;
- group = g_simple_async_result_get_op_res_gpointer (my_result);
- g_assert (G_IS_DBUS_ACTION_GROUP (group));
+ g_assert (group->actions == NULL);
+ group->actions = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, action_info_free);
+
g_assert (group->connection == (gpointer) source);
- reply = g_dbus_connection_call_finish (group->connection, result, &error);
+ reply = g_dbus_connection_call_finish (group->connection, result, NULL);
if (reply != NULL)
{
@@ -383,130 +255,238 @@ g_dbus_action_group_describe_all_done (GObject *source,
g_variant_get (reply, "(a{s(bgav)})", &iter);
while ((action = action_info_new_from_iter (iter)))
- g_hash_table_insert (group->actions, action->name, action);
+ {
+ g_hash_table_insert (group->actions, action->name, action);
+
+ if (group->strict)
+ g_action_group_action_added (G_ACTION_GROUP (group), action->name);
+ }
g_variant_iter_free (iter);
g_variant_unref (reply);
}
+}
+
+
+static void
+g_dbus_action_group_async_init (GDBusActionGroup *group)
+{
+ if (group->subscription_id != 0)
+ return;
+
+ group->subscription_id =
+ g_dbus_connection_signal_subscribe (group->connection, group->bus_name, "org.gtk.Actions", "Changed", group->object_path,
+ NULL, G_DBUS_SIGNAL_FLAGS_NONE, g_dbus_action_group_changed, group, NULL);
+
+ g_dbus_connection_call (group->connection, group->bus_name, group->object_path, "org.gtk.Actions", "DescribeAll", NULL,
+ G_VARIANT_TYPE ("(a{s(bgav)})"), G_DBUS_CALL_FLAGS_NONE, -1, NULL,
+ g_dbus_action_group_describe_all_done, group);
+}
+
+static gchar **
+g_dbus_action_group_list_actions (GActionGroup *g_group)
+{
+ GDBusActionGroup *group = G_DBUS_ACTION_GROUP (g_group);
+ gchar **keys;
+
+ if (group->actions != NULL)
+ {
+ GHashTableIter iter;
+ gint n, i = 0;
+ gpointer key;
+
+ n = g_hash_table_size (group->actions);
+ keys = g_new (gchar *, n + 1);
+
+ g_hash_table_iter_init (&iter, group->actions);
+ while (g_hash_table_iter_next (&iter, &key, NULL))
+ keys[i++] = g_strdup (key);
+ g_assert_cmpint (i, ==, n);
+ keys[n] = NULL;
+ }
else
{
- g_simple_async_result_set_from_error (my_result, error);
- g_error_free (error);
+ g_dbus_action_group_async_init (group);
+ keys = g_new0 (gchar *, 1);
}
- g_simple_async_result_complete (my_result);
- g_object_unref (my_result);
+ group->strict = TRUE;
+
+ return keys;
}
-/**
- * g_dbus_action_group_new:
- * @connection: A #GDBusConnection
- * @bus_name: the bus name which exports the action group
- * @object_path: the object path at which the action group is exported
- * @cancellable: A #GCancellable or %NULL
- * @callback: Callback function to invoke when the object is ready
- * @user_data: User data to pass to @callback
- *
- * Creates a new, empty, #GDBusActionGroup.
- *
- * This is a failable asynchronous constructor - when the object
- * is ready, @callback will be invoked and you can use
- * g_dbus_action_group_new_finish() to get the result.
- *
- * See g_dbus_action_group_new_sync() and for a synchronous version
- * of this constructor.
- */
-void
-g_dbus_action_group_new (GDBusConnection *connection,
- const gchar *bus_name,
- const gchar *object_path,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+static gboolean
+g_dbus_action_group_query_action (GActionGroup *g_group,
+ const gchar *action_name,
+ gboolean *enabled,
+ const GVariantType **parameter_type,
+ const GVariantType **state_type,
+ GVariant **state_hint,
+ GVariant **state)
{
- GSimpleAsyncResult *result;
- GDBusActionGroup *group;
+ GDBusActionGroup *group = G_DBUS_ACTION_GROUP (g_group);
+ ActionInfo *info;
- group = g_object_new (G_TYPE_DBUS_ACTION_GROUP, NULL);
- group->connection = g_object_ref (connection);
- group->bus_name = g_strdup (bus_name);
- group->object_path = g_strdup (object_path);
+ if (group->actions != NULL)
+ {
+ info = g_hash_table_lookup (group->actions, action_name);
- /* It's probably excessive to worry about watching the name ownership.
- * The person using this class will know for themselves when the name
- * disappears.
- */
+ if (info == NULL)
+ {
+ group->strict = TRUE;
+ return FALSE;
+ }
- result = g_simple_async_result_new (G_OBJECT (group), callback, user_data, g_dbus_action_group_new);
- g_simple_async_result_set_op_res_gpointer (result, group, g_object_unref);
+ if (enabled)
+ *enabled = info->enabled;
- group->subscription_id =
- g_dbus_connection_signal_subscribe (connection, bus_name, "org.gtk.Actions", "Changed", object_path, NULL,
- G_DBUS_SIGNAL_FLAGS_NONE, g_dbus_action_group_changed, group, NULL);
+ if (parameter_type)
+ *parameter_type = info->parameter_type;
+
+ if (state_type)
+ *state_type = info->state ? g_variant_get_type (info->state) : NULL;
+
+ if (state_hint)
+ *state_hint = NULL;
+
+ if (state)
+ *state = info->state ? g_variant_ref (info->state) : NULL;
+
+ return TRUE;
+ }
+ else
+ {
+ g_dbus_action_group_async_init (group);
- g_dbus_connection_call (connection, bus_name, object_path, "org.gtk.Actions", "DescribeAll", NULL,
- G_VARIANT_TYPE ("(a{s(bgav)})"), G_DBUS_CALL_FLAGS_NONE, -1, cancellable,
- g_dbus_action_group_describe_all_done, result);
+ return FALSE;
+ }
}
-/**
- * g_dbus_action_group_new_finish:
- * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback
- * function passed to g_dbus_action_group_new()
- * @error: Return location for error or %NULL
- *
- * Finishes creating a #GDBusActionGroup.
- *
- * Returns: A #GDBusProxy or %NULL if @error is set. Free with g_object_unref().
- */
-GDBusActionGroup *
-g_dbus_action_group_new_finish (GAsyncResult *result,
- GError **error)
+static void
+g_dbus_action_group_change_state (GActionGroup *g_group,
+ const gchar *action_name,
+ GVariant *value)
{
- GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
+ GDBusActionGroup *group = G_DBUS_ACTION_GROUP (g_group);
- g_return_val_if_fail (g_simple_async_result_is_valid (result,
- g_simple_async_result_get_op_res_gpointer (simple),
- g_dbus_action_group_new), NULL);
+ /* Don't bother with the checks. The other side will do it again. */
+ g_dbus_connection_call (group->connection, group->bus_name, group->object_path, "org.gtk.Actions", "SetState",
+ g_variant_new ("(sva{sv})", action_name, value, NULL),
+ NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
+}
- if (g_simple_async_result_propagate_error (simple, error))
- return NULL;
+static void
+g_dbus_action_group_activate (GActionGroup *g_group,
+ const gchar *action_name,
+ GVariant *parameter)
+{
+ GDBusActionGroup *group = G_DBUS_ACTION_GROUP (g_group);
+ GVariantBuilder builder;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
+
+ if (parameter)
+ g_variant_builder_add (&builder, "v", parameter);
+
+ g_dbus_connection_call (group->connection, group->bus_name, group->object_path, "org.gtk.Actions", "Activate",
+ g_variant_new ("(sava{sv})", action_name, &builder, NULL),
+ NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
+}
+
+static void
+g_dbus_action_group_finalize (GObject *object)
+{
+ GDBusActionGroup *group = G_DBUS_ACTION_GROUP (object);
+
+ if (group->subscription_id)
+ g_dbus_connection_signal_unsubscribe (group->connection, group->subscription_id);
+
+ if (group->actions)
+ g_hash_table_unref (group->actions);
+
+ g_object_unref (group->connection);
+ g_free (group->object_path);
+ g_free (group->bus_name);
+
+ G_OBJECT_CLASS (g_dbus_action_group_parent_class)
+ ->finalize (object);
+}
+
+static void
+g_dbus_action_group_init (GDBusActionGroup *group)
+{
+}
- return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
+static void
+g_dbus_action_group_class_init (GDBusActionGroupClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->finalize = g_dbus_action_group_finalize;
+}
+
+static void
+g_dbus_action_group_iface_init (GActionGroupInterface *iface)
+{
+ iface->list_actions = g_dbus_action_group_list_actions;
+ iface->query_action = g_dbus_action_group_query_action;
+ iface->change_action_state = g_dbus_action_group_change_state;
+ iface->activate_action = g_dbus_action_group_activate;
}
/**
- * g_dbus_action_group_new_sync:
+ * g_dbus_action_group_get:
* @connection: A #GDBusConnection
* @bus_name: the bus name which exports the action group
* @object_path: the object path at which the action group is exported
* @cancellable: A #GCancellable or %NULL
- * @error: Return location for error or %NULL
+ * @callback: Callback function to invoke when the object is ready
+ * @user_data: User data to pass to @callback
*
- * This is a synchronous failable constructor. See g_dbus_action_group_new()
- * and g_dbus_action_group_new_finish() for the asynchronous version.
+ * Obtains a #GDBusAcitonGroup for the aciton group which is exported at
+ * the given @bus_name and @object_path.
*
- * Returns: A #GDBusProxy or %NULL if @error is set. Free with g_object_unref().
- */
+ * The thread default main context is taken at the time of this call.
+ * All signals on the menu model (and any linked models) are reported
+ * with respect to this context. All calls on the returned menu model
+ * (and linked models) must also originate from this same context, with
+ * the thread default main context unchanged.
+ *
+ * This call is non-blocking. The returned action group may or may not
+ * already be filled in. The correct thing to do is connect the signals
+ * for the action group to monitor for changes and then to call
+ * g_action_group_list_actions() to get the initial list.
+ *
+ * Returns: (transfer full): a #GDBusActionGroup
+ **/
GDBusActionGroup *
-g_dbus_action_group_new_sync (GDBusConnection *connection,
- const gchar *bus_name,
- const gchar *object_path,
- GCancellable *cancellable,
- GError **error)
+g_dbus_action_group_get (GDBusConnection *connection,
+ const gchar *bus_name,
+ const gchar *object_path)
{
GDBusActionGroup *group;
- GVariant *reply;
group = g_object_new (G_TYPE_DBUS_ACTION_GROUP, NULL);
group->connection = g_object_ref (connection);
group->bus_name = g_strdup (bus_name);
group->object_path = g_strdup (object_path);
+ return group;
+}
+
+G_GNUC_INTERNAL gboolean
+g_dbus_action_group_sync (GDBusActionGroup *group,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GVariant *reply;
+
+ g_assert (group->subscription_id == 0);
+
group->subscription_id =
- g_dbus_connection_signal_subscribe (connection, bus_name, "org.gtk.Actions", "Changed", object_path, NULL,
- G_DBUS_SIGNAL_FLAGS_NONE, g_dbus_action_group_changed, group, NULL);
+ g_dbus_connection_signal_subscribe (group->connection, group->bus_name, "org.gtk.Actions", "Changed", group->object_path,
+ NULL, G_DBUS_SIGNAL_FLAGS_NONE, g_dbus_action_group_changed, group, NULL);
- reply = g_dbus_connection_call_sync (connection, bus_name, object_path, "org.gtk.Actions",
+ reply = g_dbus_connection_call_sync (group->connection, group->bus_name, group->object_path, "org.gtk.Actions",
"DescribeAll", NULL, G_VARIANT_TYPE ("(a{s(bgav)})"),
G_DBUS_CALL_FLAGS_NONE, -1, cancellable, error);
@@ -521,11 +501,6 @@ g_dbus_action_group_new_sync (GDBusConnection *connection,
g_variant_iter_free (iter);
g_variant_unref (reply);
}
- else
- {
- g_object_unref (group);
- return NULL;
- }
- return group;
+ return reply != NULL;
}
diff --git a/gio/gdbusactiongroup.h b/gio/gdbusactiongroup.h
index 6da5861..12a8edf 100644
--- a/gio/gdbusactiongroup.h
+++ b/gio/gdbusactiongroup.h
@@ -45,21 +45,9 @@ G_BEGIN_DECLS
GType g_dbus_action_group_get_type (void) G_GNUC_CONST;
-void g_dbus_action_group_new (GDBusConnection *connection,
+GDBusActionGroup * g_dbus_action_group_get (GDBusConnection *connection,
const gchar *bus_name,
- const gchar *object_path,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-
-GDBusActionGroup * g_dbus_action_group_new_finish (GAsyncResult *result,
- GError **error);
-
-GDBusActionGroup * g_dbus_action_group_new_sync (GDBusConnection *connection,
- const gchar *bus_name,
- const gchar *object_path,
- GCancellable *cancellable,
- GError **error);
+ const gchar *object_path);
G_END_DECLS
diff --git a/gio/tests/actions.c b/gio/tests/actions.c
index e887458..57fec75 100644
--- a/gio/tests/actions.c
+++ b/gio/tests/actions.c
@@ -496,24 +496,12 @@ stop_loop (gpointer data)
return G_SOURCE_REMOVE;
}
-GDBusActionGroup *proxy;
-
-static void
-got_proxy (GObject *source,
- GAsyncResult *res,
- gpointer user_data)
-{
- GError *error = NULL;
-
- proxy = g_dbus_action_group_new_finish (res, &error);
- g_assert_no_error (error);
-}
-
static void
test_dbus_export (void)
{
GDBusConnection *bus;
GSimpleActionGroup *group;
+ GDBusActionGroup *proxy;
GSimpleAction *action;
GMainLoop *loop;
static GActionEntry entries[] = {
@@ -539,8 +527,8 @@ test_dbus_export (void)
id = g_dbus_connection_export_action_group (bus, "/", G_ACTION_GROUP (group), &error);
g_assert_no_error (error);
- g_dbus_action_group_new (bus, g_dbus_connection_get_unique_name (bus), "/", NULL, got_proxy, NULL);
- g_assert_no_error (error);
+ proxy = g_dbus_action_group_get (bus, g_dbus_connection_get_unique_name (bus), "/");
+ g_strfreev (g_action_group_list_actions (G_ACTION_GROUP (proxy)));
g_timeout_add (100, stop_loop, loop);
g_main_loop_run (loop);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]