[glib] Implement (untested) GApplication actions support
- From: Ryan Lortie <ryanl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] Implement (untested) GApplication actions support
- Date: Mon, 25 Oct 2010 18:43:03 +0000 (UTC)
commit d8d2513710c5663dc7387d79e443edeb5c75598f
Author: Ryan Lortie <desrt desrt ca>
Date: Mon Oct 25 14:32:07 2010 -0400
Implement (untested) GApplication actions support
gio/gactiongroup.h | 29 +++-
gio/gapplication.c | 118 ++++++++--
gio/gapplicationimpl-dbus.c | 517 ++++++++++++++++++++++++++++++++++++++-----
gio/gapplicationimpl.h | 23 ++-
gio/giotypes.h | 1 +
5 files changed, 607 insertions(+), 81 deletions(-)
---
diff --git a/gio/gactiongroup.h b/gio/gactiongroup.h
index 300d415..2fa4831 100644
--- a/gio/gactiongroup.h
+++ b/gio/gactiongroup.h
@@ -38,6 +38,15 @@ G_BEGIN_DECLS
#define G_ACTION_GROUP_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), \
G_TYPE_ACTION_GROUP, GActionGroupInterface))
+#define G_TYPE_ACTION_GROUP (g_action_group_get_type ())
+#define G_ACTION_GROUP(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
+ G_TYPE_ACTION_GROUP, GActionGroup))
+#define G_IS_ACTION_GROUP(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
+ G_TYPE_ACTION_GROUP))
+#define G_ACTION_GROUP_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), \
+ G_TYPE_ACTION_GROUP, GActionGroupInterface))
+
+typedef struct _GContextActionGroupInterface GContextActionGroupInterface;
typedef struct _GActionGroupInterface GActionGroupInterface;
/**
@@ -101,11 +110,25 @@ struct _GActionGroupInterface
void (* action_enabled_changed) (GActionGroup *action_group,
const gchar *action_name,
gboolean enabled);
- void (* action_state_changed) (GActionGroup *action_group,
- const gchar *action_name,
- GVariant *value);
+ void (* action_state_changed) (GActionGroup *action_group,
+ const gchar *action_name,
+ GVariant *value);
};
+struct _GContextActionGroupInterface
+{
+ void (* change_action_state) (GActionGroup *action_group,
+ const gchar *action_name,
+ GVariant *value,
+ GVariant *context);
+
+ void (* activate_action) (GActionGroup *action_group,
+ const gchar *action_name,
+ GVariant *parameter,
+ GVariant *context);
+};
+
+
GType g_action_group_get_type (void) G_GNUC_CONST;
gboolean g_action_group_has_action (GActionGroup *action_group,
diff --git a/gio/gapplication.c b/gio/gapplication.c
index 279d501..d81ea80 100644
--- a/gio/gapplication.c
+++ b/gio/gapplication.c
@@ -93,6 +93,7 @@ struct _GApplicationPrivate
guint is_registered : 1;
guint is_remote : 1;
+ GHashTable *remote_actions; /* string -> RemoteActionInfo */
GApplicationImpl *impl;
};
@@ -350,7 +351,7 @@ g_application_set_action_group (GApplication *application,
GActionGroup *action_group)
{
g_return_if_fail (G_IS_APPLICATION (application));
- g_return_if_fail (application->priv->is_registered);
+ g_return_if_fail (!application->priv->is_registered);
if (application->priv->actions != NULL)
g_object_unref (application->priv->actions);
@@ -894,22 +895,21 @@ g_application_register (GApplication *application,
if (!application->priv->is_registered)
{
- gboolean is_remote;
-
application->priv->impl =
g_application_impl_register (application, application->priv->id,
application->priv->flags,
- &is_remote, cancellable, error);
+ &application->priv->remote_actions,
+ cancellable, error);
if (application->priv->impl == NULL)
return FALSE;
- application->priv->is_remote = is_remote;
+ application->priv->is_remote = application->priv->remote_actions != NULL;
application->priv->is_registered = TRUE;
g_object_notify (G_OBJECT (application), "is-registered");
- if (!is_remote)
+ if (!application->priv->is_remote)
g_signal_emit (application, g_application_signals[SIGNAL_STARTUP], 0);
}
@@ -1198,6 +1198,10 @@ g_application_has_action (GActionGroup *action_group,
g_return_val_if_fail (application->priv->is_registered, FALSE);
+ if (application->priv->remote_actions != NULL)
+ return g_hash_table_lookup (application->priv->remote_actions,
+ action_name) != NULL;
+
return application->priv->actions &&
g_action_group_has_action (application->priv->actions, action_name);
}
@@ -1209,7 +1213,26 @@ g_application_list_actions (GActionGroup *action_group)
g_return_val_if_fail (application->priv->is_registered, NULL);
- if (application->priv->actions != NULL)
+ if (application->priv->remote_actions != NULL)
+ {
+ GHashTableIter iter;
+ gint n, i = 0;
+ gchar **keys;
+ gpointer key;
+
+ n = g_hash_table_size (application->priv->remote_actions);
+ keys = g_new (gchar *, n + 1);
+
+ g_hash_table_iter_init (&iter, application->priv->remote_actions);
+ while (g_hash_table_iter_next (&iter, &key, NULL))
+ keys[i++] = g_strdup (key);
+ g_assert_cmpint (i, ==, n);
+ keys[n] = NULL;
+
+ return keys;
+ }
+
+ else if (application->priv->actions != NULL)
return g_action_group_list_actions (application->priv->actions);
else
@@ -1226,6 +1249,16 @@ g_application_get_action_enabled (GActionGroup *action_group,
g_return_val_if_fail (application->priv->actions != NULL, FALSE);
g_return_val_if_fail (application->priv->is_registered, FALSE);
+ if (application->priv->remote_actions)
+ {
+ RemoteActionInfo *info;
+
+ info = g_hash_table_lookup (application->priv->remote_actions,
+ action_name);
+
+ return info && info->enabled;
+ }
+
return g_action_group_get_action_enabled (application->priv->actions,
action_name);
}
@@ -1239,6 +1272,19 @@ g_application_get_action_parameter_type (GActionGroup *action_group,
g_return_val_if_fail (application->priv->actions != NULL, NULL);
g_return_val_if_fail (application->priv->is_registered, NULL);
+ if (application->priv->remote_actions)
+ {
+ RemoteActionInfo *info;
+
+ info = g_hash_table_lookup (application->priv->remote_actions,
+ action_name);
+
+ if (info)
+ return info->parameter_type;
+ else
+ return NULL;
+ }
+
return g_action_group_get_action_parameter_type (application->priv->actions,
action_name);
}
@@ -1252,20 +1298,20 @@ g_application_get_action_state_type (GActionGroup *action_group,
g_return_val_if_fail (application->priv->actions != NULL, NULL);
g_return_val_if_fail (application->priv->is_registered, NULL);
- return g_action_group_get_action_state_type (application->priv->actions,
- action_name);
-}
+ if (application->priv->remote_actions)
+ {
+ RemoteActionInfo *info;
-static GVariant *
-g_application_get_action_state_hint (GActionGroup *action_group,
- const gchar *action_name)
-{
- GApplication *application = G_APPLICATION (action_group);
+ info = g_hash_table_lookup (application->priv->remote_actions,
+ action_name);
- g_return_val_if_fail (application->priv->actions != NULL, NULL);
- g_return_val_if_fail (application->priv->is_registered, NULL);
+ if (info && info->state)
+ return g_variant_get_type (info->state);
+ else
+ return NULL;
+ }
- return g_action_group_get_action_state_hint (application->priv->actions,
+ return g_action_group_get_action_state_type (application->priv->actions,
action_name);
}
@@ -1278,6 +1324,19 @@ g_application_get_action_state (GActionGroup *action_group,
g_return_val_if_fail (application->priv->actions != NULL, NULL);
g_return_val_if_fail (application->priv->is_registered, NULL);
+ if (application->priv->remote_actions)
+ {
+ RemoteActionInfo *info;
+
+ info = g_hash_table_lookup (application->priv->remote_actions,
+ action_name);
+
+ if (info && info->state)
+ return g_variant_ref (info->state);
+ else
+ return NULL;
+ }
+
return g_action_group_get_action_state (application->priv->actions,
action_name);
}
@@ -1289,11 +1348,16 @@ g_application_change_action_state (GActionGroup *action_group,
{
GApplication *application = G_APPLICATION (action_group);
- g_return_if_fail (application->priv->actions != NULL);
g_return_if_fail (application->priv->is_registered);
- g_action_group_change_action_state (application->priv->actions,
- action_name, value);
+ if (application->priv->is_remote)
+ g_application_impl_change_action_state (application->priv->impl,
+ action_name, value,
+ get_platform_data (application));
+
+ else
+ g_action_group_change_action_state (application->priv->actions,
+ action_name, value);
}
static void
@@ -1303,11 +1367,16 @@ g_application_activate_action (GActionGroup *action_group,
{
GApplication *application = G_APPLICATION (action_group);
- g_return_if_fail (application->priv->actions != NULL);
g_return_if_fail (application->priv->is_registered);
- g_action_group_activate_action (application->priv->actions,
- action_name, parameter);
+ if (application->priv->is_remote)
+ g_application_impl_activate_action (application->priv->impl,
+ action_name, parameter,
+ get_platform_data (application));
+
+ else
+ g_action_group_activate_action (application->priv->actions,
+ action_name, parameter);
}
static void
@@ -1319,7 +1388,6 @@ g_application_action_group_iface_init (GActionGroupInterface *iface)
iface->get_action_enabled = g_application_get_action_enabled;
iface->get_action_parameter_type = g_application_get_action_parameter_type;
iface->get_action_state_type = g_application_get_action_state_type;
- iface->get_action_state_hint = g_application_get_action_state_hint;
iface->get_action_state = g_application_get_action_state;
iface->change_action_state = g_application_change_action_state;
iface->activate_action = g_application_activate_action;
diff --git a/gio/gapplicationimpl-dbus.c b/gio/gapplicationimpl-dbus.c
index 893c96b..8a3837d 100644
--- a/gio/gapplicationimpl-dbus.c
+++ b/gio/gapplicationimpl-dbus.c
@@ -21,6 +21,7 @@
#include "gapplicationimpl.h"
+#include "gactiongroup.h"
#include "gapplication.h"
#include "gfile.h"
#include "gdbusconnection.h"
@@ -82,6 +83,40 @@ const GDBusInterfaceInfo org_gtk_Application = {
(GDBusMethodInfo **) application_methods
};
+static const GDBusArgInfo list_arg = { -1, (gchar *) "list", (gchar *) "a(savbav)" };
+static const GDBusArgInfo *describe_all_out[] = { &list_arg, NULL };
+
+static const GDBusArgInfo action_name_arg = { -1, (gchar *) "action_name", (gchar *) "s" };
+static const GDBusArgInfo value_arg = { -1, (gchar *) "value", (gchar *) "v" };
+static const GDBusArgInfo *set_action_state_in[] = { &action_name_arg, &value_arg, &platform_data_arg, NULL };
+
+static const GDBusArgInfo parameter_arg = { -1, (gchar *) "parameter", (gchar *) "av" };
+static const GDBusArgInfo *activate_action_in[] = { &action_name_arg, ¶meter_arg, &platform_data_arg, NULL };
+
+static const GDBusMethodInfo describe_all_method = {
+ -1, (gchar *) "DescribeAll", NULL,
+ (GDBusArgInfo **) describe_all_out
+};
+
+static const GDBusMethodInfo set_action_state_method = {
+ -1, (gchar *) "SetState",
+ (GDBusArgInfo **) set_action_state_in
+};
+
+static const GDBusMethodInfo activate_action_method = {
+ -1, (gchar *) "Activate",
+ (GDBusArgInfo **) activate_action_in
+};
+
+static const GDBusMethodInfo *actions_methods[] = {
+ &describe_all_method, &set_action_state_method, &activate_action_method, NULL
+};
+
+const GDBusInterfaceInfo org_gtk_Actions = {
+ -1, (gchar *) "org.gtk.Actions",
+ (GDBusMethodInfo **) actions_methods
+};
+
static const GDBusArgInfo message_arg = { -1, (gchar *) "message", (gchar *) "s" };
static const GDBusArgInfo *print_in[] = { &message_arg, NULL };
static const GDBusArgInfo *print_out[] = { NULL };
@@ -107,7 +142,6 @@ const GDBusInterfaceInfo org_gtk_private_Cmdline = {
(GDBusMethodInfo **) cmdline_methods
};
-
/* GApplication implementation {{{1 */
struct _GApplicationImpl
{
@@ -115,7 +149,11 @@ struct _GApplicationImpl
const gchar *bus_name;
gchar *object_path;
guint object_id;
+ guint action_id;
gpointer app;
+
+ GHashTable *actions;
+ guint signal_id;
};
@@ -147,6 +185,8 @@ g_application_impl_method_call (GDBusConnection *connection,
g_signal_emit_by_name (impl->app, "activate");
class->after_emit (impl->app, platform_data);
g_variant_unref (platform_data);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
}
else if (strcmp (method_name, "Open") == 0)
@@ -182,6 +222,8 @@ g_application_impl_method_call (GDBusConnection *connection,
for (i = 0; i < n; i++)
g_object_unref (files[i]);
g_free (files);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
}
else if (strcmp (method_name, "CommandLine") == 0)
@@ -199,6 +241,135 @@ g_application_impl_method_call (GDBusConnection *connection,
g_variant_unref (platform_data);
g_object_unref (cmdline);
}
+ else
+ g_assert_not_reached ();
+}
+
+static void
+g_application_impl_actions_method_call (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ GApplicationImpl *impl = user_data;
+ GActionGroup *action_group;
+ GApplicationClass *class;
+
+ class = G_APPLICATION_GET_CLASS (impl->app);
+ action_group = G_ACTION_GROUP (impl->app);
+
+ if (strcmp (method_name, "DescribeAll") == 0)
+ {
+ GVariantBuilder builder;
+ gchar **actions;
+ gint i;
+
+ actions = g_action_group_list_actions (action_group);
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("(a(savbav))"));
+ g_variant_builder_open (&builder, G_VARIANT_TYPE ("a(savbav)"));
+
+ for (i = 0; actions[i]; i++)
+ {
+ /* Open */
+ g_variant_builder_open (&builder, G_VARIANT_TYPE ("(savbav)"));
+
+ /* Name */
+ g_variant_builder_add (&builder, "s", actions[i]);
+
+ /* Parameter type */
+ g_variant_builder_open (&builder, G_VARIANT_TYPE ("av"));
+ {
+ const GVariantType *type;
+
+ type = g_action_group_get_action_parameter_type (action_group,
+ actions[i]);
+ if (type != NULL)
+ {
+ GVariantType *array_type;
+
+ array_type = g_variant_type_new_array (type);
+ g_variant_builder_open (&builder, G_VARIANT_TYPE_VARIANT);
+ g_variant_builder_open (&builder, array_type);
+ g_variant_builder_close (&builder);
+ g_variant_builder_close (&builder);
+ g_variant_type_free (array_type);
+ }
+ }
+ g_variant_builder_close (&builder);
+
+ /* Enabled */
+ {
+ gboolean enabled = g_action_group_get_action_enabled (action_group,
+ actions[i]);
+ g_variant_builder_add (&builder, "b", enabled);
+ }
+
+ /* State */
+ g_variant_builder_open (&builder, G_VARIANT_TYPE ("av"));
+ {
+ GVariant *state = g_action_group_get_action_state (action_group,
+ actions[i]);
+ if (state != NULL)
+ {
+ g_variant_builder_add (&builder, "v", state);
+ g_variant_unref (state);
+ }
+ }
+ g_variant_builder_close (&builder);
+
+ /* Close */
+ g_variant_builder_close (&builder);
+ }
+ g_variant_builder_close (&builder);
+
+ g_dbus_method_invocation_return_value (invocation,
+ g_variant_builder_end (&builder));
+ }
+
+ else if (strcmp (method_name, "SetState") == 0)
+ {
+ const gchar *action_name;
+ GVariant *platform_data;
+ GVariant *state;
+
+ g_variant_get (parameters, "(&sv a{sv})",
+ &action_name, &state, &platform_data);
+
+ class->before_emit (impl->app, platform_data);
+ g_action_group_change_action_state (action_group, action_name, state);
+ class->after_emit (impl->app, platform_data);
+ g_variant_unref (platform_data);
+ g_variant_unref (state);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
+
+ else if (strcmp (method_name, "Activate") == 0)
+ {
+ const gchar *action_name;
+ GVariant *platform_data;
+ GVariantIter *param;
+ GVariant *parameter;
+
+ g_variant_get (parameters, "(&sav a{sv})",
+ &action_name, ¶m, &platform_data);
+ parameter = g_variant_iter_next_value (param);
+ g_variant_iter_free (param);
+
+ class->before_emit (impl->app, platform_data);
+ g_action_group_activate_action (action_group, action_name, parameter);
+ class->after_emit (impl->app, platform_data);
+ g_variant_unref (platform_data);
+
+ if (parameter)
+ g_variant_unref (parameter);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
else
g_assert_not_reached ();
@@ -240,17 +411,132 @@ g_application_impl_destroy (GApplicationImpl *impl)
g_slice_free (GApplicationImpl, impl);
}
+RemoteActionInfo *
+remote_action_info_new_from_iter (GVariantIter *iter)
+{
+ RemoteActionInfo *info;
+ const gchar *name;
+ GVariant *param_type;
+ gboolean enabled;
+ GVariant *state;
+
+ if (!g_variant_iter_next (iter, "(s avb@av)", &name,
+ ¶m_type, &enabled, &state))
+ return NULL;
+
+ info = g_slice_new (RemoteActionInfo);
+ info->parameter_type = g_variant_type_copy (
+ g_variant_type_element (
+ g_variant_get_type (param_type)));
+ info->enabled = enabled;
+ info->state = state;
+
+ g_variant_unref (param_type);
+
+ return info;
+}
+
+static void
+g_application_impl_action_signal (GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ GApplicationImpl *impl = user_data;
+ GActionGroup *action_group;
+
+ action_group = G_ACTION_GROUP (impl->app);
+
+ if (strcmp (signal_name, "Added") == 0 &&
+ g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(a(savbav))")))
+ {
+ RemoteActionInfo *info;
+ GVariantIter *iter;
+
+ g_variant_get_child (parameters, 0, "a(savbav)", &iter);
+
+ while ((info = remote_action_info_new_from_iter (iter)))
+ {
+ g_hash_table_replace (impl->actions, info->name, info);
+ g_action_group_action_added (action_group, info->name);
+ }
+
+ g_variant_iter_free (iter);
+ }
+
+ else if (strcmp (signal_name, "Removed") == 0 &&
+ g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(as)")))
+ {
+ GVariantIter *iter;
+ const gchar *name;
+
+ g_variant_get_child (parameters, 0, "as", &iter);
+ while (g_variant_iter_next (iter, "&s", &name))
+ if (g_hash_table_remove (impl->actions, name))
+ g_action_group_action_removed (action_group, name);
+ g_variant_iter_free (iter);
+ }
+
+ else if (strcmp (signal_name, "EnabledChanged") == 0 &&
+ g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sb)")))
+ {
+ RemoteActionInfo *info;
+ const gchar *name;
+ gboolean enabled;
+
+ g_variant_get (parameters, "(&sb)", &name, &enabled);
+ info = g_hash_table_lookup (impl->actions, name);
+
+ if (info && enabled != info->enabled)
+ {
+ info->enabled = enabled;
+ g_action_group_action_enabled_changed (action_group,
+ info->name,
+ enabled);
+ }
+ }
+
+ else if (strcmp (signal_name, "StateChanged") == 0 &&
+ g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sv)")))
+ {
+ RemoteActionInfo *info;
+ const gchar *name;
+ GVariant *state;
+
+ g_variant_get (parameters, "(&sv)", &name, &state);
+ info = g_hash_table_lookup (impl->actions, name);
+
+ if (info && info->state &&
+ g_variant_is_of_type (state, g_variant_get_type (info->state)) &&
+ !g_variant_equal (state, info->state))
+ {
+ g_variant_unref (info->state);
+ info->state = g_variant_ref (state);
+ g_action_group_action_state_changed (action_group,
+ info->name,
+ state);
+ }
+ g_variant_unref (state);
+ }
+}
+
GApplicationImpl *
g_application_impl_register (GApplication *application,
const gchar *appid,
GApplicationFlags flags,
- gboolean *is_remote,
+ GHashTable **remote_actions,
GCancellable *cancellable,
GError **error)
{
const static GDBusInterfaceVTable vtable = {
g_application_impl_method_call
};
+ const static GDBusInterfaceVTable actions_vtable = {
+ g_application_impl_actions_method_call
+ };
GApplicationImpl *impl;
GVariant *reply;
guint32 rval;
@@ -271,68 +557,91 @@ g_application_impl_register (GApplication *application,
impl->object_path = application_path_from_appid (appid);
- /* don't try to be the primary instance if
- * G_APPLICATION_IS_LAUNCHER was specified.
+ /* Only try to be the primary instance if
+ * G_APPLICATION_IS_LAUNCHER was not specified.
*/
- if (flags & G_APPLICATION_IS_LAUNCHER)
+ if (~flags & G_APPLICATION_IS_LAUNCHER)
{
- impl->object_id = 0;
- *is_remote = TRUE;
+ /* Attempt to become primary instance. */
+ impl->object_id =
+ g_dbus_connection_register_object (impl->session_bus,
+ impl->object_path,
+ (GDBusInterfaceInfo *)
+ &org_gtk_Application,
+ &vtable, impl, NULL, error);
+
+ if (impl->object_id == 0)
+ {
+ g_object_unref (impl->session_bus);
+ g_free (impl->object_path);
+ impl->session_bus = NULL;
+ impl->object_path = NULL;
- return impl;
- }
+ g_slice_free (GApplicationImpl, impl);
+ return NULL;
+ }
- impl->object_id = g_dbus_connection_register_object (impl->session_bus,
- impl->object_path,
- (GDBusInterfaceInfo *)
- &org_gtk_Application,
- &vtable,
- impl, NULL,
- error);
+ impl->action_id =
+ g_dbus_connection_register_object (impl->session_bus,
+ impl->object_path,
+ (GDBusInterfaceInfo *)
+ &org_gtk_Actions,
+ &actions_vtable,
+ impl, NULL, error);
- if (impl->object_id == 0)
- {
- g_object_unref (impl->session_bus);
- g_free (impl->object_path);
- impl->session_bus = NULL;
- impl->object_path = NULL;
+ if (impl->action_id == 0)
+ {
+ g_dbus_connection_unregister_object (impl->session_bus,
+ impl->object_id);
- g_slice_free (GApplicationImpl, impl);
- return NULL;
- }
+ g_object_unref (impl->session_bus);
+ g_free (impl->object_path);
+ impl->session_bus = NULL;
+ impl->object_path = NULL;
- reply = g_dbus_connection_call_sync (impl->session_bus,
- "org.freedesktop.DBus",
- "/org/freedesktop/DBus",
- "org.freedesktop.DBus",
- "RequestName",
- g_variant_new ("(su)",
- /* DBUS_NAME_FLAG_DO_NOT_QUEUE: 0x4 */
- impl->bus_name, 0x4),
- G_VARIANT_TYPE ("(u)"),
- 0, -1, cancellable, error);
+ g_slice_free (GApplicationImpl, impl);
+ return NULL;
+ }
- if (reply == NULL)
- {
- g_dbus_connection_unregister_object (impl->session_bus,
- impl->object_id);
- impl->object_id = 0;
+ /* DBUS_NAME_FLAG_DO_NOT_QUEUE: 0x4 */
+ reply = g_dbus_connection_call_sync (impl->session_bus,
+ "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ "RequestName",
+ g_variant_new ("(su)",
+ impl->bus_name,
+ 0x4),
+ G_VARIANT_TYPE ("(u)"),
+ 0, -1, cancellable, error);
+
+ if (reply == NULL)
+ {
+ g_dbus_connection_unregister_object (impl->session_bus,
+ impl->object_id);
+ impl->object_id = 0;
- g_object_unref (impl->session_bus);
- g_free (impl->object_path);
- impl->session_bus = NULL;
- impl->object_path = NULL;
+ g_object_unref (impl->session_bus);
+ g_free (impl->object_path);
+ impl->session_bus = NULL;
+ impl->object_path = NULL;
- g_slice_free (GApplicationImpl, impl);
- return NULL;
- }
+ g_slice_free (GApplicationImpl, impl);
+ return NULL;
+ }
- g_variant_get (reply, "(u)", &rval);
- g_variant_unref (reply);
+ g_variant_get (reply, "(u)", &rval);
+ g_variant_unref (reply);
- /* DBUS_REQUEST_NAME_REPLY_EXISTS: 3 */
- if ((*is_remote = (rval == 3)))
- {
+ /* DBUS_REQUEST_NAME_REPLY_EXISTS: 3 */
+ if (rval != 3)
+ {
+ /* We are the primary instance. */
+ *remote_actions = NULL;
+ return impl;
+ }
+
+ /* We didn't make it. Drop our service-side stuff. */
g_dbus_connection_unregister_object (impl->session_bus,
impl->object_id);
impl->object_id = 0;
@@ -349,6 +658,70 @@ g_application_impl_register (GApplication *application,
}
}
+ /* We are non-primary. Try to get the primary's list of actions.
+ * This also serves as a mechanism to ensure that the primary exists
+ * (ie: DBus service files installed correctly, etc).
+ */
+ impl->signal_id =
+ g_dbus_connection_signal_subscribe (impl->session_bus, impl->bus_name,
+ "org.gtk.Actions", NULL,
+ impl->object_path, NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ g_application_impl_action_signal,
+ impl, NULL);
+
+ reply = g_dbus_connection_call_sync (impl->session_bus, impl->bus_name,
+ impl->object_path, "org.gtk.Actions",
+ "DescribeAll", NULL,
+ G_VARIANT_TYPE ("(a(savbav))"),
+ G_DBUS_CALL_FLAGS_NONE, -1,
+ cancellable, error);
+
+ if (reply == NULL)
+ {
+ /* The primary appears not to exist. Fail the registration. */
+ g_object_unref (impl->session_bus);
+ g_free (impl->object_path);
+ impl->session_bus = NULL;
+ impl->object_path = NULL;
+
+ g_slice_free (GApplicationImpl, impl);
+ return NULL;
+ }
+
+ /* Create and populate the hashtable */
+ {
+ GVariant *descriptions;
+ GVariantIter iter;
+ GVariant *param_type;
+ gboolean enabled;
+ GVariant *state;
+ gchar *name;
+
+ *remote_actions = g_hash_table_new (g_str_hash, g_str_equal);
+ descriptions = g_variant_get_child_value (reply, 0);
+ g_variant_iter_init (&iter, descriptions);
+
+ while (g_variant_iter_next (&iter, "(s avb@av)", &name,
+ ¶m_type, &enabled, &state))
+ {
+ RemoteActionInfo *action;
+
+ action = g_slice_new (RemoteActionInfo);
+ action->parameter_type = g_variant_type_copy (
+ g_variant_type_element (
+ g_variant_get_type (param_type)));
+ action->enabled = enabled;
+ action->state = state;
+
+ g_hash_table_insert (*remote_actions, name, action);
+ g_variant_unref (param_type);
+ }
+
+ g_variant_unref (descriptions);
+ }
+
+
return impl;
}
@@ -499,6 +872,46 @@ g_application_impl_command_line (GApplicationImpl *impl,
}
void
+g_application_impl_change_action_state (GApplicationImpl *impl,
+ const gchar *action_name,
+ GVariant *value,
+ GVariant *platform_data)
+{
+ g_dbus_connection_call (impl->session_bus,
+ impl->bus_name,
+ impl->object_path,
+ "org.gtk.Actions",
+ "SetState",
+ g_variant_new ("(sv a{sv})", action_name,
+ value, platform_data),
+ NULL, 0, -1, NULL, NULL, NULL);
+}
+
+void
+g_application_impl_activate_action (GApplicationImpl *impl,
+ const gchar *action_name,
+ GVariant *parameter,
+ GVariant *platform_data)
+{
+ GVariant *param;
+
+ if (parameter)
+ parameter = g_variant_new_variant (parameter);
+
+ param = g_variant_new_array (G_VARIANT_TYPE_VARIANT,
+ ¶meter, parameter != NULL);
+
+ g_dbus_connection_call (impl->session_bus,
+ impl->bus_name,
+ impl->object_path,
+ "org.gtk.Actions",
+ "Activate",
+ g_variant_new ("(s av@a{sv})", action_name,
+ param, platform_data),
+ NULL, 0, -1, NULL, NULL, NULL);
+}
+
+void
g_application_impl_flush (GApplicationImpl *impl)
{
g_dbus_connection_flush_sync (impl->session_bus, NULL, NULL);
diff --git a/gio/gapplicationimpl.h b/gio/gapplicationimpl.h
index 35a34b9..95f0b76 100644
--- a/gio/gapplicationimpl.h
+++ b/gio/gapplicationimpl.h
@@ -2,6 +2,15 @@
typedef struct _GApplicationImpl GApplicationImpl;
+typedef struct
+{
+ gchar *name;
+
+ GVariantType *parameter_type;
+ gboolean enabled;
+ GVariant *state;
+} RemoteActionInfo;
+
G_GNUC_INTERNAL
void g_application_impl_destroy (GApplicationImpl *impl);
@@ -9,7 +18,7 @@ G_GNUC_INTERNAL
GApplicationImpl * g_application_impl_register (GApplication *application,
const gchar *appid,
GApplicationFlags flags,
- gboolean *is_remote,
+ GHashTable **remote_actions,
GCancellable *cancellable,
GError **error);
@@ -30,4 +39,16 @@ int g_application_impl_command_line (GApplic
GVariant *platform_data);
G_GNUC_INTERNAL
+void g_application_impl_change_action_state (GApplicationImpl *impl,
+ const gchar *action_name,
+ GVariant *value,
+ GVariant *platform_data);
+
+G_GNUC_INTERNAL
+void g_application_impl_activate_action (GApplicationImpl *impl,
+ const gchar *action_name,
+ GVariant *parameter,
+ GVariant *platform_data);
+
+G_GNUC_INTERNAL
void g_application_impl_flush (GApplicationImpl *impl);
diff --git a/gio/giotypes.h b/gio/giotypes.h
index ffd38ef..b9eb908 100644
--- a/gio/giotypes.h
+++ b/gio/giotypes.h
@@ -47,6 +47,7 @@ typedef struct _GSimplePermission GSimplePermission;
typedef struct _GZlibCompressor GZlibCompressor;
typedef struct _GZlibDecompressor GZlibDecompressor;
+typedef struct _GDBusActionGroup GDBusActionGroup;
typedef struct _GSimpleActionGroup GSimpleActionGroup;
typedef struct _GActionGroup GActionGroup;
typedef struct _GSimpleAction GSimpleAction;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]