]> Pileus Git - ~andy/gtk/blob - gtk/gtkapplication.c
Merge branch 'master' into broadway2
[~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 <stdlib.h>
25 #ifdef HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
28 #include <string.h>
29
30 #include "gtkapplication.h"
31 #include "gtkmarshalers.h"
32 #include "gtkwindow.h"
33 #include "gtkmain.h"
34
35 #include <gdk/gdk.h>
36 #ifdef GDK_WINDOWING_X11
37 #include <gdk/x11/gdkx.h>
38 #endif
39
40 /**
41  * SECTION:gtkapplication
42  * @title: GtkApplication
43  * @short_description: Application class
44  *
45  * #GtkApplication is a class that handles many important aspects
46  * of a GTK+ application in a convenient fashion, without enforcing
47  * a one-size-fits-all application model.
48  *
49  * Currently, GtkApplication handles GTK+ initialization, application
50  * uniqueness, provides some basic scriptability by exporting 'actions',
51  * and manages a list of toplevel windows whose life-cycle is automatically
52  * tied to the life-cycle of your application.
53  *
54  * <example id="gtkapplication"><title>A simple application</title>
55  * <programlisting>
56  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../examples/bloatpad.c">
57  *  <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
58  * </xi:include>
59  * </programlisting>
60  * </example>
61  */
62
63 G_DEFINE_TYPE (GtkApplication, gtk_application, G_TYPE_APPLICATION)
64
65 struct _GtkApplicationPrivate
66 {
67   GList *windows;
68 };
69
70 static void
71 gtk_application_startup (GApplication *application)
72 {
73   gtk_init (0, 0);
74 }
75
76 static void
77 gtk_application_quit_mainloop (GApplication *application)
78 {
79   gtk_main_quit ();
80 }
81
82 static void
83 gtk_application_run_mainloop (GApplication *application)
84 {
85   gtk_main ();
86 }
87
88 static void
89 gtk_application_add_platform_data (GApplication    *application,
90                                    GVariantBuilder *builder)
91 {
92   const gchar *startup_id;
93
94   startup_id = getenv ("DESKTOP_STARTUP_ID");
95   
96   if (startup_id && g_utf8_validate (startup_id, -1, NULL))
97     g_variant_builder_add (builder, "{sv}", "desktop-startup-id",
98                            g_variant_new_string (startup_id));
99 }
100
101 static void
102 gtk_application_before_emit (GApplication *application,
103                              GVariant     *platform_data)
104 {
105   GVariantIter iter;
106   const gchar *key;
107   GVariant *value;
108
109   g_variant_iter_init (&iter, platform_data);
110   while (g_variant_iter_loop (&iter, "{&sv}", &key, &value))
111     {
112 #ifdef GDK_WINDOWING_X11
113       if (strcmp (key, "desktop-startup-id") == 0)
114         {
115           GdkDisplay *display;
116           const gchar *id;
117
118           display = gdk_display_get_default ();
119           id = g_variant_get_string (value, NULL);
120           gdk_x11_display_set_startup_notification_id (display, id);
121        }
122 #endif
123     }
124 }
125
126 static void
127 gtk_application_after_emit (GApplication *application,
128                             GVariant     *platform_data)
129 {
130   gdk_notify_startup_complete ();
131 }
132
133 static void
134 gtk_application_init (GtkApplication *application)
135 {
136   application->priv = G_TYPE_INSTANCE_GET_PRIVATE (application,
137                                                    GTK_TYPE_APPLICATION,
138                                                    GtkApplicationPrivate);
139 }
140
141 static void
142 gtk_application_class_init (GtkApplicationClass *class)
143 {
144   GApplicationClass *application_class = G_APPLICATION_CLASS (class);
145
146   application_class->add_platform_data = gtk_application_add_platform_data;
147   application_class->before_emit = gtk_application_before_emit;
148   application_class->after_emit = gtk_application_after_emit;
149   application_class->startup = gtk_application_startup;
150
151   application_class->quit_mainloop = gtk_application_quit_mainloop;
152   application_class->run_mainloop = gtk_application_run_mainloop;
153
154   g_type_class_add_private (class, sizeof (GtkApplicationPrivate));
155 }
156
157 /**
158  * gtk_application_new:
159  * @application_id: the application id
160  * @flags: the application flags
161  *
162  * Creates a new #GtkApplication instance.
163  *
164  * This function calls g_type_init() for you. gtk_init() is called
165  * as soon as the application gets registered as the primary instance.
166  *
167  * The application id must be valid. See g_application_id_is_valid().
168  *
169  * Returns: a new #GtkApplication instance
170  */
171 GtkApplication *
172 gtk_application_new (const gchar       *application_id,
173                      GApplicationFlags  flags)
174 {
175   g_return_val_if_fail (g_application_id_is_valid (application_id), NULL);
176
177   g_type_init ();
178
179   return g_object_new (GTK_TYPE_APPLICATION,
180                        "application-id", application_id,
181                        "flags", flags,
182                        NULL);
183 }
184
185 /**
186  * gtk_application_add_window:
187  * @application: a #GtkApplication
188  * @window: a #GtkWindow
189  *
190  * Adds a window from @application.
191  *
192  * This call is equivalent to setting the #GtkWindow:application
193  * property of @window to @application.
194  *
195  * Since: 3.0
196  **/
197 void
198 gtk_application_add_window (GtkApplication *application,
199                             GtkWindow      *window)
200 {
201   GtkApplicationPrivate *priv;
202
203   g_return_if_fail (GTK_IS_APPLICATION (application));
204
205   priv = application->priv;
206
207   if (!g_list_find (priv->windows, window))
208     {
209       priv->windows = g_list_prepend (priv->windows, window);
210       gtk_window_set_application (window, application);
211       g_application_hold (G_APPLICATION (application));
212     }
213 }
214
215 /**
216  * gtk_application_remove_window:
217  * @application: a #GtkApplication
218  * @window: a #GtkWindow
219  *
220  * Remove a window from @application.
221  *
222  * If @window belongs to @application then this call is equivalent to
223  * setting the #GtkWindow:application property of @window to
224  * %NULL.
225  *
226  * The application may stop running as a result of a call to this
227  * function.
228  *
229  * Since: 3.0
230  **/
231 void
232 gtk_application_remove_window (GtkApplication *application,
233                                GtkWindow      *window)
234 {
235   GtkApplicationPrivate *priv;
236
237   g_return_if_fail (GTK_IS_APPLICATION (application));
238
239   priv = application->priv;
240   if (g_list_find (priv->windows, window))
241     {
242       priv->windows = g_list_remove (priv->windows, window);
243       g_application_release (G_APPLICATION (application));
244       gtk_window_set_application (window, NULL);
245     }
246 }
247
248 /**
249  * gtk_application_get_windows:
250  * @application: a #GtkApplication
251  *
252  * Gets a list of the #GtkWindow<!-- -->s associated with @application.
253  *
254  * The list that is returned should not be modified in any way.
255  *
256  * Returns: a #GList of #GtkWindow
257  *
258  * Since: 3.0
259  **/
260 GList *
261 gtk_application_get_windows (GtkApplication *application)
262 {
263   g_return_val_if_fail (GTK_IS_APPLICATION (application), NULL);
264
265   return application->priv->windows;
266 }