Implement bash completion for gsettings
[platform/upstream/glib.git] / gio / gdbusapplication.c
1 /* GIO - GLib Input, Output and Streaming Library
2  *
3  * Copyright © 2010 Red Hat, Inc
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Authors: Colin Walters <walters@verbum.org>
21  */
22
23 #define G_APPLICATION_IFACE "org.gtk.Application"
24
25 static void
26 application_dbus_method_call (GDBusConnection       *connection,
27                               const gchar           *sender,
28                               const gchar           *object_path,
29                               const gchar           *interface_name,
30                               const gchar           *method_name,
31                               GVariant              *parameters,
32                               GDBusMethodInvocation *invocation,
33                               gpointer               user_data)
34 {
35   GApplication *app = G_APPLICATION (user_data);
36
37   if (method_name == NULL && *method_name == '\0')
38     return;
39
40   if (strcmp (method_name, "Quit") == 0)
41     {
42       GVariant *platform_data;
43
44       g_variant_get (parameters, "(@a{sv})", &platform_data);
45
46       g_dbus_method_invocation_return_value (invocation, NULL);
47
48       g_application_quit_with_data (app, platform_data);
49
50       g_variant_unref (platform_data);
51     }
52   else if (strcmp (method_name, "ListActions") == 0)
53     {
54       GHashTableIter iter;
55       GApplicationAction *value;
56       GVariantBuilder builder;
57
58       g_variant_builder_init (&builder, G_VARIANT_TYPE ("(a{s(sb)})"));
59       g_variant_builder_open (&builder, G_VARIANT_TYPE ("a{s(sb)}"));
60       g_hash_table_iter_init (&iter, app->priv->actions);
61       while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&value))
62         g_variant_builder_add (&builder, "{s(sb)}",
63                                value->name,
64                                value->description ? value->description : "",
65                                value->enabled);
66       g_variant_builder_close (&builder);
67
68       g_dbus_method_invocation_return_value (invocation,
69                                              g_variant_builder_end (&builder));
70     }
71   else if (strcmp (method_name, "InvokeAction") == 0)
72     {
73       const char *action_name;
74       GVariant *platform_data;
75       GApplicationAction *action;
76
77       g_variant_get (parameters, "(&s@a{sv})", &action_name, &platform_data);
78
79       action = g_hash_table_lookup (app->priv->actions, action_name);
80
81       if (!action)
82         {
83           char *errmsg  = g_strdup_printf ("Invalid action: %s", action_name);
84           g_dbus_method_invocation_return_dbus_error (invocation, G_APPLICATION_IFACE ".InvalidAction", errmsg);
85           g_free (errmsg);
86           g_variant_unref (platform_data);
87           return;
88         }
89
90       g_signal_emit (app, application_signals[ACTION_WITH_DATA],
91                      g_quark_from_string (action_name), action_name, platform_data);
92
93       g_dbus_method_invocation_return_value (invocation, NULL);
94       g_variant_unref (platform_data);
95     }
96   else if (strcmp (method_name, "Activate") == 0)
97     {
98       GVariant *args;
99       GVariant *platform_data;
100
101       g_variant_get (parameters, "(@aay@a{sv})", &args, &platform_data);
102
103       g_signal_emit (app, application_signals[PREPARE_ACTIVATION], 0, args, platform_data);
104
105       g_variant_unref (args);
106       g_variant_unref (platform_data);
107
108       g_dbus_method_invocation_return_value (invocation, NULL);
109     }
110 }
111
112 static const GDBusArgInfo application_quit_in_args[] =
113 {
114   {
115     -1,
116     "platform_data",
117     "a{sv}",
118     NULL
119   }
120 };
121
122 static const GDBusArgInfo * const application_quit_in_args_p[] = {
123   &application_quit_in_args[0],
124   NULL
125 };
126
127 static const GDBusArgInfo application_list_actions_out_args[] =
128 {
129   {
130     -1,
131     "actions",
132     "a{s(sb)}",
133     NULL
134   }
135 };
136
137 static const GDBusArgInfo * const application_list_actions_out_args_p[] = {
138   &application_list_actions_out_args[0],
139   NULL
140 };
141
142 static const GDBusArgInfo application_invoke_action_in_args[] =
143 {
144   {
145     -1,
146     "action",
147     "s",
148     NULL
149   },
150   {
151     -1,
152     "platform_data",
153     "a{sv}",
154     NULL
155   }
156 };
157
158 static const GDBusArgInfo * const application_invoke_action_in_args_p[] = {
159   &application_invoke_action_in_args[0],
160   &application_invoke_action_in_args[1],
161   NULL
162 };
163
164 static const GDBusMethodInfo application_quit_method_info =
165 {
166   -1,
167   "Quit",
168   (GDBusArgInfo **) &application_quit_in_args_p,
169   NULL,
170   NULL
171 };
172
173 static const GDBusMethodInfo application_list_actions_method_info =
174 {
175   -1,
176   "ListActions",
177   NULL,
178   (GDBusArgInfo **) &application_list_actions_out_args_p,
179   NULL
180 };
181
182 static const GDBusMethodInfo application_invoke_action_method_info =
183 {
184   -1,
185   "InvokeAction",
186   (GDBusArgInfo **) &application_invoke_action_in_args_p,
187   NULL,
188   NULL
189 };
190
191 static const GDBusArgInfo application_activate_in_args[] =
192 {
193   {
194     -1,
195     "arguments",
196     "aay",
197     NULL
198   },
199   {
200     -1,
201     "data",
202     "a{sv}",
203     NULL
204   }
205 };
206
207 static const GDBusArgInfo * const application_activate_in_args_p[] = {
208   &application_activate_in_args[0],
209   &application_activate_in_args[1],
210   NULL
211 };
212
213 static const GDBusMethodInfo application_activate_method_info =
214 {
215   -1,
216   "Activate",
217   (GDBusArgInfo **) &application_activate_in_args_p,
218   NULL,
219   NULL
220 };
221
222 static const GDBusMethodInfo * const application_dbus_method_info_p[] =
223 {
224   &application_quit_method_info,
225   &application_list_actions_method_info,
226   &application_invoke_action_method_info,
227   &application_activate_method_info,
228   NULL
229 };
230
231 static const GDBusSignalInfo application_dbus_signal_info[] =
232 {
233   {
234     -1,
235     "ActionsChanged",
236     NULL,
237     NULL
238   }
239 };
240
241 static const GDBusSignalInfo * const application_dbus_signal_info_p[] = {
242   &application_dbus_signal_info[0],
243   NULL
244 };
245
246 static const GDBusInterfaceInfo application_dbus_interface_info =
247 {
248   -1,
249   G_APPLICATION_IFACE,
250   (GDBusMethodInfo **) application_dbus_method_info_p,
251   (GDBusSignalInfo **) application_dbus_signal_info_p,
252   NULL,
253 };
254
255 static GDBusInterfaceVTable application_dbus_vtable =
256 {
257   application_dbus_method_call,
258   NULL,
259   NULL
260 };
261
262 static gchar *
263 application_path_from_appid (const gchar *appid)
264 {
265   gchar *appid_path, *iter;
266
267
268   appid_path = g_strconcat ("/", appid, NULL);
269   for (iter = appid_path; *iter; iter++)
270     {
271       if (*iter == '.')
272         *iter = '/';
273     }
274
275   return appid_path;
276 }
277
278 static gboolean
279 _g_application_platform_init (GApplication  *app,
280                               GCancellable  *cancellable,
281                               GError       **error)
282 {
283   if (app->priv->session_bus == NULL)
284     app->priv->session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, cancellable, error);
285   if (!app->priv->session_bus)
286     return FALSE;
287
288   if (!app->priv->dbus_path)
289     app->priv->dbus_path = application_path_from_appid (app->priv->appid);
290   return TRUE;
291 }
292
293 static gboolean
294 _g_application_platform_register (GApplication  *app,
295                                   gboolean      *unique,
296                                   GCancellable  *cancellable,
297                                   GError       **error)
298 {
299   GVariant *request_result;
300   guint32 request_status;
301   gboolean result;
302   guint registration_id;
303
304   registration_id = g_dbus_connection_register_object (app->priv->session_bus,
305                                                        app->priv->dbus_path,
306                                                        &application_dbus_interface_info,
307                                                        &application_dbus_vtable,
308                                                        app,
309                                                        NULL,
310                                                        error);
311   if (registration_id == 0)
312     return FALSE;
313
314   request_result = g_dbus_connection_call_sync (app->priv->session_bus,
315                                                 "org.freedesktop.DBus",
316                                                 "/org/freedesktop/DBus",
317                                                 "org.freedesktop.DBus",
318                                                 "RequestName",
319                                                 g_variant_new ("(su)", app->priv->appid, 0x4),
320                                                 NULL, 0, -1, cancellable, error);
321
322   if (request_result == NULL)
323     {
324       result = FALSE;
325       goto done;
326     }
327
328   if (g_variant_is_of_type (request_result, G_VARIANT_TYPE ("(u)")))
329     g_variant_get (request_result, "(u)", &request_status);
330   else
331     request_status = 0;
332
333   g_variant_unref (request_result);
334
335   *unique = (request_status == 1 || request_status == 4);
336   result = TRUE;
337
338   if (*unique)
339     {
340       app->priv->is_remote = FALSE;
341     }
342   else if (app->priv->default_quit)
343     {
344       GVariantBuilder builder;
345       GVariant *message;
346       GVariant *result;
347
348       g_variant_builder_init (&builder, G_VARIANT_TYPE ("(aaya{sv})"));
349       g_variant_builder_add_value (&builder, app->priv->argv);
350       g_variant_builder_add_value (&builder, app->priv->platform_data);
351       message = g_variant_builder_end (&builder);
352
353       result = g_dbus_connection_call_sync (app->priv->session_bus,
354                                             app->priv->appid,
355                                             app->priv->dbus_path,
356                                             G_APPLICATION_IFACE,
357                                             "Activate",
358                                             message,
359                                             NULL, 0, -1, NULL, NULL);
360
361       if (result)
362         g_variant_unref (result);
363
364       exit (0);
365     }
366
367 done:
368   if (!result)
369     g_dbus_connection_unregister_object (app->priv->session_bus, registration_id);
370
371   return result;
372 }
373
374 static void
375 _g_application_platform_on_actions_changed (GApplication *app)
376 {
377   g_dbus_connection_emit_signal (app->priv->session_bus, NULL,
378                                  app->priv->dbus_path,
379                                  G_APPLICATION_IFACE,
380                                  "ActionsChanged", NULL, NULL);
381 }
382
383 static void
384 _g_application_platform_remote_invoke_action (GApplication  *app,
385                                               const gchar   *action,
386                                               GVariant      *platform_data)
387 {
388   GVariant *result;
389
390   result = g_dbus_connection_call_sync (app->priv->session_bus,
391                                         app->priv->appid,
392                                         app->priv->dbus_path,
393                                         G_APPLICATION_IFACE,
394                                         "InvokeAction",
395                                         g_variant_new ("(s@a{sv})",
396                                                        action,
397                                                        platform_data),
398                                         NULL, 0, -1, NULL, NULL);
399   if (result)
400     g_variant_unref (result);
401 }
402
403 static void
404 _g_application_platform_remote_quit (GApplication *app,
405                                      GVariant     *platform_data)
406 {
407   GVariant *result;
408
409   result = g_dbus_connection_call_sync (app->priv->session_bus,
410                                         app->priv->appid,
411                                         app->priv->dbus_path,
412                                         G_APPLICATION_IFACE,
413                                         "Quit",
414                                         g_variant_new ("(@a{sv})",
415                                                        platform_data),
416                                         NULL, 0, -1, NULL, NULL);
417   if (result)
418     g_variant_unref (result);
419 }
420