]> Pileus Git - ~andy/gtk/blob - gtk/gtkapplication.c
22660321ab6f5d548ccc324f016ec846b7cacfa7
[~andy/gtk] / gtk / gtkapplication.c
1 /* GTK - The GIMP Toolkit
2  *
3  * Copyright (C) 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 Public
16  * 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  * Author: Colin Walters <walters@verbum.org>
21  */
22
23 /*
24  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
25  * file for a list of people on the GTK+ Team.  See the ChangeLog
26  * files for a list of changes.  These files are distributed with
27  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
28  */
29
30 #include "config.h"
31
32 #include <stdlib.h>
33 #include <unistd.h>
34
35 #include "gtkapplication.h"
36 #include "gtkmain.h"
37 #include "gtkmarshalers.h"
38 #include "gtkintl.h"
39 #include "gtkprivate.h"
40
41 #include "gtkalias.h"
42
43 #include <gdk/gdk.h>
44 #ifdef GDK_WINDOWING_X11
45 #include <gdk/x11/gdkx.h>
46 #endif
47
48 /**
49  * SECTION:gtkapplication
50  * @title: GtkApplication
51  * @short_description: Application class
52  *
53  * #GtkApplication is a class that handles many important aspects
54  * of a GTK+ application in a convenient fashion, without enforcing
55  * a one-size-fits-all application model.
56  *
57  * Currently, GtkApplication handles application uniqueness, provides
58  * some basic scriptability by exporting 'actions', implements some
59  * standard actions itself (such as 'Quit') and provides a main window
60  * whose life-cycle is automatically tied to the life-cycle of your
61  * application.
62  *
63  * <example id="gtkapplication"><title>A simple application</title>
64  * <programlisting>
65  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gtk/tests/gtk-example-application.c">
66  *  <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
67  * </xi:include>
68  * </programlisting>
69  * </example>
70  */
71 enum
72 {
73   PROP_0,
74   PROP_WINDOW
75 };
76
77 enum
78 {
79   ACTIVATED,
80   QUIT,
81   ACTION,
82
83   LAST_SIGNAL
84 };
85
86 static guint gtk_application_signals[LAST_SIGNAL] = { 0 };
87
88 struct _GtkApplicationPrivate
89 {
90   GtkActionGroup *main_actions;
91
92   GtkWindow *default_window;
93   GSList *windows;
94 };
95
96 G_DEFINE_TYPE (GtkApplication, gtk_application, G_TYPE_APPLICATION)
97
98 static void
99 process_timestamp_from_platform_data (GVariant *platform_data)
100 {
101   /* TODO - extract timestamp from here, update GDK time */
102 }
103
104 static gboolean
105 gtk_application_default_quit (GtkApplication *application)
106 {
107   gtk_main_quit ();
108   return TRUE;
109 }
110
111 static gboolean
112 gtk_application_default_quit_with_data (GApplication *application,
113                                         GVariant     *platform_data)
114 {
115   gboolean result;
116
117   process_timestamp_from_platform_data (platform_data);
118   
119   g_signal_emit (application, gtk_application_signals[QUIT], 0, &result);
120
121   return result;
122 }
123
124 static void
125 gtk_application_default_run (GApplication *application)
126 {
127   gtk_main ();
128 }
129
130 static void
131 gtk_application_default_prepare_activation (GApplication *application,
132                                             GVariant     *arguments,
133                                             GVariant     *platform_data)
134 {
135   GVariantIter iter;
136   gchar *key;
137   GVariant *value;
138
139   g_variant_iter_init (&iter, platform_data);
140   while (g_variant_iter_next (&iter, "{&sv}", &key, &value))
141     {
142       if (strcmp (key, "startup-notification-id") == 0 &&
143           g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
144         gdk_notify_startup_complete_with_id (g_variant_get_string (value, NULL));
145       g_variant_unref (value);
146     }
147   
148   g_signal_emit (G_OBJECT (application), gtk_application_signals[ACTIVATED], 0, arguments);
149 }
150
151 static void
152 gtk_application_default_activated (GtkApplication *application,
153                                    GVariant     *arguments)
154 {
155   GtkApplication *app = GTK_APPLICATION (application);
156
157   /* TODO: should we raise the last focused window instead ? */
158   if (app->priv->default_window != NULL)
159     gtk_window_present (app->priv->default_window);
160 }
161
162 static void
163 gtk_application_default_action (GtkApplication *application,
164                                 const gchar    *action_name)
165 {
166   GtkAction *action;
167
168   action = gtk_action_group_get_action (application->priv->main_actions, action_name);
169   if (action)
170     {
171       gtk_action_activate (action);
172     }
173 }
174                                 
175 static void
176 gtk_application_default_action_with_data (GApplication *application,
177                                           const gchar  *action_name,
178                                           GVariant     *platform_data)
179 {
180   process_timestamp_from_platform_data (platform_data);
181
182   g_signal_emit (application, gtk_application_signals[ACTION], g_quark_from_string (action_name));
183 }
184
185 static GVariant *
186 gtk_application_format_activation_data (void)
187 {
188   const gchar *startup_id = NULL;
189   GdkDisplay *display = gdk_display_get_default ();
190   GVariantBuilder builder;
191
192   g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
193
194   /* try and get the startup notification id from GDK, the environment
195    * or, if everything else failed, fake one.
196    */
197 #ifdef GDK_WINDOWING_X11
198   startup_id = gdk_x11_display_get_startup_notification_id (display);
199 #endif /* GDK_WINDOWING_X11 */
200
201   if (startup_id)
202     g_variant_builder_add (&builder, "{sv}", "startup-notification-id",
203                            g_variant_new ("s", startup_id));
204   return g_variant_builder_end (&builder);
205 }
206
207 /**
208  * gtk_application_new:
209  * @argc: (allow-none) (inout): System argument count
210  * @argv: (allow-none) (inout): System argument vector
211  * @appid: System-dependent application identifier
212  *
213  * Create a new #GtkApplication, or if one has already been initialized
214  * in this process, return the existing instance. This function will as
215  * a side effect initialize the display system; see gtk_init().
216  *
217  * For the behavior if this application is running in another process,
218  * see g_application_new().
219  *
220  * Returns: (transfer full): A newly-referenced #GtkApplication
221  *
222  * Since: 3.0
223  */
224 GtkApplication*
225 gtk_application_new (gint          *argc,
226                      gchar       ***argv,
227                      const gchar   *appid)
228 {
229   GtkApplication *app;
230   gint argc_for_app;
231   gchar **argv_for_app;
232   GVariant *platform_data;
233
234   gtk_init (argc, argv);
235
236   if (argc)
237     argc_for_app = *argc;
238   else
239     argc_for_app = 0;
240   if (argv)
241     argv_for_app = *argv;
242   else
243     argv_for_app = NULL;
244
245   app = g_object_new (GTK_TYPE_APPLICATION, "application-id", appid, NULL);
246
247   platform_data = gtk_application_format_activation_data ();
248   g_application_register_with_data (G_APPLICATION (app), argc_for_app, argv_for_app,
249                                     platform_data);
250   g_variant_unref (platform_data);
251
252   return app;
253 }
254
255 static void
256 on_action_sensitive (GtkAction      *action,
257                      GParamSpec     *pspec,
258                      GtkApplication *app)
259 {
260   g_application_set_action_enabled (G_APPLICATION (app),
261                                     gtk_action_get_name (action),
262                                     gtk_action_get_sensitive (action));
263 }
264
265 /**
266  * gtk_application_set_action_group:
267  * @app: A #GtkApplication
268  * @group: A #GtkActionGroup
269  *
270  * Set @group as this application's global action group.
271  * This will ensure the operating system interface uses
272  * these actions as follows:
273  *
274  * <itemizedlist>
275  *   <listitem>In GNOME 2 this exposes the actions for scripting.</listitem>
276  *   <listitem>In GNOME 3, this function populates the application menu.</listitem>
277  *   <listitem>In Windows prior to version 7, this function does nothing.</listitem>
278  *   <listitem>In Windows 7, this function adds "Tasks" to the Jump List.</listitem>
279  *   <listitem>In Mac OS X, this function extends the Dock menu.</listitem>
280  * </itemizedlist>
281  *
282  * It is an error to call this function more than once.
283  *
284  * Since: 3.0
285  */
286 void
287 gtk_application_set_action_group (GtkApplication *app,
288                                   GtkActionGroup *group)
289 {
290   GList *actions, *iter;
291
292   g_return_if_fail (GTK_IS_APPLICATION (app));
293   g_return_if_fail (app->priv->main_actions == NULL);
294
295   app->priv->main_actions = g_object_ref (group);
296   actions = gtk_action_group_list_actions (group);
297   for (iter = actions; iter; iter = iter->next)
298     {
299       GtkAction *action = iter->data;
300       g_application_add_action (G_APPLICATION (app),
301                                 gtk_action_get_name (action),
302                                 gtk_action_get_tooltip (action));
303       g_signal_connect (action, "notify::sensitive",
304                         G_CALLBACK (on_action_sensitive), app);
305     }
306   g_list_free (actions);
307 }
308
309 static gboolean
310 gtk_application_on_window_destroy (GtkWidget *window,
311                                    gpointer   user_data)
312 {
313   GtkApplication *app = GTK_APPLICATION (user_data);
314
315   app->priv->windows = g_slist_remove (app->priv->windows, window);
316
317   if (app->priv->windows == NULL)
318     gtk_application_quit (app);
319
320   return FALSE;
321 }
322
323 static gchar *default_title;
324
325 /**
326  * gtk_application_add_window:
327  * @app: a #GtkApplication
328  * @window: a toplevel window to add to @app
329  *
330  * Adds a window to the #GtkApplication.
331  *
332  * If the user closes all of the windows added to @app, the default
333  * behaviour is to call gtk_application_quit().
334  *
335  * If your application uses only a single toplevel window, you can
336  * use gtk_application_get_window().
337  *
338  * Since: 3.0
339  */
340 void
341 gtk_application_add_window (GtkApplication *app,
342                             GtkWindow      *window)
343 {
344   app->priv->windows = g_slist_prepend (app->priv->windows, window);
345
346   if (gtk_window_get_title (window) == NULL && default_title != NULL)
347     gtk_window_set_title (window, default_title);
348
349   g_signal_connect (window, "destroy",
350                     G_CALLBACK (gtk_application_on_window_destroy), app);
351 }
352
353 /**
354  * gtk_application_get_window:
355  * @app: a #GtkApplication
356  *
357  * A simple #GtkApplication has a "default window". This window should
358  * act as the primary user interaction point with your application.
359  * The window returned by this function is of type #GTK_WINDOW_TYPE_TOPLEVEL
360  * and its properties such as "title" and "icon-name" will be initialized
361  * as appropriate for the platform.
362  *
363  * If the user closes this window, and your application hasn't created
364  * any other windows, the default action will be to call gtk_application_quit().
365  *
366  * If your application has more than one toplevel window (e.g. an
367  * single-document-interface application with multiple open documents),
368  * or if you are constructing your toplevel windows yourself (e.g. using
369  * #GtkBuilder), use gtk_application_add_window() instead.
370  *
371  * Returns: (transfer none): The default #GtkWindow for this application
372  *
373  * Since: 3.0
374  */
375 GtkWindow *
376 gtk_application_get_window (GtkApplication *app)
377 {
378   if (app->priv->default_window != NULL)
379     return app->priv->default_window;
380
381   app->priv->default_window = GTK_WINDOW (gtk_window_new (GTK_WINDOW_TOPLEVEL));
382   g_object_ref_sink (app->priv->default_window);
383
384   gtk_application_add_window (app, app->priv->default_window);
385
386   return app->priv->default_window;
387 }
388
389 /**
390  * gtk_application_run:
391  * @app: a #GtkApplication
392  *
393  * Runs the main loop; see g_application_run().
394  * The default implementation for #GtkApplication uses gtk_main().
395  *
396  * Since: 3.0
397  */
398 void
399 gtk_application_run (GtkApplication *app)
400 {
401   g_application_run (G_APPLICATION (app));
402 }
403
404 /**
405  * gtk_application_quit:
406  * @app: a #GtkApplication
407  *
408  * Request the application exit.  This function invokes
409  * g_application_quit_with_data(), which normally will
410  * in turn cause @app to emit #GtkApplication::quit.
411  *
412  * To control an application's quit behavior (for example, to ask for
413  * files to be saved), connect to the #GtkApplication::quit signal
414  * handler.
415  *
416  * Since: 3.0
417  */
418 void
419 gtk_application_quit (GtkApplication *app)
420 {
421   GVariantBuilder builder;
422   GVariant *platform_data;
423
424   g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
425   g_variant_builder_add (&builder, "{sv}",
426                          "timestamp",
427                          g_variant_new ("u",
428                                         gtk_get_current_event_time ()));
429   platform_data = g_variant_builder_end (&builder);
430     
431   g_application_quit_with_data (G_APPLICATION (app), platform_data);
432
433   g_variant_unref (platform_data);
434 }
435
436 static void
437 gtk_application_get_property (GObject    *object,
438                               guint       prop_id,
439                               GValue     *value,
440                               GParamSpec *pspec)
441 {
442   GtkApplication *app = GTK_APPLICATION (object);
443
444   switch (prop_id)
445     {
446       case PROP_WINDOW:
447         g_value_set_object (value, gtk_application_get_window (app));
448         break;
449       default:
450         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
451     }
452 }
453
454 static void
455 gtk_application_set_property (GObject      *object,
456                               guint         prop_id,
457                               const GValue *value,
458                               GParamSpec   *pspec)
459 {
460   GtkApplication *app = GTK_APPLICATION (object);
461
462   g_assert (app != NULL);
463
464   switch (prop_id)
465     {
466       default:
467         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
468     }
469 }
470
471 static void
472 setup_default_window_decorations (void)
473 {
474   const gchar *pid;
475   const gchar *filename;
476   GKeyFile *keyfile;
477   gchar *title;
478   gchar *icon_name;
479
480   pid = g_getenv ("GIO_LAUNCHED_DESKTOP_FILE_PID");
481   filename = g_getenv ("GIO_LAUNCHED_DESKTOP_FILE");
482
483   keyfile = g_key_file_new ();
484
485   if (pid != NULL && filename != NULL && atoi (pid) == getpid () &&
486       g_key_file_load_from_file (keyfile, filename, 0, NULL))
487     {
488       title = g_key_file_get_locale_string (keyfile, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NAME, NULL, NULL);
489       icon_name = g_key_file_get_string (keyfile, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_ICON, NULL);
490
491       if (default_title == NULL)
492         default_title = title;
493
494       if (gtk_window_get_default_icon_name () == NULL)
495         gtk_window_set_default_icon_name (icon_name);
496
497       g_free (icon_name);
498     }
499
500   g_key_file_free (keyfile);
501 }
502
503 static void
504 gtk_application_init (GtkApplication *application)
505 {
506   application->priv = G_TYPE_INSTANCE_GET_PRIVATE (application, GTK_TYPE_APPLICATION, GtkApplicationPrivate);
507
508   setup_default_window_decorations ();
509 }
510
511
512 static GObject*
513 gtk_application_constructor (GType                  type,
514                              guint                  n_construct_properties,
515                              GObjectConstructParam *construct_params)
516 {
517   GObject *object;
518
519   /* Last ditch effort here */
520   gtk_init (0, NULL);
521
522   object = (* G_OBJECT_CLASS (gtk_application_parent_class)->constructor) (type,
523                                                                            n_construct_properties,
524                                                                            construct_params);
525
526   return object;
527 }
528
529 static void
530 gtk_application_class_init (GtkApplicationClass *klass)
531 {
532   GObjectClass *gobject_class;
533   GApplicationClass *application_class;
534
535   gobject_class = G_OBJECT_CLASS (klass);
536   application_class = G_APPLICATION_CLASS (klass);
537
538   gobject_class->constructor = gtk_application_constructor;
539   gobject_class->get_property = gtk_application_get_property;
540   gobject_class->set_property = gtk_application_set_property;
541
542   application_class->run = gtk_application_default_run;
543   application_class->quit_with_data = gtk_application_default_quit_with_data;
544   application_class->action_with_data = gtk_application_default_action_with_data;
545   application_class->prepare_activation = gtk_application_default_prepare_activation;
546
547   klass->quit = gtk_application_default_quit;
548   klass->action = gtk_application_default_action;
549
550   klass->activated = gtk_application_default_activated;
551
552   /**
553    * GtkApplication::activated:
554    * @arguments: A #GVariant with the signature "aay"
555    *
556    * This signal is emitted when a non-primary process for a given
557    * application is invoked while your application is running; for
558    * example, when a file browser launches your program to open a
559    * file.  The raw operating system arguments are passed in the
560    * variant @arguments.
561    */
562
563   gtk_application_signals[ACTIVATED] =
564     g_signal_new (g_intern_static_string ("activated"),
565                   G_OBJECT_CLASS_TYPE (klass),
566                   G_SIGNAL_RUN_LAST,
567                   G_STRUCT_OFFSET (GtkApplicationClass, activated),
568                   NULL, NULL,
569                   g_cclosure_marshal_VOID__BOXED,
570                   G_TYPE_NONE, 1,
571                   G_TYPE_VARIANT);
572
573   /**
574    * GtkApplication::quit:
575    * @application: the object on which the signal is emitted
576    *
577    * This signal is emitted when a quit is initiated.  See also
578    * the #GApplication::quit-with-data signal which may in
579    * turn trigger this signal.
580    *
581    * The default handler for this signal exits the mainloop of the
582    * application.
583    *
584    * Returns: %TRUE if the signal has been handled, %FALSE to continue
585    *   signal emission
586    */
587   gtk_application_signals[QUIT] =
588     g_signal_new (g_intern_static_string ("quit"),
589                   G_OBJECT_CLASS_TYPE (klass),
590                   G_SIGNAL_RUN_LAST,
591                   G_STRUCT_OFFSET (GtkApplicationClass, quit),
592                   g_signal_accumulator_true_handled, NULL,
593                   _gtk_marshal_BOOLEAN__VOID,
594                   G_TYPE_BOOLEAN, 0);
595
596   /**
597    * GtkApplication::action:
598    * @application: the object on which the signal is emitted
599    * @name: The name of the activated action
600    *
601    * This signal is emitted when an action is activated. The action name
602    * is passed as the first argument, but also as signal detail, so it
603    * is possible to connect to this signal for individual actions.
604    *
605    * See also the #GApplication::action-with-data signal which may in
606    * turn trigger this signal.
607    *
608    * The signal is never emitted for disabled actions.
609    */
610   gtk_application_signals[ACTION] =
611     g_signal_new (g_intern_static_string ("action"),
612                   G_OBJECT_CLASS_TYPE (klass),
613                   G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED,
614                   G_STRUCT_OFFSET (GtkApplicationClass, action),
615                   NULL, NULL,
616                   g_cclosure_marshal_VOID__STRING,
617                   G_TYPE_NONE, 1,
618                   G_TYPE_STRING);
619                  
620   g_type_class_add_private (gobject_class, sizeof (GtkApplicationPrivate));
621 }
622
623 #define __GTK_APPLICATION_C__
624 #include "gtkaliasdef.c"