/* GIO - GLib Input, Output and Streaming Library * * Copyright © 2010 Red Hat, Inc * * 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 License, 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: Colin Walters */ #define G_APPLICATION_IFACE "org.gtk.Application" static void application_dbus_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) { GApplication *app = G_APPLICATION (user_data); if (method_name == NULL && *method_name == '\0') return; if (strcmp (method_name, "Quit") == 0) { GVariant *platform_data; g_variant_get (parameters, "(@a{sv})", &platform_data); g_dbus_method_invocation_return_value (invocation, NULL); g_application_quit_with_data (app, platform_data); g_variant_unref (platform_data); } else if (strcmp (method_name, "ListActions") == 0) { GHashTableIter iter; GApplicationAction *value; GVariantBuilder builder; g_variant_builder_init (&builder, G_VARIANT_TYPE ("(a{s(sb)})")); g_variant_builder_open (&builder, G_VARIANT_TYPE ("a{s(sb)}")); g_hash_table_iter_init (&iter, app->priv->actions); while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&value)) g_variant_builder_add (&builder, "{s(sb)}", value->name, value->description ? value->description : "", value->enabled); g_variant_builder_close (&builder); g_dbus_method_invocation_return_value (invocation, g_variant_builder_end (&builder)); } else if (strcmp (method_name, "InvokeAction") == 0) { const char *action_name; GVariant *platform_data; GApplicationAction *action; g_variant_get (parameters, "(&s@a{sv})", &action_name, &platform_data); action = g_hash_table_lookup (app->priv->actions, action_name); if (!action) { char *errmsg = g_strdup_printf ("Invalid action: %s", action_name); g_dbus_method_invocation_return_dbus_error (invocation, G_APPLICATION_IFACE ".InvalidAction", errmsg); g_free (errmsg); g_variant_unref (platform_data); return; } g_signal_emit (app, application_signals[ACTION_WITH_DATA], g_quark_from_string (action_name), action_name, platform_data); g_dbus_method_invocation_return_value (invocation, NULL); g_variant_unref (platform_data); } else if (strcmp (method_name, "Activate") == 0) { GVariant *args; GVariant *platform_data; g_variant_get (parameters, "(@aay@a{sv})", &args, &platform_data); g_signal_emit (app, application_signals[PREPARE_ACTIVATION], 0, args, platform_data); g_variant_unref (args); g_variant_unref (platform_data); g_dbus_method_invocation_return_value (invocation, NULL); } } static const GDBusArgInfo application_quit_in_args[] = { { -1, "platform_data", "a{sv}", NULL } }; static const GDBusArgInfo * const application_quit_in_args_p[] = { &application_quit_in_args[0], NULL }; static const GDBusArgInfo application_list_actions_out_args[] = { { -1, "actions", "a{s(sb)}", NULL } }; static const GDBusArgInfo * const application_list_actions_out_args_p[] = { &application_list_actions_out_args[0], NULL }; static const GDBusArgInfo application_invoke_action_in_args[] = { { -1, "action", "s", NULL }, { -1, "platform_data", "a{sv}", NULL } }; static const GDBusArgInfo * const application_invoke_action_in_args_p[] = { &application_invoke_action_in_args[0], &application_invoke_action_in_args[1], NULL }; static const GDBusMethodInfo application_quit_method_info = { -1, "Quit", (GDBusArgInfo **) &application_quit_in_args_p, NULL, NULL }; static const GDBusMethodInfo application_list_actions_method_info = { -1, "ListActions", NULL, (GDBusArgInfo **) &application_list_actions_out_args_p, NULL }; static const GDBusMethodInfo application_invoke_action_method_info = { -1, "InvokeAction", (GDBusArgInfo **) &application_invoke_action_in_args_p, NULL, NULL }; static const GDBusArgInfo application_activate_in_args[] = { { -1, "arguments", "aay", NULL }, { -1, "data", "a{sv}", NULL } }; static const GDBusArgInfo * const application_activate_in_args_p[] = { &application_activate_in_args[0], &application_activate_in_args[1], NULL }; static const GDBusMethodInfo application_activate_method_info = { -1, "Activate", (GDBusArgInfo **) &application_activate_in_args_p, NULL, NULL }; static const GDBusMethodInfo * const application_dbus_method_info_p[] = { &application_quit_method_info, &application_list_actions_method_info, &application_invoke_action_method_info, &application_activate_method_info, NULL }; static const GDBusSignalInfo application_dbus_signal_info[] = { { -1, "ActionsChanged", NULL, NULL } }; static const GDBusSignalInfo * const application_dbus_signal_info_p[] = { &application_dbus_signal_info[0], NULL }; static const GDBusInterfaceInfo application_dbus_interface_info = { -1, G_APPLICATION_IFACE, (GDBusMethodInfo **) application_dbus_method_info_p, (GDBusSignalInfo **) application_dbus_signal_info_p, NULL, }; static GDBusInterfaceVTable application_dbus_vtable = { application_dbus_method_call, NULL, NULL }; static gchar * application_path_from_appid (const gchar *appid) { gchar *appid_path, *iter; appid_path = g_strconcat ("/", appid, NULL); for (iter = appid_path; *iter; iter++) { if (*iter == '.') *iter = '/'; } return appid_path; } static gboolean _g_application_platform_init (GApplication *app, GCancellable *cancellable, GError **error) { if (app->priv->session_bus == NULL) app->priv->session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, cancellable, error); if (!app->priv->session_bus) return FALSE; if (!app->priv->dbus_path) app->priv->dbus_path = application_path_from_appid (app->priv->appid); return TRUE; } static gboolean _g_application_platform_register (GApplication *app, gboolean *unique, GCancellable *cancellable, GError **error) { GVariant *request_result; guint32 request_status; gboolean result; guint registration_id; /* Callers should have verified this */ g_assert (app->priv->registration_tried == FALSE); app->priv->registration_tried = TRUE; registration_id = g_dbus_connection_register_object (app->priv->session_bus, app->priv->dbus_path, (GDBusInterfaceInfo *) &application_dbus_interface_info, &application_dbus_vtable, app, NULL, error); if (registration_id == 0) return FALSE; request_result = g_dbus_connection_call_sync (app->priv->session_bus, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "RequestName", g_variant_new ("(su)", app->priv->appid, 0x4), NULL, 0, -1, cancellable, error); if (request_result == NULL) { result = FALSE; goto done; } if (g_variant_is_of_type (request_result, G_VARIANT_TYPE ("(u)"))) g_variant_get (request_result, "(u)", &request_status); else request_status = 0; g_variant_unref (request_result); *unique = (request_status == 1 || request_status == 4); result = TRUE; if (*unique) { app->priv->is_remote = FALSE; } else { GVariantBuilder builder; GVariant *message; GVariant *result; g_variant_builder_init (&builder, G_VARIANT_TYPE ("(aaya{sv})")); g_variant_builder_add_value (&builder, app->priv->argv); g_variant_builder_add_value (&builder, app->priv->platform_data); message = g_variant_builder_end (&builder); result = g_dbus_connection_call_sync (app->priv->session_bus, app->priv->appid, app->priv->dbus_path, G_APPLICATION_IFACE, "Activate", message, NULL, 0, -1, NULL, NULL); if (result) g_variant_unref (result); if (app->priv->default_quit) exit (0); } done: if (!result) g_dbus_connection_unregister_object (app->priv->session_bus, registration_id); return result; } static void _g_application_platform_on_actions_changed (GApplication *app) { g_dbus_connection_emit_signal (app->priv->session_bus, NULL, app->priv->dbus_path, G_APPLICATION_IFACE, "ActionsChanged", NULL, NULL); } static void _g_application_platform_remote_invoke_action (GApplication *app, const gchar *action, GVariant *platform_data) { GVariant *result; result = g_dbus_connection_call_sync (app->priv->session_bus, app->priv->appid, app->priv->dbus_path, G_APPLICATION_IFACE, "InvokeAction", g_variant_new ("(s@a{sv})", action, platform_data), NULL, 0, -1, NULL, NULL); if (result) g_variant_unref (result); } static void _g_application_platform_remote_quit (GApplication *app, GVariant *platform_data) { GVariant *result; result = g_dbus_connection_call_sync (app->priv->session_bus, app->priv->appid, app->priv->dbus_path, G_APPLICATION_IFACE, "Quit", g_variant_new ("(@a{sv})", platform_data), NULL, 0, -1, NULL, NULL); if (result) g_variant_unref (result); }