]> Pileus Git - ~andy/gtk/blob - gtk/gtkapplication.c
Add a trivial implementation of the new apis
[~andy/gtk] / gtk / gtkapplication.c
1 /*
2  * Copyright © 2010 Codethink Limited
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the licence, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  *
19  * Author: Ryan Lortie <desrt@desrt.ca>
20  */
21
22 #include "config.h"
23
24 #include "gtkapplication.h"
25
26 #include <stdlib.h>
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30 #include <string.h>
31
32 #include "gtkapplicationprivate.h"
33 #include "gtkmarshalers.h"
34 #include "gtkmain.h"
35 #include "gtkaccelmapprivate.h"
36 #include "gactionmuxer.h"
37 #include "gtkintl.h"
38
39 #ifdef GDK_WINDOWING_QUARTZ
40 #include "gtkquartz-menu.h"
41 #import <Cocoa/Cocoa.h>
42 #endif
43
44 #include <gdk/gdk.h>
45 #ifdef GDK_WINDOWING_X11
46 #include <gdk/x11/gdkx.h>
47 #endif
48
49 /**
50  * SECTION:gtkapplication
51  * @title: GtkApplication
52  * @short_description: Application class
53  *
54  * #GtkApplication is a class that handles many important aspects
55  * of a GTK+ application in a convenient fashion, without enforcing
56  * a one-size-fits-all application model.
57  *
58  * Currently, GtkApplication handles GTK+ initialization, application
59  * uniqueness, session management, provides some basic scriptability and
60  * desktop shell integration by exporting actions and menus and manages a
61  * list of toplevel windows whose life-cycle is automatically tied to the
62  * life-cycle of your application.
63  *
64  * While GtkApplication works fine with plain #GtkWindows, it is recommended
65  * to use it together with #GtkApplicationWindow.
66  *
67  * When GDK threads are enabled, GtkApplication will acquire the GDK
68  * lock when invoking actions that arrive from other processes.  The GDK
69  * lock is not touched for local action invocations.  In order to have
70  * actions invoked in a predictable context it is therefore recommended
71  * that the GDK lock be held while invoking actions locally with
72  * g_action_group_activate_action().  The same applies to actions
73  * associated with #GtkApplicationWindow and to the 'activate' and
74  * 'open' #GApplication methods.
75  *
76  * To set an application menu on a GtkApplication, use
77  * g_application_set_app_menu(). The #GMenuModel that this function
78  * expects is usually constructed using #GtkBuilder, as seen in the
79  * following example. To set a menubar that will be automatically picked
80  * up by #GApplicationWindows, use g_application_set_menubar(). GTK+
81  * makes these menus appear as expected, depending on the platform
82  * the application is running on.
83  *
84  * <figure label="Menu integration in OS X">
85  * <graphic fileref="bloatpad-osx.png" format="PNG"/>
86  * </figure>
87  *
88  * <figure label="Menu integration in GNOME">
89  * <graphic fileref="bloatpad-gnome.png" format="PNG"/>
90  * </figure>
91  *
92  * <figure label="Menu integration in Xfce">
93  * <graphic fileref="bloatpad-xfce.png" format="PNG"/>
94  * </figure>
95  *
96  * <example id="gtkapplication"><title>A simple application</title>
97  * <programlisting>
98  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../examples/bloatpad.c">
99  *  <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
100  * </xi:include>
101  * </programlisting>
102  * </example>
103  *
104  * GtkApplication optionally registers with a session manager
105  * of the users session (if you set the #GtkApplication::register-session
106  * property) and offers various functionality related to the session
107  * life-cycle.
108  *
109  * An application can be informed when the session is about to end
110  * by connecting to the #GtkApplication::quit-requested signal.
111  *
112  * An application can request the session to be ended by calling
113  * gtk_application_end_session().
114  *
115  * An application can block various ways to end the session with
116  * the gtk_application_inhibit() function. Typical use cases for
117  * this kind of inhibiting are long-running, uninterruptible operations,
118  * such as burning a CD or performing a disk backup. The session
119  * manager may not honor the inhibitor, but it can be expected to
120  * inform the user about the negative consequences of ending the
121  * session while inhibitors are present.
122  */
123
124 enum {
125   WINDOW_ADDED,
126   WINDOW_REMOVED,
127   QUIT_REQUESTED,
128   QUIT_CANCELLED,
129   QUIT,
130   LAST_SIGNAL
131 };
132
133 static guint gtk_application_signals[LAST_SIGNAL];
134
135 enum {
136   PROP_ZERO,
137   PROP_REGISTER_SESSION
138 };
139
140 G_DEFINE_TYPE (GtkApplication, gtk_application, G_TYPE_APPLICATION)
141
142 struct _GtkApplicationPrivate
143 {
144   GList *windows;
145
146   gboolean register_session;
147
148 #ifdef GDK_WINDOWING_X11
149   GDBusConnection *session_bus;
150   gchar *window_prefix;
151   guint next_id;
152
153   GDBusProxy *sm_proxy;
154   GDBusProxy *client_proxy;
155   gchar *app_id;
156   gchar *client_path;
157 #endif
158
159 #ifdef GDK_WINDOWING_QUARTZ
160   GActionMuxer *muxer;
161   GMenu *combined;
162 #endif
163 };
164
165 #ifdef GDK_WINDOWING_X11
166 static void
167 gtk_application_window_added_x11 (GtkApplication *application,
168                                   GtkWindow      *window)
169 {
170   if (application->priv->session_bus == NULL)
171     return;
172
173   if (GTK_IS_APPLICATION_WINDOW (window))
174     {
175       GtkApplicationWindow *app_window = GTK_APPLICATION_WINDOW (window);
176       gboolean success;
177
178       /* GtkApplicationWindow associates with us when it is first created,
179        * so surely it's not realized yet...
180        */
181       g_assert (!gtk_widget_get_realized (GTK_WIDGET (window)));
182
183       do
184         {
185           gchar *window_path;
186           guint window_id;
187
188           window_id = application->priv->next_id++;
189           window_path = g_strdup_printf ("%s%d", application->priv->window_prefix, window_id);
190           success = gtk_application_window_publish (app_window, application->priv->session_bus, window_path);
191           g_free (window_path);
192         }
193       while (!success);
194     }
195 }
196
197 static void
198 gtk_application_window_removed_x11 (GtkApplication *application,
199                                     GtkWindow      *window)
200 {
201   if (application->priv->session_bus == NULL)
202     return;
203
204   if (GTK_IS_APPLICATION_WINDOW (window))
205     gtk_application_window_unpublish (GTK_APPLICATION_WINDOW (window));
206 }
207
208 static gchar *
209 window_prefix_from_appid (const gchar *appid)
210 {
211   gchar *appid_path, *iter;
212
213   appid_path = g_strconcat ("/", appid, "/windows/", NULL);
214   for (iter = appid_path; *iter; iter++)
215     {
216       if (*iter == '.')
217         *iter = '/';
218
219       if (*iter == '-')
220         *iter = '_';
221     }
222
223   return appid_path;
224 }
225
226 static void gtk_application_startup_session_dbus (GtkApplication *app);
227
228
229 static void
230 gtk_application_startup_x11 (GtkApplication *application)
231 {
232   const gchar *application_id;
233
234   application_id = g_application_get_application_id (G_APPLICATION (application));
235   application->priv->session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
236   application->priv->window_prefix = window_prefix_from_appid (application_id);
237
238   gtk_application_startup_session_dbus (GTK_APPLICATION (application));
239 }
240
241 static void
242 gtk_application_shutdown_x11 (GtkApplication *application)
243 {
244   g_free (application->priv->window_prefix);
245   application->priv->window_prefix = NULL;
246   g_clear_object (&application->priv->session_bus);
247
248   g_clear_object (&application->priv->sm_proxy);
249   g_clear_object (&application->priv->client_proxy);
250   g_free (application->priv->app_id);
251   g_free (application->priv->client_path);
252 }
253 #endif
254
255 #ifdef GDK_WINDOWING_QUARTZ
256 static void
257 gtk_application_menu_changed_quartz (GObject    *object,
258                                      GParamSpec *pspec,
259                                      gpointer    user_data)
260 {
261   GtkApplication *application = GTK_APPLICATION (object);
262   GMenu *combined;
263
264   combined = g_menu_new ();
265   g_menu_append_submenu (combined, "Application", g_application_get_app_menu (application));
266   g_menu_append_section (combined, NULL, gtk_application_get_menubar (application));
267
268   gtk_quartz_set_main_menu (G_MENU_MODEL (combined), G_ACTION_OBSERVABLE (application->priv->muxer));
269 }
270
271 static void
272 gtk_application_startup_quartz (GtkApplication *application)
273 {
274   [NSApp finishLaunching];
275
276   application->priv->muxer = g_action_muxer_new ();
277   g_action_muxer_insert (application->priv->muxer, "app", G_ACTION_GROUP (application));
278
279   g_signal_connect (application, "notify::app-menu", G_CALLBACK (gtk_application_menu_changed_quartz), NULL);
280   g_signal_connect (application, "notify::menubar", G_CALLBACK (gtk_application_menu_changed_quartz), NULL);
281   gtk_application_menu_changed_quartz (G_OBJECT (application), NULL, NULL);
282 }
283
284 static void
285 gtk_application_shutdown_quartz (GtkApplication *application)
286 {
287   g_signal_handlers_disconnect_by_func (application, gtk_application_menu_changed_quartz, NULL);
288
289   g_object_unref (application->priv->muxer);
290   application->priv->muxer = NULL;
291 }
292
293 static void
294 gtk_application_focus_changed (GtkApplication *application,
295                                GtkWindow      *window)
296 {
297   if (G_IS_ACTION_GROUP (window))
298     g_action_muxer_insert (application->priv->muxer, "win", G_ACTION_GROUP (window));
299   else
300     g_action_muxer_remove (application->priv->muxer, "win");
301 }
302 #endif
303
304 static gboolean
305 gtk_application_focus_in_event_cb (GtkWindow      *window,
306                                    GdkEventFocus  *event,
307                                    GtkApplication *application)
308 {
309   GtkApplicationPrivate *priv = application->priv;
310   GList *link;
311
312   /* Keep the window list sorted by most-recently-focused. */
313   link = g_list_find (priv->windows, window);
314   if (link != NULL && link != priv->windows)
315     {
316       priv->windows = g_list_remove_link (priv->windows, link);
317       priv->windows = g_list_concat (link, priv->windows);
318     }
319
320 #ifdef GDK_WINDOWING_QUARTZ
321   gtk_application_focus_changed (application, window);
322 #endif
323
324   return FALSE;
325 }
326
327 static void
328 gtk_application_startup (GApplication *application)
329 {
330   G_APPLICATION_CLASS (gtk_application_parent_class)
331     ->startup (application);
332
333   gtk_init (0, 0);
334
335 #ifdef GDK_WINDOWING_X11
336   gtk_application_startup_x11 (GTK_APPLICATION (application));
337 #endif
338
339 #ifdef GDK_WINDOWING_QUARTZ
340   gtk_application_startup_quartz (GTK_APPLICATION (application));
341 #endif
342 }
343
344 static void
345 gtk_application_shutdown (GApplication *application)
346 {
347 #ifdef GDK_WINDOWING_X11
348   gtk_application_shutdown_x11 (GTK_APPLICATION (application));
349 #endif
350
351 #ifdef GDK_WINDOWING_QUARTZ
352   gtk_application_shutdown_quartz (GTK_APPLICATION (application));
353 #endif
354
355   G_APPLICATION_CLASS (gtk_application_parent_class)
356     ->shutdown (application);
357 }
358
359 static void
360 gtk_application_add_platform_data (GApplication    *application,
361                                    GVariantBuilder *builder)
362 {
363   const gchar *startup_id;
364
365   startup_id = getenv ("DESKTOP_STARTUP_ID");
366   
367   if (startup_id && g_utf8_validate (startup_id, -1, NULL))
368     g_variant_builder_add (builder, "{sv}", "desktop-startup-id",
369                            g_variant_new_string (startup_id));
370 }
371
372 static void
373 gtk_application_before_emit (GApplication *application,
374                              GVariant     *platform_data)
375 {
376   GVariantIter iter;
377   const gchar *key;
378   GVariant *value;
379
380   gdk_threads_enter ();
381
382   g_variant_iter_init (&iter, platform_data);
383   while (g_variant_iter_loop (&iter, "{&sv}", &key, &value))
384     {
385 #ifdef GDK_WINDOWING_X11
386       if (strcmp (key, "desktop-startup-id") == 0)
387         {
388           GdkDisplay *display;
389           const gchar *id;
390
391           display = gdk_display_get_default ();
392           id = g_variant_get_string (value, NULL);
393           if (GDK_IS_X11_DISPLAY (display))
394             gdk_x11_display_set_startup_notification_id (display, id);
395        }
396 #endif
397     }
398 }
399
400 static void
401 gtk_application_after_emit (GApplication *application,
402                             GVariant     *platform_data)
403 {
404   gdk_notify_startup_complete ();
405
406   gdk_threads_leave ();
407 }
408
409 static void
410 gtk_application_init (GtkApplication *application)
411 {
412   application->priv = G_TYPE_INSTANCE_GET_PRIVATE (application,
413                                                    GTK_TYPE_APPLICATION,
414                                                    GtkApplicationPrivate);
415 }
416
417 static void
418 gtk_application_window_added (GtkApplication *application,
419                               GtkWindow      *window)
420 {
421   GtkApplicationPrivate *priv = application->priv;
422
423   priv->windows = g_list_prepend (priv->windows, window);
424   gtk_window_set_application (window, application);
425   g_application_hold (G_APPLICATION (application));
426
427   g_signal_connect (window, "focus-in-event",
428                     G_CALLBACK (gtk_application_focus_in_event_cb),
429                     application);
430
431 #ifdef GDK_WINDOWING_X11
432   gtk_application_window_added_x11 (application, window);
433 #endif
434 }
435
436 static void
437 gtk_application_window_removed (GtkApplication *application,
438                                 GtkWindow      *window)
439 {
440   GtkApplicationPrivate *priv = application->priv;
441
442 #ifdef GDK_WINDOWING_X11
443   gtk_application_window_removed_x11 (application, window);
444 #endif
445
446   g_signal_handlers_disconnect_by_func (window,
447                                         gtk_application_focus_in_event_cb,
448                                         application);
449
450   g_application_release (G_APPLICATION (application));
451   priv->windows = g_list_remove (priv->windows, window);
452   gtk_window_set_application (window, NULL);
453 }
454
455 static void
456 extract_accel_from_menu_item (GMenuModel     *model,
457                               gint            item,
458                               GtkApplication *app)
459 {
460   GMenuAttributeIter *iter;
461   const gchar *key;
462   GVariant *value;
463   const gchar *accel = NULL;
464   const gchar *action = NULL;
465   GVariant *target = NULL;
466
467   iter = g_menu_model_iterate_item_attributes (model, item);
468   while (g_menu_attribute_iter_get_next (iter, &key, &value))
469     {
470       if (g_str_equal (key, "action") && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
471         action = g_variant_get_string (value, NULL);
472       else if (g_str_equal (key, "accel") && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
473         accel = g_variant_get_string (value, NULL);
474       else if (g_str_equal (key, "target"))
475         target = g_variant_ref (value);
476       g_variant_unref (value);
477     }
478   g_object_unref (iter);
479
480   if (accel && action)
481     gtk_application_add_accelerator (app, accel, action, target);
482
483   if (target)
484     g_variant_unref (target);
485 }
486
487 static void
488 extract_accels_from_menu (GMenuModel     *model,
489                           GtkApplication *app)
490 {
491   gint i;
492   GMenuLinkIter *iter;
493   const gchar *key;
494   GMenuModel *m;
495
496   for (i = 0; i < g_menu_model_get_n_items (model); i++)
497     {
498       extract_accel_from_menu_item (model, i, app);
499
500       iter = g_menu_model_iterate_item_links (model, i);
501       while (g_menu_link_iter_get_next (iter, &key, &m))
502         {
503           extract_accels_from_menu (m, app);
504           g_object_unref (m);
505         }
506       g_object_unref (iter);
507     }
508 }
509
510 static void
511 gtk_application_notify (GObject    *object,
512                         GParamSpec *pspec)
513 {
514   if (strcmp (pspec->name, "app-menu") == 0 ||
515       strcmp (pspec->name, "menubar") == 0)
516     {
517       GMenuModel *model;
518       g_object_get (object, pspec->name, &model, NULL);
519       if (model)
520         {
521           extract_accels_from_menu (model, GTK_APPLICATION (object));
522           g_object_unref (model);
523         }
524     }
525
526   if (G_OBJECT_CLASS (gtk_application_parent_class)->notify)
527     G_OBJECT_CLASS (gtk_application_parent_class)->notify (object, pspec);
528 }
529
530 static void
531 gtk_application_get_property (GObject    *object,
532                               guint       prop_id,
533                               GValue     *value,
534                               GParamSpec *pspec)
535 {
536   GtkApplication *application = GTK_APPLICATION (object);
537
538   switch (prop_id)
539     {
540     case PROP_REGISTER_SESSION:
541       g_value_set_boolean (value, application->priv->register_session);
542       break;
543
544     default:
545       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
546       break;
547     }
548 }
549
550 static void
551 gtk_application_set_property (GObject      *object,
552                               guint         prop_id,
553                               const GValue *value,
554                               GParamSpec   *pspec)
555 {
556   GtkApplication *application = GTK_APPLICATION (object);
557
558   switch (prop_id)
559     {
560     case PROP_REGISTER_SESSION:
561       application->priv->register_session = g_value_get_boolean (value);
562       break;
563
564     default:
565       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
566       break;
567     }
568 }
569
570 static void
571 gtk_application_class_init (GtkApplicationClass *class)
572 {
573   GObjectClass *object_class = G_OBJECT_CLASS (class);
574   GApplicationClass *application_class = G_APPLICATION_CLASS (class);
575
576   object_class->get_property = gtk_application_get_property;
577   object_class->set_property = gtk_application_set_property;
578   object_class->notify = gtk_application_notify;
579
580   application_class->add_platform_data = gtk_application_add_platform_data;
581   application_class->before_emit = gtk_application_before_emit;
582   application_class->after_emit = gtk_application_after_emit;
583   application_class->startup = gtk_application_startup;
584   application_class->shutdown = gtk_application_shutdown;
585
586   class->window_added = gtk_application_window_added;
587   class->window_removed = gtk_application_window_removed;
588
589   g_type_class_add_private (class, sizeof (GtkApplicationPrivate));
590
591   /**
592    * GtkApplication::window-added:
593    * @application: the #GtkApplication which emitted the signal
594    * @window: the newly-added #GtkWindow
595    *
596    * Emitted when a #GtkWindow is added to @application through
597    * gtk_application_add_window().
598    *
599    * Since: 3.2
600    */
601   gtk_application_signals[WINDOW_ADDED] =
602     g_signal_new ("window-added", GTK_TYPE_APPLICATION, G_SIGNAL_RUN_FIRST,
603                   G_STRUCT_OFFSET (GtkApplicationClass, window_added),
604                   NULL, NULL,
605                   g_cclosure_marshal_VOID__OBJECT,
606                   G_TYPE_NONE, 1, GTK_TYPE_WINDOW);
607
608   /**
609    * GtkApplication::window-removed:
610    * @application: the #GtkApplication which emitted the signal
611    * @window: the #GtkWindow that is being removed
612    *
613    * Emitted when a #GtkWindow is removed from @application,
614    * either as a side-effect of being destroyed or explicitly
615    * through gtk_application_remove_window().
616    *
617    * Since: 3.2
618    */
619   gtk_application_signals[WINDOW_REMOVED] =
620     g_signal_new ("window-removed", GTK_TYPE_APPLICATION, G_SIGNAL_RUN_FIRST,
621                   G_STRUCT_OFFSET (GtkApplicationClass, window_removed),
622                   NULL, NULL,
623                   g_cclosure_marshal_VOID__OBJECT,
624                   G_TYPE_NONE, 1, GTK_TYPE_WINDOW);
625
626   /**
627    * GtkApplication::quit-requested:
628    * @application: the #GtkApplication
629    *
630    * Emitted when the session manager requests that the application
631    * exit (generally because the user is logging out). The application
632    * should decide whether or not it is willing to quit and then call
633    * g_application_quit_response(), passing %TRUE or %FALSE to give its
634    * answer to the session manager. It does not need to give an answer
635    * before returning from the signal handler; the answer can be given
636    * later on, but <emphasis>the application must not attempt to perform
637    * any actions or interact with the user</emphasis> in response to
638    * this signal. Any actions required for a clean shutdown should take
639    * place in response to the #GtkApplication::quit signal.
640    *
641    * The application should limit its operations until either the
642    * #GApplication::quit or #GtkApplication::quit-cancelled signals is
643    * emitted.
644    *
645    * To receive this signal, you need to set the
646    * #GtkApplication::register-session property
647    * when creating the application object.
648    *
649    * Since: 3.4
650    */
651   gtk_application_signals[QUIT_REQUESTED] =
652     g_signal_new ("quit-requested", GTK_TYPE_APPLICATION, G_SIGNAL_RUN_LAST,
653                   G_STRUCT_OFFSET (GtkApplicationClass, quit_requested),
654                   NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
655
656   /**
657    * GtkApplication::quit-cancelled:
658    * @application: the #GtkApplication
659    *
660    * Emitted when the session manager decides to cancel a logout after
661    * the application has already agreed to quit. After receiving this
662    * signal, the application can go back to what it was doing before
663    * receiving the #GtkApplication::quit-requested signal.
664    *
665    * To receive this signal, you need to set the
666    * #GtkApplication::register-session property
667    * when creating the application object.
668    *
669    * Since: 3.4
670    */
671   gtk_application_signals[QUIT_CANCELLED] =
672     g_signal_new ("quit-cancelled", GTK_TYPE_APPLICATION, G_SIGNAL_RUN_LAST,
673                   G_STRUCT_OFFSET (GtkApplicationClass, quit_cancelled),
674                   NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
675
676   /**
677    * GtkApplication::quit:
678    * @application: the #GtkApplication
679    *
680    * Emitted when the session manager wants the application to quit
681    * (generally because the user is logging out). The application
682    * should exit as soon as possible after receiving this signal; if
683    * it does not, the session manager may choose to forcibly kill it.
684    *
685    * Normally, an application would only be sent a ::quit if it
686    * agreed to quit in response to a #GtkApplication::quit-requested
687    * signal. However, this is not guaranteed; in some situations the
688    * session manager may decide to end the session without giving
689    * applications a chance to object.
690    *
691    * To receive this signal, you need to set the
692    * #GtkApplication::register-session property
693    * when creating the application object.
694    *
695    * Since: 3.4
696    */
697   gtk_application_signals[QUIT] =
698     g_signal_new ("quit", GTK_TYPE_APPLICATION, G_SIGNAL_RUN_LAST,
699                   G_STRUCT_OFFSET (GtkApplicationClass, quit),
700                   NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
701
702   g_object_class_install_property (object_class, PROP_REGISTER_SESSION,
703     g_param_spec_boolean ("register-session",
704                           P_("Register session"),
705                           P_("Register with the session manager"),
706                           FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
707 }
708
709 /**
710  * gtk_application_new:
711  * @application_id: the application id
712  * @flags: the application flags
713  *
714  * Creates a new #GtkApplication instance.
715  *
716  * This function calls g_type_init() for you. gtk_init() is called
717  * as soon as the application gets registered as the primary instance.
718  *
719  * Note that commandline arguments are not passed to gtk_init().
720  * All GTK+ functionality that is available via commandline arguments
721  * can also be achieved by setting suitable environment variables
722  * such as <envvar>G_DEBUG</envvar>, so this should not be a big
723  * problem. If you absolutely must support GTK+ commandline arguments,
724  * you can explicitly call gtk_init() before creating the application
725  * instance.
726  *
727  * The application id must be valid. See g_application_id_is_valid().
728  *
729  * Returns: a new #GtkApplication instance
730  */
731 GtkApplication *
732 gtk_application_new (const gchar       *application_id,
733                      GApplicationFlags  flags)
734 {
735   g_return_val_if_fail (g_application_id_is_valid (application_id), NULL);
736
737   g_type_init ();
738
739   return g_object_new (GTK_TYPE_APPLICATION,
740                        "application-id", application_id,
741                        "flags", flags,
742                        NULL);
743 }
744
745 /**
746  * gtk_application_add_window:
747  * @application: a #GtkApplication
748  * @window: a #GtkWindow
749  *
750  * Adds a window from @application.
751  *
752  * This call is equivalent to setting the #GtkWindow:application
753  * property of @window to @application.
754  *
755  * Normally, the connection between the application and the window
756  * will remain until the window is destroyed, but you can explicitly
757  * remove it with gtk_application_remove_window().
758  *
759  * GTK+ will keep the application running as long as it has
760  * any windows.
761  *
762  * Since: 3.0
763  **/
764 void
765 gtk_application_add_window (GtkApplication *application,
766                             GtkWindow      *window)
767 {
768   g_return_if_fail (GTK_IS_APPLICATION (application));
769
770   if (!g_list_find (application->priv->windows, window))
771     g_signal_emit (application,
772                    gtk_application_signals[WINDOW_ADDED], 0, window);
773 }
774
775 /**
776  * gtk_application_remove_window:
777  * @application: a #GtkApplication
778  * @window: a #GtkWindow
779  *
780  * Remove a window from @application.
781  *
782  * If @window belongs to @application then this call is equivalent to
783  * setting the #GtkWindow:application property of @window to
784  * %NULL.
785  *
786  * The application may stop running as a result of a call to this
787  * function.
788  *
789  * Since: 3.0
790  **/
791 void
792 gtk_application_remove_window (GtkApplication *application,
793                                GtkWindow      *window)
794 {
795   g_return_if_fail (GTK_IS_APPLICATION (application));
796
797   if (g_list_find (application->priv->windows, window))
798     g_signal_emit (application,
799                    gtk_application_signals[WINDOW_REMOVED], 0, window);
800 }
801
802 /**
803  * gtk_application_get_windows:
804  * @application: a #GtkApplication
805  *
806  * Gets a list of the #GtkWindows associated with @application.
807  *
808  * The list is sorted by most recently focused window, such that the first
809  * element is the currently focused window. (Useful for choosing a parent
810  * for a transient window.)
811  *
812  * The list that is returned should not be modified in any way. It will
813  * only remain valid until the next focus change or window creation or
814  * deletion.
815  *
816  * Returns: (element-type GtkWindow) (transfer none): a #GList of #GtkWindow
817  *
818  * Since: 3.0
819  **/
820 GList *
821 gtk_application_get_windows (GtkApplication *application)
822 {
823   g_return_val_if_fail (GTK_IS_APPLICATION (application), NULL);
824
825   return application->priv->windows;
826 }
827
828 /**
829  * gtk_application_add_accelerator:
830  * @application: a #GtkApplication
831  * @accelerator: accelerator string
832  * @action_name: the name of the action to activate
833  * @parameter: (allow-none): parameter to pass when activating the action,
834  *   or %NULL if the action does not accept an activation parameter
835  *
836  * Installs an accelerator that will cause the named action
837  * to be activated when the key combination specificed by @accelerator
838  * is pressed.
839  *
840  * @accelerator must be a string that can be parsed by
841  * gtk_accelerator_parse(), e.g. "<Primary>q" or "<Control><Alt>p".
842  *
843  * @action_name must be the name of an action as it would be used
844  * in the app menu, i.e. actions that have been added to the application
845  * are referred to with an "app." prefix, and window-specific actions
846  * with a "win." prefix.
847  *
848  * GtkApplication also extracts accelerators out of 'accel' attributes
849  * in the #GMenuModels passed to g_application_set_app_menu() and
850  * g_application_set_menubar(), which is usually more convenient
851  * than calling this function for each accelerator.
852  *
853  * Since: 3.4
854  */
855 void
856 gtk_application_add_accelerator (GtkApplication *application,
857                                  const gchar    *accelerator,
858                                  const gchar    *action_name,
859                                  GVariant       *parameter)
860 {
861   gchar *accel_path;
862   guint accel_key;
863   GdkModifierType accel_mods;
864
865   g_return_if_fail (GTK_IS_APPLICATION (application));
866
867   /* Call this here, since gtk_init() is only getting called in startup() */
868   _gtk_accel_map_init ();
869
870   gtk_accelerator_parse (accelerator, &accel_key, &accel_mods);
871
872   if (accel_key == 0)
873     {
874       g_warning ("Failed to parse accelerator: '%s'\n", accelerator);
875       return;
876     }
877
878   accel_path = _gtk_accel_path_for_action (action_name, parameter);
879
880   if (gtk_accel_map_lookup_entry (accel_path, NULL))
881     gtk_accel_map_change_entry (accel_path, accel_key, accel_mods, TRUE);
882   else
883     gtk_accel_map_add_entry (accel_path, accel_key, accel_mods);
884
885   g_free (accel_path);
886 }
887
888 /**
889  * gtk_application_remove_accelerator:
890  * @application: a #GtkApplication
891  * @action_name: the name of the action to activate
892  * @parameter: (allow-none): parameter to pass when activating the action,
893  *   or %NULL if the action does not accept an activation parameter
894  *
895  * Removes an accelerator that has been previously added
896  * with gtk_application_add_accelerator().
897  *
898  * Since: 3.4
899  */
900 void
901 gtk_application_remove_accelerator (GtkApplication *application,
902                                     const gchar    *action_name,
903                                     GVariant       *parameter)
904 {
905   gchar *accel_path;
906
907   g_return_if_fail (GTK_IS_APPLICATION (application));
908
909   accel_path = _gtk_accel_path_for_action (action_name, parameter);
910
911   if (!gtk_accel_map_lookup_entry (accel_path, NULL))
912     {
913       g_warning ("No accelerator found for '%s'\n", accel_path);
914       g_free (accel_path);
915       return;
916     }
917
918   gtk_accel_map_change_entry (accel_path, 0, 0, FALSE);
919   g_free (accel_path);
920 }
921
922 /**
923  * gtk_application_set_app_menu:
924  * @application: a #GtkApplication
925  * @model: (allow-none): a #GMenuModel, or %NULL
926  *
927  * Sets or unsets the application menu for @application.
928  *
929  * The application menu is a single menu containing items that typically
930  * impact the application as a whole, rather than acting on a specific
931  * window or document.  For example, you would expect to see
932  * "Preferences" or "Quit" in an application menu, but not "Save" or
933  * "Print".
934  *
935  * If supported, the application menu will be rendered by the desktop
936  * environment.
937  *
938  * Since: 3.4
939  */
940 void
941 gtk_application_set_app_menu (GtkApplication *application,
942                               GMenuModel     *model)
943 {
944   g_object_set (application, "app-menu", model, NULL);
945 }
946
947 /**
948  * gtk_application_get_app_menu:
949  * @application: a #GtkApplication
950  *
951  * Returns the menu model that has been set with
952  * g_application_set_app_menu().
953  *
954  * Returns: (transfer none): the application menu of @application
955  *
956  * Since: 3.4
957  */
958 GMenuModel *
959 gtk_application_get_app_menu (GtkApplication *application)
960 {
961   GMenuModel *app_menu = NULL;
962
963   g_object_get (application, "app-menu", &app_menu, NULL);
964
965   if (app_menu)
966     g_object_unref (app_menu);
967
968   return app_menu;
969 }
970
971 /**
972  * gtk_application_set_menubar:
973  * @application: a #GtkApplication
974  * @model: (allow-none): a #GMenuModel, or %NULL
975  *
976  * Sets or unsets the menubar for windows of @application.
977  *
978  * This is a menubar in the traditional sense.
979  *
980  * Depending on the desktop environment, this may appear at the top of
981  * each window, or at the top of the screen.  In some environments, if
982  * both the application menu and the menubar are set, the application
983  * menu will be presented as if it were the first item of the menubar.
984  * Other environments treat the two as completely separate -- for
985  * example, the application menu may be rendered by the desktop shell
986  * while the menubar (if set) remains in each individual window.
987  *
988  * Since: 3.4
989  */
990 void
991 gtk_application_set_menubar (GtkApplication *application,
992                              GMenuModel     *model)
993 {
994   g_object_set (application, "menubar", model, NULL);
995 }
996
997 /**
998  * gtk_application_get_menubar:
999  * @application: a #GtkApplication
1000  *
1001  * Returns the menu model that has been set with
1002  * g_application_set_menubar().
1003  *
1004  * Returns: (transfer none): the menubar for windows of @application
1005  *
1006  * Since: 3.4
1007  */
1008 GMenuModel *
1009 gtk_application_get_menubar (GtkApplication *application)
1010 {
1011   GMenuModel *menubar = NULL;
1012
1013   g_object_get (application, "menubar", &menubar, NULL);
1014
1015   if (menubar)
1016     g_object_unref (menubar);
1017
1018   return menubar;
1019 }
1020
1021 /* D-Bus Session Management
1022  *
1023  * The protocol and the D-Bus API are described here:
1024  * http://live.gnome.org/SessionManagement/GnomeSession
1025  * http://people.gnome.org/~mccann/gnome-session/docs/gnome-session.html
1026  */
1027
1028 #ifdef GDK_WINDOWING_X11
1029
1030 /**
1031  * GtkApplicationInhibitFlags:
1032  * @GTK_APPLICATION_INHIBIT_LOGOUT: Inhibit logging out (including shutdown
1033  *     of the computer)
1034  * @GTK_APPLICATION_INHIBIT_SWITCH: Inhibit user switching
1035  * @GTK_APPLICATION_INHIBIT_SUSPEND: Inhibit suspending the
1036  *     session or computer
1037  * @GTK_APPLICATION_INHIBIT_IDLE: Inhibit the session being
1038  *     marked as idle (and possibly locked)
1039  *
1040  * Types of user actions that may be blocked by gtk_application_inhibit().
1041  *
1042  * Since: 3.4
1043  */
1044
1045 static void
1046 unregister_client (GtkApplication *app)
1047 {
1048   GError *error = NULL;
1049
1050   g_debug ("Unregistering client");
1051
1052   g_dbus_proxy_call_sync (app->priv->sm_proxy,
1053                           "UnregisterClient",
1054                           g_variant_new ("(o)", app->priv->client_path),
1055                           G_DBUS_CALL_FLAGS_NONE,
1056                           G_MAXINT,
1057                           NULL,
1058                           &error);
1059
1060   if (error)
1061     {
1062       g_warning ("Failed to unregister client: %s", error->message);
1063       g_error_free (error);
1064     }
1065
1066   g_clear_object (&app->priv->client_proxy);
1067
1068   g_free (app->priv->client_path);
1069   app->priv->client_path = NULL;
1070 }
1071
1072 static void
1073 client_proxy_signal (GDBusProxy     *proxy,
1074                      const gchar    *sender_name,
1075                      const gchar    *signal_name,
1076                      GVariant       *parameters,
1077                      GtkApplication *app)
1078 {
1079   if (strcmp (signal_name, "QueryEndSession") == 0)
1080     {
1081       g_debug ("Received QueryEndSession");
1082       g_signal_emit (app, gtk_application_signals[QUIT_REQUESTED], 0);
1083     }
1084   else if (strcmp (signal_name, "EndSession") == 0)
1085     {
1086       g_debug ("Received EndSession");
1087       gtk_application_quit_response (app, TRUE, NULL);
1088       unregister_client (app);
1089       g_signal_emit (app, gtk_application_signals[QUIT], 0);
1090     }
1091   else if (strcmp (signal_name, "CancelEndSession") == 0)
1092     {
1093       g_debug ("Received CancelEndSession");
1094       g_signal_emit (app, gtk_application_signals[QUIT_CANCELLED], 0);
1095     }
1096   else if (strcmp (signal_name, "Stop") == 0)
1097     {
1098       g_debug ("Received Stop");
1099       unregister_client (app);
1100       g_signal_emit (app, gtk_application_signals[QUIT], 0);
1101     }
1102 }
1103
1104 static void
1105 gtk_application_startup_session_dbus (GtkApplication *app)
1106 {
1107   static gchar *client_id;
1108   GError *error = NULL;
1109   GVariant *res;
1110
1111   if (app->priv->session_bus == NULL)
1112     return;
1113
1114   if (client_id == NULL)
1115     {
1116       const gchar *desktop_autostart_id;
1117
1118       desktop_autostart_id = g_getenv ("DESKTOP_AUTOSTART_ID");
1119       /* Unset DESKTOP_AUTOSTART_ID in order to avoid child processes to
1120        * use the same client id.
1121        */
1122       g_unsetenv ("DESKTOP_AUTOSTART_ID");
1123       client_id = g_strdup (desktop_autostart_id ? desktop_autostart_id : "");
1124     }
1125
1126   g_debug ("Connecting to session manager");
1127
1128   app->priv->sm_proxy = g_dbus_proxy_new_sync (app->priv->session_bus,
1129                                                G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
1130                                                G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
1131                                                NULL,
1132                                                "org.gnome.SessionManager",
1133                                                "/org/gnome/SessionManager",
1134                                                "org.gnome.SessionManager",
1135                                                NULL,
1136                                                &error);
1137   if (error)
1138     {
1139       g_warning ("Failed to get a session proxy: %s", error->message);
1140       g_error_free (error);
1141       return;
1142     }
1143
1144   /* FIXME: should we reuse the D-Bus application id here ? */
1145   app->priv->app_id = g_strdup (g_get_prgname ());
1146
1147   if (!app->priv->register_session)
1148     return;
1149
1150   g_debug ("Registering client '%s' '%s'", app->priv->app_id, client_id);
1151
1152   res = g_dbus_proxy_call_sync (app->priv->sm_proxy,
1153                                 "RegisterClient",
1154                                 g_variant_new ("(ss)", app->priv->app_id, client_id),
1155                                 G_DBUS_CALL_FLAGS_NONE,
1156                                 G_MAXINT,
1157                                 NULL,
1158                                 &error);
1159
1160   if (error)
1161     {
1162       g_warning ("Failed to register client: %s", error->message);
1163       g_error_free (error);
1164       g_clear_object (&app->priv->sm_proxy);
1165       return;
1166     }
1167
1168   g_variant_get (res, "(o)", &app->priv->client_path);
1169   g_variant_unref (res);
1170
1171   g_debug ("Registered client at '%s'", app->priv->client_path);
1172
1173   app->priv->client_proxy = g_dbus_proxy_new_sync (app->priv->session_bus, 0,
1174                                                    NULL,
1175                                                    "org.gnome.SessionManager",
1176                                                    app->priv->client_path,
1177                                                    "org.gnome.SessionManager.ClientPrivate",
1178                                                    NULL,
1179                                                    &error);
1180   if (error)
1181     {
1182       g_warning ("Failed to get client proxy: %s", error->message);
1183       g_error_free (error);
1184       g_clear_object (&app->priv->sm_proxy);
1185       g_free (app->priv->client_path);
1186       app->priv->client_path = NULL;
1187       return;
1188     }
1189
1190   g_signal_connect (app->priv->client_proxy, "g-signal", G_CALLBACK (client_proxy_signal), app);
1191 }
1192
1193 /**
1194  * gtk_application_quit_response:
1195  * @application: the #GtkApplication
1196  * @will_quit: whether the application agrees to quit
1197  * @reason: (allow-none): a short human-readable string that explains
1198  *     why quitting is not possible
1199  *
1200  * This function <emphasis>must</emphasis> be called in response to the
1201  * #GtkApplication::quit-requested signal, to indicate whether or
1202  * not the application is willing to quit. The application may call
1203  * it either directly from the signal handler, or at some later point.
1204  *
1205  * It should be stressed that <emphasis>applications should not assume
1206  * that they have the ability to block logout or shutdown</emphasis>,
1207  * even when %FALSE is passed for @will_quit.
1208  *
1209  * After calling this method, the application should wait to receive
1210  * either #GtkApplication::quit-cancelled or #GtkApplication::quit.
1211  *
1212  * If the application does not connect to #GtkApplication::quit-requested,
1213  * #GtkApplication will call this method on its behalf (passing %TRUE
1214  * for @will_quit).
1215  *
1216  * Since: 3.4
1217  */
1218 void
1219 gtk_application_quit_response (GtkApplication *application,
1220                                gboolean        will_quit,
1221                                const gchar    *reason)
1222 {
1223   g_return_if_fail (GTK_IS_APPLICATION (application));
1224   g_return_if_fail (!g_application_get_is_remote (G_APPLICATION (application)));
1225   g_return_if_fail (application->priv->client_proxy != NULL);
1226
1227   g_debug ("Calling EndSessionResponse %d '%s'", will_quit, reason);
1228
1229   g_dbus_proxy_call (application->priv->client_proxy,
1230                      "EndSessionResponse",
1231                      g_variant_new ("(bs)", will_quit, reason ? reason : ""),
1232                      G_DBUS_CALL_FLAGS_NONE,
1233                      G_MAXINT,
1234                      NULL, NULL, NULL);
1235 }
1236
1237 /**
1238  * gtk_application_inhibit:
1239  * @application: the #GApplication
1240  * @window: (allow-none): a #GtkWindow, or %NULL
1241  * @flags: what types of actions should be inhibited
1242  * @reason: (allow-none): a short, human-readable string that explains
1243  *     why these operations are inhibited
1244  *
1245  * Inform the session manager that certain types of actions should be
1246  * inhibited. This is not guaranteed to work on all platforms and for
1247  * all types of actions.
1248  *
1249  * Applications should invoke this method when they begin an operation
1250  * that should not be interrupted, such as creating a CD or DVD. The
1251  * types of actions that may be blocked are specified by the @flags
1252  * parameter. When the application completes the operation it should
1253  * call g_application_uninhibit() to remove the inhibitor.
1254  * Inhibitors are also cleared when the application exits.
1255  *
1256  * Applications should not expect that they will always be able to block
1257  * the action. In most cases, users will be given the option to force
1258  * the action to take place.
1259  *
1260  * Reasons should be short and to the point.
1261  *
1262  * If a window is passed, the session manager may point the user to
1263  * this window to find out more about why the action is inhibited.
1264  *
1265  * Returns: A non-zero cookie that is used to uniquely identify this
1266  *     request. It should be used as an argument to g_application_uninhibit()
1267  *     in order to remove the request. If the platform does not support
1268  *     inhibiting or the request failed for some reason, 0 is returned.
1269  *
1270  * Since: 3.4
1271  */
1272 guint
1273 gtk_application_inhibit (GtkApplication             *application,
1274                          GtkWindow                  *window,
1275                          GtkApplicationInhibitFlags  flags,
1276                          const gchar                *reason)
1277 {
1278   GVariant *res;
1279   GError *error = NULL;
1280   guint cookie;
1281   guint xid;
1282
1283   g_return_val_if_fail (GTK_IS_APPLICATION (application), 0);
1284   g_return_val_if_fail (!g_application_get_is_remote (G_APPLICATION (application)), 0);
1285   g_return_val_if_fail (application->priv->sm_proxy != NULL, 0);
1286
1287   g_debug ("Calling Inhibit\n");
1288
1289   if (window != NULL)
1290     xid = GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (window)));
1291   else
1292     xid = 0;
1293
1294   res = g_dbus_proxy_call_sync (application->priv->sm_proxy,
1295                                 "Inhibit",
1296                                 g_variant_new ("(susu)",
1297                                                application->priv->app_id,
1298                                                xid,
1299                                                reason,
1300                                                flags),
1301                                 G_DBUS_CALL_FLAGS_NONE,
1302                                 G_MAXINT,
1303                                 NULL,
1304                                 &error);
1305  if (error)
1306     {
1307       g_warning ("Calling Inhibit failed: %s\n", error->message);
1308       g_error_free (error);
1309       return 0;
1310     }
1311
1312   g_variant_get (res, "(u)", &cookie);
1313   g_variant_unref (res);
1314
1315   return cookie;
1316 }
1317
1318 /**
1319  * gtk_application_uninhibit:
1320  * @application: the #GApplication
1321  * @cookie: a cookie that was returned by g_application_inhibit()
1322  *
1323  * Removes an inhibitor that has been established with g_application_inhibit().
1324  * Inhibitors are also cleared when the application exits.
1325  *
1326  * Since: 3.4
1327  */
1328 void
1329 gtk_application_uninhibit (GtkApplication *application,
1330                            guint           cookie)
1331 {
1332   g_return_if_fail (GTK_IS_APPLICATION (application));
1333   g_return_if_fail (!g_application_get_is_remote (G_APPLICATION (application)));
1334   g_return_if_fail (application->priv->sm_proxy != NULL);
1335
1336   g_dbus_proxy_call (application->priv->sm_proxy,
1337                      "Uninhibit",
1338                      g_variant_new ("(u)", cookie),
1339                      G_DBUS_CALL_FLAGS_NONE,
1340                      G_MAXINT,
1341                      NULL, NULL, NULL);
1342 }
1343
1344 /**
1345  * gtk_application_is_inhibited:
1346  * @application: the #GApplication
1347  * @flags: what types of actions should be queried
1348  *
1349  * Determines if any of the actions specified in @flags are
1350  * currently inhibited (possibly by another application).
1351  *
1352  * Returns: %TRUE if any of the actions specified in @flags are inhibited
1353  *
1354  * Since: 3.4
1355  */
1356 gboolean
1357 gtk_application_is_inhibited (GtkApplication             *application,
1358                               GtkApplicationInhibitFlags  flags)
1359 {
1360   GVariant *res;
1361   GError *error = NULL;
1362   gboolean inhibited;
1363
1364   g_return_val_if_fail (GTK_IS_APPLICATION (application), FALSE);
1365   g_return_val_if_fail (!g_application_get_is_remote (G_APPLICATION (application)), FALSE);
1366   g_return_val_if_fail (application->priv->sm_proxy != NULL, FALSE);
1367
1368   g_debug ("Calling IsInhibited\n");
1369
1370   res = g_dbus_proxy_call_sync (application->priv->sm_proxy,
1371                                 "IsInhibited",
1372                                 g_variant_new ("(u)", flags),
1373                                 G_DBUS_CALL_FLAGS_NONE,
1374                                 G_MAXINT,
1375                                 NULL,
1376                                 &error);
1377   if (error)
1378     {
1379       g_warning ("Calling IsInhibited failed: %s\n", error->message);
1380       g_error_free (error);
1381       return FALSE;
1382     }
1383
1384   g_variant_get (res, "(b)", &inhibited);
1385   g_variant_unref (res);
1386
1387   return inhibited;
1388 }
1389
1390 /**
1391  * GtkApplicationEndStyle:
1392  * @GTK_APPLICATION_LOGOUT: End the session by logging out.
1393  * @GTK_APPLICATION_REBOOT: Restart the computer.
1394  * @GTK_APPLICATION_SHUTDOWN: Shut the computer down.
1395  *
1396  * Different ways to end a user session, for use with
1397  * gtk_application_end_session().
1398  */
1399
1400 /**
1401  * gtk_application_end_session:
1402  * @application: the #GtkApplication
1403  * @style: the desired kind of session end
1404  * @request_confirmation: whether or not the user should get a chance
1405  *     to confirm the action
1406  *
1407  * Requests that the session manager end the current session.
1408  * @style indicates how the session should be ended, and
1409  * @request_confirmation indicates whether or not the user should be
1410  * given a chance to confirm the action. Both of these flags are merely
1411  * hints though; the session manager may choose to ignore them.
1412  *
1413  * Return value: %TRUE if the request was sent; %FALSE if it could not
1414  *     be sent (eg, because it could not connect to the session manager)
1415  *
1416  * Since: 3.4
1417  */
1418 gboolean
1419 gtk_application_end_session (GtkApplication         *application,
1420                              GtkApplicationEndStyle  style,
1421                              gboolean                request_confirmation)
1422 {
1423   g_return_val_if_fail (GTK_IS_APPLICATION (application), FALSE);
1424   g_return_val_if_fail (!g_application_get_is_remote (G_APPLICATION (application)), FALSE);
1425   g_return_val_if_fail (application->priv->sm_proxy != NULL, FALSE);
1426
1427   switch (style)
1428     {
1429     case GTK_APPLICATION_LOGOUT:
1430       g_dbus_proxy_call (application->priv->sm_proxy,
1431                          "Logout",
1432                          g_variant_new ("(u)", request_confirmation),
1433                          G_DBUS_CALL_FLAGS_NONE,
1434                          G_MAXINT,
1435                          NULL, NULL, NULL);
1436       break;
1437     case GTK_APPLICATION_REBOOT:
1438     case GTK_APPLICATION_SHUTDOWN:
1439       g_dbus_proxy_call (application->priv->sm_proxy,
1440                          "Shutdown",
1441                          NULL,
1442                          G_DBUS_CALL_FLAGS_NONE,
1443                          G_MAXINT,
1444                          NULL, NULL, NULL);
1445       break;
1446     }
1447
1448 #else
1449
1450 /* Trivial implementation.
1451  *
1452  * EggSMClient has working Win32 and OSX implementations of
1453  * ::quit-requested, ::quit, ::quit-cancelled that should be
1454  * copied here eventually.
1455  *
1456  * For the inhibit API, see
1457  * http://msdn.microsoft.com/en-us/library/ms700677%28VS.85%29.aspx
1458  */
1459
1460 void
1461 gtk_application_quit_response (GtkApplication *application,
1462                                gboolean        will_quit,
1463                                const gchar    *reason)
1464 {
1465 }
1466
1467 guint
1468 gtk_application_inhibit (GtkApplication             *application,
1469                          GtkWindow                  *window,
1470                          GtkApplicationInhibitFlags  flags,
1471                          const gchar                *reason)
1472 {
1473   return 0;
1474 }
1475
1476 void
1477 gtk_application_uninhibit (GtkApplication *application,
1478                            guint           cookie)
1479 {
1480 }
1481
1482 gboolean
1483 gtk_application_is_inhibited (GtkApplication             *application,
1484                               GtkApplicationInhibitFlags  flags)
1485 {
1486   return FALSE;
1487 }
1488
1489 gboolean
1490 gtk_application_end_session (GtkApplication         *application,
1491                              GtkApplicationEndStyle *style,
1492                              gboolean                request_confirmation)
1493 {
1494   return FALSE;
1495 }
1496
1497 #endif