Implement (untested) GApplication actions support

This commit is contained in:
Ryan Lortie 2010-10-25 14:32:07 -04:00
parent 196cd41f74
commit d8d2513710
5 changed files with 609 additions and 83 deletions

View File

@ -38,6 +38,15 @@ G_BEGIN_DECLS
#define G_ACTION_GROUP_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), \ #define G_ACTION_GROUP_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), \
G_TYPE_ACTION_GROUP, GActionGroupInterface)) 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; typedef struct _GActionGroupInterface GActionGroupInterface;
/** /**
@ -101,11 +110,25 @@ struct _GActionGroupInterface
void (* action_enabled_changed) (GActionGroup *action_group, void (* action_enabled_changed) (GActionGroup *action_group,
const gchar *action_name, const gchar *action_name,
gboolean enabled); gboolean enabled);
void (* action_state_changed) (GActionGroup *action_group, void (* action_state_changed) (GActionGroup *action_group,
const gchar *action_name, const gchar *action_name,
GVariant *value); 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; GType g_action_group_get_type (void) G_GNUC_CONST;
gboolean g_action_group_has_action (GActionGroup *action_group, gboolean g_action_group_has_action (GActionGroup *action_group,

View File

@ -93,6 +93,7 @@ struct _GApplicationPrivate
guint is_registered : 1; guint is_registered : 1;
guint is_remote : 1; guint is_remote : 1;
GHashTable *remote_actions; /* string -> RemoteActionInfo */
GApplicationImpl *impl; GApplicationImpl *impl;
}; };
@ -350,7 +351,7 @@ g_application_set_action_group (GApplication *application,
GActionGroup *action_group) GActionGroup *action_group)
{ {
g_return_if_fail (G_IS_APPLICATION (application)); 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) if (application->priv->actions != NULL)
g_object_unref (application->priv->actions); g_object_unref (application->priv->actions);
@ -894,22 +895,21 @@ g_application_register (GApplication *application,
if (!application->priv->is_registered) if (!application->priv->is_registered)
{ {
gboolean is_remote;
application->priv->impl = application->priv->impl =
g_application_impl_register (application, application->priv->id, g_application_impl_register (application, application->priv->id,
application->priv->flags, application->priv->flags,
&is_remote, cancellable, error); &application->priv->remote_actions,
cancellable, error);
if (application->priv->impl == NULL) if (application->priv->impl == NULL)
return FALSE; return FALSE;
application->priv->is_remote = is_remote; application->priv->is_remote = application->priv->remote_actions != NULL;
application->priv->is_registered = TRUE; application->priv->is_registered = TRUE;
g_object_notify (G_OBJECT (application), "is-registered"); 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); 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); 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 && return application->priv->actions &&
g_action_group_has_action (application->priv->actions, action_name); 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); 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); return g_action_group_list_actions (application->priv->actions);
else 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->actions != NULL, FALSE);
g_return_val_if_fail (application->priv->is_registered, 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, return g_action_group_get_action_enabled (application->priv->actions,
action_name); 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->actions != NULL, NULL);
g_return_val_if_fail (application->priv->is_registered, 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, return g_action_group_get_action_parameter_type (application->priv->actions,
action_name); action_name);
} }
@ -1252,23 +1298,23 @@ 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->actions != NULL, NULL);
g_return_val_if_fail (application->priv->is_registered, 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_get_type (info->state);
else
return NULL;
}
return g_action_group_get_action_state_type (application->priv->actions, return g_action_group_get_action_state_type (application->priv->actions,
action_name); action_name);
} }
static GVariant *
g_application_get_action_state_hint (GActionGroup *action_group,
const gchar *action_name)
{
GApplication *application = G_APPLICATION (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_hint (application->priv->actions,
action_name);
}
static GVariant * static GVariant *
g_application_get_action_state (GActionGroup *action_group, g_application_get_action_state (GActionGroup *action_group,
const gchar *action_name) const gchar *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->actions != NULL, NULL);
g_return_val_if_fail (application->priv->is_registered, 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, return g_action_group_get_action_state (application->priv->actions,
action_name); action_name);
} }
@ -1289,11 +1348,16 @@ g_application_change_action_state (GActionGroup *action_group,
{ {
GApplication *application = G_APPLICATION (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_return_if_fail (application->priv->is_registered);
g_action_group_change_action_state (application->priv->actions, if (application->priv->is_remote)
action_name, value); 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 static void
@ -1303,11 +1367,16 @@ g_application_activate_action (GActionGroup *action_group,
{ {
GApplication *application = G_APPLICATION (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_return_if_fail (application->priv->is_registered);
g_action_group_activate_action (application->priv->actions, if (application->priv->is_remote)
action_name, parameter); 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 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_enabled = g_application_get_action_enabled;
iface->get_action_parameter_type = g_application_get_action_parameter_type; 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_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->get_action_state = g_application_get_action_state;
iface->change_action_state = g_application_change_action_state; iface->change_action_state = g_application_change_action_state;
iface->activate_action = g_application_activate_action; iface->activate_action = g_application_activate_action;

View File

@ -21,6 +21,7 @@
#include "gapplicationimpl.h" #include "gapplicationimpl.h"
#include "gactiongroup.h"
#include "gapplication.h" #include "gapplication.h"
#include "gfile.h" #include "gfile.h"
#include "gdbusconnection.h" #include "gdbusconnection.h"
@ -82,6 +83,40 @@ const GDBusInterfaceInfo org_gtk_Application = {
(GDBusMethodInfo **) application_methods (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, &parameter_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 message_arg = { -1, (gchar *) "message", (gchar *) "s" };
static const GDBusArgInfo *print_in[] = { &message_arg, NULL }; static const GDBusArgInfo *print_in[] = { &message_arg, NULL };
static const GDBusArgInfo *print_out[] = { NULL }; static const GDBusArgInfo *print_out[] = { NULL };
@ -107,7 +142,6 @@ const GDBusInterfaceInfo org_gtk_private_Cmdline = {
(GDBusMethodInfo **) cmdline_methods (GDBusMethodInfo **) cmdline_methods
}; };
/* GApplication implementation {{{1 */ /* GApplication implementation {{{1 */
struct _GApplicationImpl struct _GApplicationImpl
{ {
@ -115,7 +149,11 @@ struct _GApplicationImpl
const gchar *bus_name; const gchar *bus_name;
gchar *object_path; gchar *object_path;
guint object_id; guint object_id;
guint action_id;
gpointer app; 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"); g_signal_emit_by_name (impl->app, "activate");
class->after_emit (impl->app, platform_data); class->after_emit (impl->app, platform_data);
g_variant_unref (platform_data); g_variant_unref (platform_data);
g_dbus_method_invocation_return_value (invocation, NULL);
} }
else if (strcmp (method_name, "Open") == 0) else if (strcmp (method_name, "Open") == 0)
@ -182,6 +222,8 @@ g_application_impl_method_call (GDBusConnection *connection,
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
g_object_unref (files[i]); g_object_unref (files[i]);
g_free (files); g_free (files);
g_dbus_method_invocation_return_value (invocation, NULL);
} }
else if (strcmp (method_name, "CommandLine") == 0) else if (strcmp (method_name, "CommandLine") == 0)
@ -199,6 +241,135 @@ g_application_impl_method_call (GDBusConnection *connection,
g_variant_unref (platform_data); g_variant_unref (platform_data);
g_object_unref (cmdline); 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, &param, &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 else
g_assert_not_reached (); g_assert_not_reached ();
@ -240,17 +411,132 @@ g_application_impl_destroy (GApplicationImpl *impl)
g_slice_free (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,
&param_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 * GApplicationImpl *
g_application_impl_register (GApplication *application, g_application_impl_register (GApplication *application,
const gchar *appid, const gchar *appid,
GApplicationFlags flags, GApplicationFlags flags,
gboolean *is_remote, GHashTable **remote_actions,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
const static GDBusInterfaceVTable vtable = { const static GDBusInterfaceVTable vtable = {
g_application_impl_method_call g_application_impl_method_call
}; };
const static GDBusInterfaceVTable actions_vtable = {
g_application_impl_actions_method_call
};
GApplicationImpl *impl; GApplicationImpl *impl;
GVariant *reply; GVariant *reply;
guint32 rval; guint32 rval;
@ -271,68 +557,91 @@ g_application_impl_register (GApplication *application,
impl->object_path = application_path_from_appid (appid); impl->object_path = application_path_from_appid (appid);
/* don't try to be the primary instance if /* Only try to be the primary instance if
* G_APPLICATION_IS_LAUNCHER was specified. * G_APPLICATION_IS_LAUNCHER was not specified.
*/ */
if (flags & G_APPLICATION_IS_LAUNCHER) if (~flags & G_APPLICATION_IS_LAUNCHER)
{ {
impl->object_id = 0; /* Attempt to become primary instance. */
*is_remote = TRUE; impl->object_id =
g_dbus_connection_register_object (impl->session_bus,
impl->object_path,
(GDBusInterfaceInfo *)
&org_gtk_Application,
&vtable, impl, NULL, error);
return impl; if (impl->object_id == 0)
} {
g_object_unref (impl->session_bus);
g_free (impl->object_path);
impl->session_bus = NULL;
impl->object_path = NULL;
impl->object_id = g_dbus_connection_register_object (impl->session_bus, g_slice_free (GApplicationImpl, impl);
impl->object_path, return NULL;
(GDBusInterfaceInfo *) }
&org_gtk_Application,
&vtable,
impl, NULL,
error);
if (impl->object_id == 0) impl->action_id =
{ g_dbus_connection_register_object (impl->session_bus,
g_object_unref (impl->session_bus); impl->object_path,
g_free (impl->object_path); (GDBusInterfaceInfo *)
impl->session_bus = NULL; &org_gtk_Actions,
impl->object_path = NULL; &actions_vtable,
impl, NULL, error);
g_slice_free (GApplicationImpl, impl); if (impl->action_id == 0)
return NULL; {
} g_dbus_connection_unregister_object (impl->session_bus,
impl->object_id);
reply = g_dbus_connection_call_sync (impl->session_bus, g_object_unref (impl->session_bus);
"org.freedesktop.DBus", g_free (impl->object_path);
"/org/freedesktop/DBus", impl->session_bus = NULL;
"org.freedesktop.DBus", impl->object_path = NULL;
"RequestName",
g_variant_new ("(su)",
/* DBUS_NAME_FLAG_DO_NOT_QUEUE: 0x4 */
impl->bus_name, 0x4),
G_VARIANT_TYPE ("(u)"),
0, -1, cancellable, error);
if (reply == NULL) g_slice_free (GApplicationImpl, impl);
{ return NULL;
g_dbus_connection_unregister_object (impl->session_bus, }
impl->object_id);
impl->object_id = 0;
g_object_unref (impl->session_bus); /* DBUS_NAME_FLAG_DO_NOT_QUEUE: 0x4 */
g_free (impl->object_path); reply = g_dbus_connection_call_sync (impl->session_bus,
impl->session_bus = NULL; "org.freedesktop.DBus",
impl->object_path = NULL; "/org/freedesktop/DBus",
"org.freedesktop.DBus",
"RequestName",
g_variant_new ("(su)",
impl->bus_name,
0x4),
G_VARIANT_TYPE ("(u)"),
0, -1, cancellable, error);
g_slice_free (GApplicationImpl, impl); if (reply == NULL)
return NULL; {
} g_dbus_connection_unregister_object (impl->session_bus,
impl->object_id);
impl->object_id = 0;
g_variant_get (reply, "(u)", &rval); g_object_unref (impl->session_bus);
g_variant_unref (reply); g_free (impl->object_path);
impl->session_bus = NULL;
impl->object_path = NULL;
/* DBUS_REQUEST_NAME_REPLY_EXISTS: 3 */ g_slice_free (GApplicationImpl, impl);
if ((*is_remote = (rval == 3))) return NULL;
{ }
g_variant_get (reply, "(u)", &rval);
g_variant_unref (reply);
/* 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, g_dbus_connection_unregister_object (impl->session_bus,
impl->object_id); impl->object_id);
impl->object_id = 0; 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,
&param_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; return impl;
} }
@ -498,6 +871,46 @@ g_application_impl_command_line (GApplicationImpl *impl,
return data.status; return data.status;
} }
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,
&parameter, 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 void
g_application_impl_flush (GApplicationImpl *impl) g_application_impl_flush (GApplicationImpl *impl)
{ {

View File

@ -2,6 +2,15 @@
typedef struct _GApplicationImpl GApplicationImpl; typedef struct _GApplicationImpl GApplicationImpl;
typedef struct
{
gchar *name;
GVariantType *parameter_type;
gboolean enabled;
GVariant *state;
} RemoteActionInfo;
G_GNUC_INTERNAL G_GNUC_INTERNAL
void g_application_impl_destroy (GApplicationImpl *impl); void g_application_impl_destroy (GApplicationImpl *impl);
@ -9,7 +18,7 @@ G_GNUC_INTERNAL
GApplicationImpl * g_application_impl_register (GApplication *application, GApplicationImpl * g_application_impl_register (GApplication *application,
const gchar *appid, const gchar *appid,
GApplicationFlags flags, GApplicationFlags flags,
gboolean *is_remote, GHashTable **remote_actions,
GCancellable *cancellable, GCancellable *cancellable,
GError **error); GError **error);
@ -29,5 +38,17 @@ int g_application_impl_command_line (GApplic
gchar **arguments, gchar **arguments,
GVariant *platform_data); 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 G_GNUC_INTERNAL
void g_application_impl_flush (GApplicationImpl *impl); void g_application_impl_flush (GApplicationImpl *impl);

View File

@ -47,6 +47,7 @@ typedef struct _GSimplePermission GSimplePermission;
typedef struct _GZlibCompressor GZlibCompressor; typedef struct _GZlibCompressor GZlibCompressor;
typedef struct _GZlibDecompressor GZlibDecompressor; typedef struct _GZlibDecompressor GZlibDecompressor;
typedef struct _GDBusActionGroup GDBusActionGroup;
typedef struct _GSimpleActionGroup GSimpleActionGroup; typedef struct _GSimpleActionGroup GSimpleActionGroup;
typedef struct _GActionGroup GActionGroup; typedef struct _GActionGroup GActionGroup;
typedef struct _GSimpleAction GSimpleAction; typedef struct _GSimpleAction GSimpleAction;