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