1/*
2 * Copyright © 2010 Codethink Limited
3 * Copyright © 2013 Canonical Limited
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 licence, 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, see <http://www.gnu.org/licenses/>.
17 *
18 * Author: Ryan Lortie <desrt@desrt.ca>
19 */
20
21#include "config.h"
22
23#include "gtkapplication.h"
24#include "gdkprofilerprivate.h"
25
26#ifdef G_OS_UNIX
27#include <gio/gunixfdlist.h>
28#endif
29
30#include <stdlib.h>
31
32#ifdef HAVE_UNISTD_H
33#include <unistd.h>
34#endif
35
36#include "gtkapplicationprivate.h"
37#include "gtkmarshalers.h"
38#include "gtkmain.h"
39#include "gtkrecentmanager.h"
40#include "gtkicontheme.h"
41#include "gtkbuilder.h"
42#include "gtkshortcutswindow.h"
43#include "gtkintl.h"
44#include "gtkprivate.h"
45
46/* NB: please do not add backend-specific GDK headers here. This should
47 * be abstracted via GtkApplicationImpl.
48 */
49
50/**
51 * GtkApplication:
52 *
53 * `GtkApplication` is a high-level API for writing applications.
54 *
55 * It supports many aspects of writing a GTK application in a convenient
56 * fashion, without enforcing a one-size-fits-all 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 [class@Gtk.Window]s, it is
65 * recommended to use it together with [class@Gtk.ApplicationWindow].
66 *
67 * ## Automatic resources
68 *
69 * `GtkApplication` will automatically load menus from the `GtkBuilder`
70 * resource located at "gtk/menus.ui", relative to the application's
71 * resource base path (see [method@Gio.Application.set_resource_base_path]).
72 * The menu with the ID "menubar" is taken as the application's
73 * menubar. Additional menus (most interesting submenus) can be named
74 * and accessed via [method@Gtk.Application.get_menu_by_id] which allows for
75 * dynamic population of a part of the menu structure.
76 *
77 * It is also possible to provide the menubar manually using
78 * [method@Gtk.Application.set_menubar].
79 *
80 * `GtkApplication` will also automatically setup an icon search path for
81 * the default icon theme by appending "icons" to the resource base
82 * path. This allows your application to easily store its icons as
83 * resources. See [method@Gtk.IconTheme.add_resource_path] for more
84 * information.
85 *
86 * If there is a resource located at `gtk/help-overlay.ui` which
87 * defines a [class@Gtk.ShortcutsWindow] with ID `help_overlay` then
88 * `GtkApplication` associates an instance of this shortcuts window with
89 * each [class@Gtk.ApplicationWindow] and sets up the keyboard accelerator
90 * <kbd>Control</kbd>+<kbd>?</kbd> to open it. To create a menu item that
91 * displays the shortcuts window, associate the item with the action
92 * `win.show-help-overlay`.
93 *
94 * ## A simple application
95 *
96 * [A simple example](https://gitlab.gnome.org/GNOME/gtk/tree/main/examples/bp/bloatpad.c)
97 * is available in the GTK source code repository
98 *
99 * `GtkApplication` optionally registers with a session manager of the
100 * users session (if you set the [property@Gtk.Application:register-session]
101 * property) and offers various functionality related to the session
102 * life-cycle.
103 *
104 * An application can block various ways to end the session with
105 * the [method@Gtk.Application.inhibit] function. Typical use cases for
106 * this kind of inhibiting are long-running, uninterruptible operations,
107 * such as burning a CD or performing a disk backup. The session
108 * manager may not honor the inhibitor, but it can be expected to
109 * inform the user about the negative consequences of ending the
110 * session while inhibitors are present.
111 *
112 * ## See Also
113 *
114 * [HowDoI: Using GtkApplication](https://wiki.gnome.org/HowDoI/GtkApplication),
115 * [Getting Started with GTK: Basics](getting_started.html#basics)
116 */
117
118enum {
119 WINDOW_ADDED,
120 WINDOW_REMOVED,
121 QUERY_END,
122 LAST_SIGNAL
123};
124
125static guint gtk_application_signals[LAST_SIGNAL];
126
127enum {
128 PROP_ZERO,
129 PROP_REGISTER_SESSION,
130 PROP_SCREENSAVER_ACTIVE,
131 PROP_MENUBAR,
132 PROP_ACTIVE_WINDOW,
133 NUM_PROPERTIES
134};
135
136static GParamSpec *gtk_application_props[NUM_PROPERTIES];
137
138typedef struct
139{
140 GtkApplicationImpl *impl;
141 GtkApplicationAccels *accels;
142
143 GList *windows;
144
145 GMenuModel *menubar;
146 guint last_window_id;
147
148 gboolean register_session;
149 gboolean screensaver_active;
150 GtkActionMuxer *muxer;
151 GtkBuilder *menus_builder;
152 char *help_overlay_path;
153} GtkApplicationPrivate;
154
155G_DEFINE_TYPE_WITH_PRIVATE (GtkApplication, gtk_application, G_TYPE_APPLICATION)
156
157static void
158gtk_application_window_active_cb (GtkWindow *window,
159 GParamSpec *pspec,
160 GtkApplication *application)
161{
162 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
163 GList *link;
164
165 if (!gtk_window_is_active (window))
166 return;
167
168 /* Keep the window list sorted by most-recently-focused. */
169 link = g_list_find (list: priv->windows, data: window);
170 if (link != NULL && link != priv->windows)
171 {
172 priv->windows = g_list_remove_link (list: priv->windows, llink: link);
173 priv->windows = g_list_concat (list1: link, list2: priv->windows);
174 }
175
176 if (priv->impl)
177 gtk_application_impl_active_window_changed (impl: priv->impl, window);
178
179 g_object_notify_by_pspec (G_OBJECT (application), pspec: gtk_application_props[PROP_ACTIVE_WINDOW]);
180}
181
182static void
183gtk_application_load_resources (GtkApplication *application)
184{
185 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
186 const char *base_path;
187 const char *optional_slash = "/";
188
189 base_path = g_application_get_resource_base_path (G_APPLICATION (application));
190
191 if (base_path == NULL)
192 return;
193
194 if (base_path[strlen (s: base_path) - 1] == '/')
195 optional_slash = "";
196
197 /* Expand the icon search path */
198 {
199 GtkIconTheme *default_theme;
200 char *iconspath;
201
202 default_theme = gtk_icon_theme_get_for_display (display: gdk_display_get_default ());
203 iconspath = g_strconcat (string1: base_path, optional_slash, "icons/", NULL);
204 gtk_icon_theme_add_resource_path (self: default_theme, path: iconspath);
205 g_free (mem: iconspath);
206 }
207
208 /* Load the menus */
209 {
210 char *menuspath;
211
212 menuspath = g_strconcat (string1: base_path, optional_slash, "gtk/menus.ui", NULL);
213 if (g_resources_get_info (path: menuspath, lookup_flags: G_RESOURCE_LOOKUP_FLAGS_NONE, NULL, NULL, NULL))
214 priv->menus_builder = gtk_builder_new_from_resource (resource_path: menuspath);
215 g_free (mem: menuspath);
216
217 if (priv->menus_builder)
218 {
219 GObject *menu;
220
221 menu = gtk_builder_get_object (builder: priv->menus_builder, name: "menubar");
222 if (menu != NULL && G_IS_MENU_MODEL (menu))
223 gtk_application_set_menubar (application, G_MENU_MODEL (menu));
224 }
225 }
226
227 /* Help overlay */
228 {
229 char *path;
230
231 path = g_strconcat (string1: base_path, optional_slash, "gtk/help-overlay.ui", NULL);
232 if (g_resources_get_info (path, lookup_flags: G_RESOURCE_LOOKUP_FLAGS_NONE, NULL, NULL, NULL))
233 {
234 const char * const accels[] = { "<Control>question", NULL };
235
236 priv->help_overlay_path = path;
237 gtk_application_set_accels_for_action (application, detailed_action_name: "win.show-help-overlay", accels);
238 }
239 else
240 {
241 g_free (mem: path);
242 }
243 }
244}
245
246
247static void
248gtk_application_startup (GApplication *g_application)
249{
250 GtkApplication *application = GTK_APPLICATION (g_application);
251 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
252 gint64 before G_GNUC_UNUSED;
253 gint64 before2 G_GNUC_UNUSED;
254
255 before = GDK_PROFILER_CURRENT_TIME;
256
257 G_APPLICATION_CLASS (gtk_application_parent_class)->startup (g_application);
258
259 gtk_action_muxer_insert (muxer: priv->muxer, prefix: "app", G_ACTION_GROUP (application));
260
261 before2 = GDK_PROFILER_CURRENT_TIME;
262 gtk_init ();
263 gdk_profiler_end_mark (before2, "gtk init", NULL);
264
265 priv->impl = gtk_application_impl_new (application, display: gdk_display_get_default ());
266 gtk_application_impl_startup (impl: priv->impl, register_sesion: priv->register_session);
267
268 gtk_application_load_resources (application);
269
270 gdk_profiler_end_mark (before, "gtk application startup", NULL);
271}
272
273static void
274gtk_application_shutdown (GApplication *g_application)
275{
276 GtkApplication *application = GTK_APPLICATION (g_application);
277 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
278
279 if (priv->impl == NULL)
280 return;
281
282 gtk_application_impl_shutdown (impl: priv->impl);
283 g_clear_object (&priv->impl);
284
285 gtk_action_muxer_remove (muxer: priv->muxer, prefix: "app");
286
287 gtk_main_sync ();
288
289 G_APPLICATION_CLASS (gtk_application_parent_class)->shutdown (g_application);
290}
291
292static gboolean
293gtk_application_local_command_line (GApplication *application,
294 char ***arguments,
295 int *exit_status)
296{
297 /* We need to call setlocale() here so --help output works */
298 setlocale_initialization ();
299
300 return G_APPLICATION_CLASS (gtk_application_parent_class)->local_command_line (application, arguments, exit_status);
301}
302
303static void
304gtk_application_add_platform_data (GApplication *application,
305 GVariantBuilder *builder)
306{
307 GdkDisplay *display;
308
309 /* This is slightly evil.
310 *
311 * We don't have an impl here because we're remote so we can't figure
312 * out what to do on a per-display-server basis.
313 *
314 * So we do all the things... which currently is just one thing.
315 */
316 display = gdk_display_get_default ();
317 if (display)
318 {
319 const char *startup_id;
320
321 startup_id = gdk_display_get_startup_notification_id (display);
322 if (startup_id && g_utf8_validate (str: startup_id, max_len: -1, NULL))
323 g_variant_builder_add (builder, format_string: "{sv}", "desktop-startup-id",
324 g_variant_new_string (string: startup_id));
325 }
326}
327
328static void
329gtk_application_before_emit (GApplication *g_application,
330 GVariant *platform_data)
331{
332 GtkApplication *application = GTK_APPLICATION (g_application);
333 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
334
335 gtk_application_impl_before_emit (impl: priv->impl, platform_data);
336}
337
338static void
339gtk_application_after_emit (GApplication *application,
340 GVariant *platform_data)
341{
342 const char *startup_notification_id = NULL;
343
344 g_variant_lookup (dictionary: platform_data, key: "desktop-startup-id", format_string: "&s", &startup_notification_id);
345 if (startup_notification_id)
346 {
347 GdkDisplay *display;
348
349 display = gdk_display_get_default ();
350 if (display)
351 gdk_display_notify_startup_complete (display, startup_id: startup_notification_id);
352 }
353}
354
355static void
356gtk_application_init (GtkApplication *application)
357{
358 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
359
360 priv->muxer = gtk_action_muxer_new (NULL);
361
362 priv->accels = gtk_application_accels_new ();
363}
364
365static void
366gtk_application_window_added (GtkApplication *application,
367 GtkWindow *window)
368{
369 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
370
371 if (GTK_IS_APPLICATION_WINDOW (window))
372 {
373 gtk_application_window_set_id (GTK_APPLICATION_WINDOW (window), id: ++priv->last_window_id);
374 if (priv->help_overlay_path)
375 {
376 GtkBuilder *builder;
377 GtkWidget *help_overlay;
378
379 builder = gtk_builder_new_from_resource (resource_path: priv->help_overlay_path);
380 help_overlay = GTK_WIDGET (gtk_builder_get_object (builder, "help_overlay"));
381 if (GTK_IS_SHORTCUTS_WINDOW (help_overlay))
382 gtk_application_window_set_help_overlay (GTK_APPLICATION_WINDOW (window),
383 GTK_SHORTCUTS_WINDOW (help_overlay));
384 g_object_unref (object: builder);
385 }
386 }
387
388 priv->windows = g_list_prepend (list: priv->windows, data: window);
389 gtk_window_set_application (window, application);
390 g_application_hold (G_APPLICATION (application));
391
392 g_signal_connect (window, "notify::is-active",
393 G_CALLBACK (gtk_application_window_active_cb),
394 application);
395
396 gtk_application_impl_window_added (impl: priv->impl, window);
397
398 gtk_application_impl_active_window_changed (impl: priv->impl, window);
399
400 g_object_notify_by_pspec (G_OBJECT (application), pspec: gtk_application_props[PROP_ACTIVE_WINDOW]);
401}
402
403static void
404gtk_application_window_removed (GtkApplication *application,
405 GtkWindow *window)
406{
407 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
408 gpointer old_active;
409
410 old_active = priv->windows;
411
412 if (priv->impl)
413 gtk_application_impl_window_removed (impl: priv->impl, window);
414
415 g_signal_handlers_disconnect_by_func (window,
416 gtk_application_window_active_cb,
417 application);
418
419 g_application_release (G_APPLICATION (application));
420 priv->windows = g_list_remove (list: priv->windows, data: window);
421 gtk_window_set_application (window, NULL);
422
423 if (priv->windows != old_active && priv->impl)
424 {
425 gtk_application_impl_active_window_changed (impl: priv->impl, window: priv->windows ? priv->windows->data : NULL);
426 g_object_notify_by_pspec (G_OBJECT (application), pspec: gtk_application_props[PROP_ACTIVE_WINDOW]);
427 }
428}
429
430static void
431gtk_application_get_property (GObject *object,
432 guint prop_id,
433 GValue *value,
434 GParamSpec *pspec)
435{
436 GtkApplication *application = GTK_APPLICATION (object);
437 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
438
439 switch (prop_id)
440 {
441 case PROP_REGISTER_SESSION:
442 g_value_set_boolean (value, v_boolean: priv->register_session);
443 break;
444
445 case PROP_SCREENSAVER_ACTIVE:
446 g_value_set_boolean (value, v_boolean: priv->screensaver_active);
447 break;
448
449 case PROP_MENUBAR:
450 g_value_set_object (value, v_object: gtk_application_get_menubar (application));
451 break;
452
453 case PROP_ACTIVE_WINDOW:
454 g_value_set_object (value, v_object: gtk_application_get_active_window (application));
455 break;
456
457 default:
458 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
459 break;
460 }
461}
462
463static void
464gtk_application_set_property (GObject *object,
465 guint prop_id,
466 const GValue *value,
467 GParamSpec *pspec)
468{
469 GtkApplication *application = GTK_APPLICATION (object);
470 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
471
472 switch (prop_id)
473 {
474 case PROP_REGISTER_SESSION:
475 priv->register_session = g_value_get_boolean (value);
476 break;
477
478 case PROP_MENUBAR:
479 gtk_application_set_menubar (application, menubar: g_value_get_object (value));
480 break;
481
482 default:
483 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
484 break;
485 }
486}
487
488static void
489gtk_application_finalize (GObject *object)
490{
491 GtkApplication *application = GTK_APPLICATION (object);
492 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
493
494 g_clear_object (&priv->menus_builder);
495 g_clear_object (&priv->menubar);
496 g_clear_object (&priv->muxer);
497 g_clear_object (&priv->accels);
498
499 g_free (mem: priv->help_overlay_path);
500
501 G_OBJECT_CLASS (gtk_application_parent_class)->finalize (object);
502}
503
504static gboolean
505gtk_application_dbus_register (GApplication *application,
506 GDBusConnection *connection,
507 const char *object_path,
508 GError **error)
509{
510 return TRUE;
511}
512
513static void
514gtk_application_dbus_unregister (GApplication *application,
515 GDBusConnection *connection,
516 const char *object_path)
517{
518}
519
520static void
521gtk_application_class_init (GtkApplicationClass *class)
522{
523 GObjectClass *object_class = G_OBJECT_CLASS (class);
524 GApplicationClass *application_class = G_APPLICATION_CLASS (class);
525
526 object_class->get_property = gtk_application_get_property;
527 object_class->set_property = gtk_application_set_property;
528 object_class->finalize = gtk_application_finalize;
529
530 application_class->local_command_line = gtk_application_local_command_line;
531 application_class->add_platform_data = gtk_application_add_platform_data;
532 application_class->before_emit = gtk_application_before_emit;
533 application_class->after_emit = gtk_application_after_emit;
534 application_class->startup = gtk_application_startup;
535 application_class->shutdown = gtk_application_shutdown;
536 application_class->dbus_register = gtk_application_dbus_register;
537 application_class->dbus_unregister = gtk_application_dbus_unregister;
538
539 class->window_added = gtk_application_window_added;
540 class->window_removed = gtk_application_window_removed;
541
542 /**
543 * GtkApplication::window-added:
544 * @application: the `GtkApplication` which emitted the signal
545 * @window: the newly-added [class@Gtk.Window]
546 *
547 * Emitted when a [class@Gtk.Window] is added to `application` through
548 * [method@Gtk.Application.add_window].
549 */
550 gtk_application_signals[WINDOW_ADDED] =
551 g_signal_new (I_("window-added"), GTK_TYPE_APPLICATION, signal_flags: G_SIGNAL_RUN_FIRST,
552 G_STRUCT_OFFSET (GtkApplicationClass, window_added),
553 NULL, NULL,
554 NULL,
555 G_TYPE_NONE, n_params: 1, GTK_TYPE_WINDOW);
556
557 /**
558 * GtkApplication::window-removed:
559 * @application: the `GtkApplication` which emitted the signal
560 * @window: the [class@Gtk.Window] that is being removed
561 *
562 * Emitted when a [class@Gtk.Window] is removed from `application`.
563 *
564 * This can happen as a side-effect of the window being destroyed
565 * or explicitly through [method@Gtk.Application.remove_window].
566 */
567 gtk_application_signals[WINDOW_REMOVED] =
568 g_signal_new (I_("window-removed"), GTK_TYPE_APPLICATION, signal_flags: G_SIGNAL_RUN_FIRST,
569 G_STRUCT_OFFSET (GtkApplicationClass, window_removed),
570 NULL, NULL,
571 NULL,
572 G_TYPE_NONE, n_params: 1, GTK_TYPE_WINDOW);
573
574 /**
575 * GtkApplication::query-end:
576 * @application: the `GtkApplication` which emitted the signal
577 *
578 * Emitted when the session manager is about to end the session.
579 *
580 * This signal is only emitted if [property@Gtk.Application:register-session]
581 * is `TRUE`. Applications can connect to this signal and call
582 * [method@Gtk.Application.inhibit] with `GTK_APPLICATION_INHIBIT_LOGOUT`
583 * to delay the end of the session until state has been saved.
584 */
585 gtk_application_signals[QUERY_END] =
586 g_signal_new (I_("query-end"), GTK_TYPE_APPLICATION, signal_flags: G_SIGNAL_RUN_FIRST,
587 class_offset: 0,
588 NULL, NULL,
589 NULL,
590 G_TYPE_NONE, n_params: 0);
591
592 /**
593 * GtkApplication:register-session:
594 *
595 * Set this property to `TRUE` to register with the session manager.
596 *
597 * This will make GTK track the session state (such as the
598 * [property@Gtk.Application:screensaver-active] property).
599 */
600 gtk_application_props[PROP_REGISTER_SESSION] =
601 g_param_spec_boolean (name: "register-session",
602 P_("Register session"),
603 P_("Register with the session manager"),
604 FALSE,
605 flags: G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS);
606
607 /**
608 * GtkApplication:screensaver-active:
609 *
610 * This property is `TRUE` if GTK believes that the screensaver is
611 * currently active.
612 *
613 * GTK only tracks session state (including this) when
614 * [property@Gtk.Application:register-session] is set to %TRUE.
615 *
616 * Tracking the screensaver state is currently only supported on
617 * Linux.
618 */
619 gtk_application_props[PROP_SCREENSAVER_ACTIVE] =
620 g_param_spec_boolean (name: "screensaver-active",
621 P_("Screensaver Active"),
622 P_("Whether the screensaver is active"),
623 FALSE,
624 flags: G_PARAM_READABLE|G_PARAM_STATIC_STRINGS);
625
626 /**
627 * GtkApplication:menubar: (attributes org.gtk.Property.get=gtk_application_get_menubar org.gtk.Property.set=gtk_application_set_menubar)
628 *
629 * The `GMenuModel` to be used for the application's menu bar.
630 */
631 gtk_application_props[PROP_MENUBAR] =
632 g_param_spec_object (name: "menubar",
633 P_("Menubar"),
634 P_("The GMenuModel for the menubar"),
635 G_TYPE_MENU_MODEL,
636 flags: G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS);
637
638 /**
639 * GtkApplication:active-window: (attributes org.gtk.Property.get=gtk_application_get_active_window)
640 *
641 * The currently focused window of the application.
642 */
643 gtk_application_props[PROP_ACTIVE_WINDOW] =
644 g_param_spec_object (name: "active-window",
645 P_("Active window"),
646 P_("The window which most recently had focus"),
647 GTK_TYPE_WINDOW,
648 flags: G_PARAM_READABLE|G_PARAM_STATIC_STRINGS);
649
650 g_object_class_install_properties (oclass: object_class, n_pspecs: NUM_PROPERTIES, pspecs: gtk_application_props);
651}
652
653/**
654 * gtk_application_new:
655 * @application_id: (nullable): The application ID
656 * @flags: the application flags
657 *
658 * Creates a new `GtkApplication` instance.
659 *
660 * When using `GtkApplication`, it is not necessary to call [func@Gtk.init]
661 * manually. It is called as soon as the application gets registered as
662 * the primary instance.
663 *
664 * Concretely, [func@Gtk.init] is called in the default handler for the
665 * `GApplication::startup` signal. Therefore, `GtkApplication` subclasses should
666 * always chain up in their `GApplication::startup` handler before using any GTK
667 * API.
668 *
669 * Note that commandline arguments are not passed to [func@Gtk.init].
670 *
671 * If `application_id` is not %NULL, then it must be valid. See
672 * `g_application_id_is_valid()`.
673 *
674 * If no application ID is given then some features (most notably application
675 * uniqueness) will be disabled.
676 *
677 * Returns: a new `GtkApplication` instance
678 */
679GtkApplication *
680gtk_application_new (const char *application_id,
681 GApplicationFlags flags)
682{
683 g_return_val_if_fail (application_id == NULL || g_application_id_is_valid (application_id), NULL);
684
685 return g_object_new (GTK_TYPE_APPLICATION,
686 first_property_name: "application-id", application_id,
687 "flags", flags,
688 NULL);
689}
690
691/**
692 * gtk_application_add_window:
693 * @application: a `GtkApplication`
694 * @window: a `GtkWindow`
695 *
696 * Adds a window to `application`.
697 *
698 * This call can only happen after the `application` has started;
699 * typically, you should add new application windows in response
700 * to the emission of the `GApplication::activate` signal.
701 *
702 * This call is equivalent to setting the [property@Gtk.Window:application]
703 * property of `window` to `application`.
704 *
705 * Normally, the connection between the application and the window
706 * will remain until the window is destroyed, but you can explicitly
707 * remove it with [method@Gtk.Application.remove_window].
708 *
709 * GTK will keep the `application` running as long as it has
710 * any windows.
711 **/
712void
713gtk_application_add_window (GtkApplication *application,
714 GtkWindow *window)
715{
716 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
717
718 g_return_if_fail (GTK_IS_APPLICATION (application));
719 g_return_if_fail (GTK_IS_WINDOW (window));
720
721 if (!g_application_get_is_registered (G_APPLICATION (application)))
722 {
723 g_critical ("New application windows must be added after the "
724 "GApplication::startup signal has been emitted.");
725 return;
726 }
727
728 if (!g_list_find (list: priv->windows, data: window))
729 g_signal_emit (instance: application,
730 signal_id: gtk_application_signals[WINDOW_ADDED], detail: 0, window);
731}
732
733/**
734 * gtk_application_remove_window:
735 * @application: a `GtkApplication`
736 * @window: a `GtkWindow`
737 *
738 * Remove a window from `application`.
739 *
740 * If `window` belongs to `application` then this call is equivalent to
741 * setting the [property@Gtk.Window:application] property of `window` to
742 * `NULL`.
743 *
744 * The application may stop running as a result of a call to this
745 * function, if `window` was the last window of the `application`.
746 **/
747void
748gtk_application_remove_window (GtkApplication *application,
749 GtkWindow *window)
750{
751 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
752
753 g_return_if_fail (GTK_IS_APPLICATION (application));
754 g_return_if_fail (GTK_IS_WINDOW (window));
755
756 if (g_list_find (list: priv->windows, data: window))
757 g_signal_emit (instance: application,
758 signal_id: gtk_application_signals[WINDOW_REMOVED], detail: 0, window);
759}
760
761/**
762 * gtk_application_get_windows:
763 * @application: a `GtkApplication`
764 *
765 * Gets a list of the [class@Gtk.Window] instances associated with `application`.
766 *
767 * The list is sorted by most recently focused window, such that the first
768 * element is the currently focused window. (Useful for choosing a parent
769 * for a transient window.)
770 *
771 * The list that is returned should not be modified in any way. It will
772 * only remain valid until the next focus change or window creation or
773 * deletion.
774 *
775 * Returns: (element-type GtkWindow) (transfer none): a `GList` of `GtkWindow`
776 * instances
777 **/
778GList *
779gtk_application_get_windows (GtkApplication *application)
780{
781 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
782
783 g_return_val_if_fail (GTK_IS_APPLICATION (application), NULL);
784
785 return priv->windows;
786}
787
788/**
789 * gtk_application_get_window_by_id:
790 * @application: a `GtkApplication`
791 * @id: an identifier number
792 *
793 * Returns the [class@Gtk.ApplicationWindow] with the given ID.
794 *
795 * The ID of a `GtkApplicationWindow` can be retrieved with
796 * [method@Gtk.ApplicationWindow.get_id].
797 *
798 * Returns: (nullable) (transfer none): the window for the given `id`
799 */
800GtkWindow *
801gtk_application_get_window_by_id (GtkApplication *application,
802 guint id)
803{
804 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
805 GList *l;
806
807 g_return_val_if_fail (GTK_IS_APPLICATION (application), NULL);
808
809 for (l = priv->windows; l != NULL; l = l->next)
810 {
811 if (GTK_IS_APPLICATION_WINDOW (l->data) &&
812 gtk_application_window_get_id (GTK_APPLICATION_WINDOW (l->data)) == id)
813 return l->data;
814 }
815
816 return NULL;
817}
818
819/**
820 * gtk_application_get_active_window: (attributes org.gtk.Method.get_property=active-window)
821 * @application: a `GtkApplication`
822 *
823 * Gets the “active” window for the application.
824 *
825 * The active window is the one that was most recently focused (within
826 * the application). This window may not have the focus at the moment
827 * if another application has it — this is just the most
828 * recently-focused window within this application.
829 *
830 * Returns: (transfer none) (nullable): the active window
831 **/
832GtkWindow *
833gtk_application_get_active_window (GtkApplication *application)
834{
835 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
836
837 g_return_val_if_fail (GTK_IS_APPLICATION (application), NULL);
838
839 return priv->windows ? priv->windows->data : NULL;
840}
841
842static void
843gtk_application_update_accels (GtkApplication *application)
844{
845 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
846 GList *l;
847
848 for (l = priv->windows; l != NULL; l = l->next)
849 _gtk_window_notify_keys_changed (window: l->data);
850}
851
852/**
853 * gtk_application_set_menubar: (attributes org.gtk.Method.set_property=menubar)
854 * @application: a `GtkApplication`
855 * @menubar: (nullable): a `GMenuModel`
856 *
857 * Sets or unsets the menubar for windows of `application`.
858 *
859 * This is a menubar in the traditional sense.
860 *
861 * This can only be done in the primary instance of the application,
862 * after it has been registered. `GApplication::startup` is a good place
863 * to call this.
864 *
865 * Depending on the desktop environment, this may appear at the top of
866 * each window, or at the top of the screen. In some environments, if
867 * both the application menu and the menubar are set, the application
868 * menu will be presented as if it were the first item of the menubar.
869 * Other environments treat the two as completely separate — for example,
870 * the application menu may be rendered by the desktop shell while the
871 * menubar (if set) remains in each individual window.
872 *
873 * Use the base `GActionMap` interface to add actions, to respond to the
874 * user selecting these menu items.
875 */
876void
877gtk_application_set_menubar (GtkApplication *application,
878 GMenuModel *menubar)
879{
880 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
881
882 g_return_if_fail (GTK_IS_APPLICATION (application));
883 g_return_if_fail (g_application_get_is_registered (G_APPLICATION (application)));
884 g_return_if_fail (!g_application_get_is_remote (G_APPLICATION (application)));
885 g_return_if_fail (menubar == NULL || G_IS_MENU_MODEL (menubar));
886
887 if (g_set_object (&priv->menubar, menubar))
888 {
889 gtk_application_impl_set_menubar (impl: priv->impl, menubar);
890
891 g_object_notify_by_pspec (G_OBJECT (application), pspec: gtk_application_props[PROP_MENUBAR]);
892 }
893}
894
895/**
896 * gtk_application_get_menubar: (attributes org.gtk.Method.get_property=menubar)
897 * @application: a `GtkApplication`
898 *
899 * Returns the menu model that has been set with
900 * [method@Gtk.Application.set_menubar].
901 *
902 * Returns: (nullable) (transfer none): the menubar for windows of `application`
903 */
904GMenuModel *
905gtk_application_get_menubar (GtkApplication *application)
906{
907 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
908
909 g_return_val_if_fail (GTK_IS_APPLICATION (application), NULL);
910
911 return priv->menubar;
912}
913
914/**
915 * GtkApplicationInhibitFlags:
916 * @GTK_APPLICATION_INHIBIT_LOGOUT: Inhibit ending the user session
917 * by logging out or by shutting down the computer
918 * @GTK_APPLICATION_INHIBIT_SWITCH: Inhibit user switching
919 * @GTK_APPLICATION_INHIBIT_SUSPEND: Inhibit suspending the
920 * session or computer
921 * @GTK_APPLICATION_INHIBIT_IDLE: Inhibit the session being
922 * marked as idle (and possibly locked)
923 *
924 * Types of user actions that may be blocked by `GtkApplication`.
925 *
926 * See [method@Gtk.Application.inhibit].
927 */
928
929/**
930 * gtk_application_inhibit:
931 * @application: the `GtkApplication`
932 * @window: (nullable): a `GtkWindow`
933 * @flags: what types of actions should be inhibited
934 * @reason: (nullable): a short, human-readable string that explains
935 * why these operations are inhibited
936 *
937 * Inform the session manager that certain types of actions should be
938 * inhibited.
939 *
940 * This is not guaranteed to work on all platforms and for all types of
941 * actions.
942 *
943 * Applications should invoke this method when they begin an operation
944 * that should not be interrupted, such as creating a CD or DVD. The
945 * types of actions that may be blocked are specified by the `flags`
946 * parameter. When the application completes the operation it should
947 * call [method@Gtk.Application.uninhibit] to remove the inhibitor. Note
948 * that an application can have multiple inhibitors, and all of them must
949 * be individually removed. Inhibitors are also cleared when the
950 * application exits.
951 *
952 * Applications should not expect that they will always be able to block
953 * the action. In most cases, users will be given the option to force
954 * the action to take place.
955 *
956 * The `reason` message should be short and to the point.
957 *
958 * If `window` is given, the session manager may point the user to
959 * this window to find out more about why the action is inhibited.
960 *
961 * Returns: A non-zero cookie that is used to uniquely identify this
962 * request. It should be used as an argument to [method@Gtk.Application.uninhibit]
963 * in order to remove the request. If the platform does not support
964 * inhibiting or the request failed for some reason, 0 is returned.
965 */
966guint
967gtk_application_inhibit (GtkApplication *application,
968 GtkWindow *window,
969 GtkApplicationInhibitFlags flags,
970 const char *reason)
971{
972 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
973
974 g_return_val_if_fail (GTK_IS_APPLICATION (application), 0);
975 g_return_val_if_fail (!g_application_get_is_remote (G_APPLICATION (application)), 0);
976 g_return_val_if_fail (window == NULL || GTK_IS_WINDOW (window), 0);
977
978 return gtk_application_impl_inhibit (impl: priv->impl, window, flags, reason);
979}
980
981/**
982 * gtk_application_uninhibit:
983 * @application: the `GtkApplication`
984 * @cookie: a cookie that was returned by [method@Gtk.Application.inhibit]
985 *
986 * Removes an inhibitor that has been previously established.
987 *
988 * See [method@Gtk.Application.inhibit].
989 *
990 * Inhibitors are also cleared when the application exits.
991 */
992void
993gtk_application_uninhibit (GtkApplication *application,
994 guint cookie)
995{
996 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
997
998 g_return_if_fail (GTK_IS_APPLICATION (application));
999 g_return_if_fail (!g_application_get_is_remote (G_APPLICATION (application)));
1000 g_return_if_fail (cookie > 0);
1001
1002 gtk_application_impl_uninhibit (impl: priv->impl, cookie);
1003}
1004
1005GtkActionMuxer *
1006gtk_application_get_parent_muxer_for_window (GtkWindow *window)
1007{
1008 GtkApplication *application = gtk_window_get_application (window);
1009 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
1010
1011 if (!application)
1012 return NULL;
1013
1014 return priv->muxer;
1015}
1016
1017GtkApplicationAccels *
1018gtk_application_get_application_accels (GtkApplication *application)
1019{
1020 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
1021
1022 return priv->accels;
1023}
1024
1025/**
1026 * gtk_application_list_action_descriptions:
1027 * @application: a `GtkApplication`
1028 *
1029 * Lists the detailed action names which have associated accelerators.
1030 *
1031 * See [method@Gtk.Application.set_accels_for_action].
1032 *
1033 * Returns: (transfer full) (array zero-terminated=1): the detailed action names
1034 */
1035char **
1036gtk_application_list_action_descriptions (GtkApplication *application)
1037{
1038 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
1039
1040 g_return_val_if_fail (GTK_IS_APPLICATION (application), NULL);
1041
1042 return gtk_application_accels_list_action_descriptions (accels: priv->accels);
1043}
1044
1045/**
1046 * gtk_application_set_accels_for_action:
1047 * @application: a `GtkApplication`
1048 * @detailed_action_name: a detailed action name, specifying an action
1049 * and target to associate accelerators with
1050 * @accels: (array zero-terminated=1): a list of accelerators in the format
1051 * understood by [func@Gtk.accelerator_parse]
1052 *
1053 * Sets zero or more keyboard accelerators that will trigger the
1054 * given action.
1055 *
1056 * The first item in `accels` will be the primary accelerator, which may be
1057 * displayed in the UI.
1058 *
1059 * To remove all accelerators for an action, use an empty, zero-terminated
1060 * array for `accels`.
1061 *
1062 * For the `detailed_action_name`, see `g_action_parse_detailed_name()` and
1063 * `g_action_print_detailed_name()`.
1064 */
1065void
1066gtk_application_set_accels_for_action (GtkApplication *application,
1067 const char *detailed_action_name,
1068 const char * const *accels)
1069{
1070 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
1071 char *action_and_target;
1072
1073 g_return_if_fail (GTK_IS_APPLICATION (application));
1074 g_return_if_fail (detailed_action_name != NULL);
1075 g_return_if_fail (accels != NULL);
1076
1077 gtk_application_accels_set_accels_for_action (accels: priv->accels,
1078 detailed_action_name,
1079 accelerators: accels);
1080
1081 action_and_target = gtk_normalise_detailed_action_name (detailed_action_name);
1082 gtk_action_muxer_set_primary_accel (muxer: priv->muxer, action_and_target, primary_accel: accels[0]);
1083 g_free (mem: action_and_target);
1084
1085 gtk_application_update_accels (application);
1086}
1087
1088/**
1089 * gtk_application_get_accels_for_action:
1090 * @application: a `GtkApplication`
1091 * @detailed_action_name: a detailed action name, specifying an action
1092 * and target to obtain accelerators for
1093 *
1094 * Gets the accelerators that are currently associated with
1095 * the given action.
1096 *
1097 * Returns: (transfer full) (array zero-terminated=1) (element-type utf8):
1098 * accelerators for `detailed_action_name`
1099 */
1100char **
1101gtk_application_get_accels_for_action (GtkApplication *application,
1102 const char *detailed_action_name)
1103{
1104 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
1105
1106 g_return_val_if_fail (GTK_IS_APPLICATION (application), NULL);
1107 g_return_val_if_fail (detailed_action_name != NULL, NULL);
1108
1109 return gtk_application_accels_get_accels_for_action (accels: priv->accels,
1110 detailed_action_name);
1111}
1112
1113/**
1114 * gtk_application_get_actions_for_accel:
1115 * @application: a `GtkApplication`
1116 * @accel: an accelerator that can be parsed by [func@Gtk.accelerator_parse]
1117 *
1118 * Returns the list of actions (possibly empty) that `accel` maps to.
1119 *
1120 * Each item in the list is a detailed action name in the usual form.
1121 *
1122 * This might be useful to discover if an accel already exists in
1123 * order to prevent installation of a conflicting accelerator (from
1124 * an accelerator editor or a plugin system, for example). Note that
1125 * having more than one action per accelerator may not be a bad thing
1126 * and might make sense in cases where the actions never appear in the
1127 * same context.
1128 *
1129 * In case there are no actions for a given accelerator, an empty array
1130 * is returned. `NULL` is never returned.
1131 *
1132 * It is a programmer error to pass an invalid accelerator string.
1133 *
1134 * If you are unsure, check it with [func@Gtk.accelerator_parse] first.
1135 *
1136 * Returns: (transfer full): a %NULL-terminated array of actions for `accel`
1137 */
1138char **
1139gtk_application_get_actions_for_accel (GtkApplication *application,
1140 const char *accel)
1141{
1142 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
1143
1144 g_return_val_if_fail (GTK_IS_APPLICATION (application), NULL);
1145 g_return_val_if_fail (accel != NULL, NULL);
1146
1147 return gtk_application_accels_get_actions_for_accel (accels: priv->accels, accel);
1148}
1149
1150GtkActionMuxer *
1151gtk_application_get_action_muxer (GtkApplication *application)
1152{
1153 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
1154
1155 g_assert (priv->muxer);
1156
1157 return priv->muxer;
1158}
1159
1160void
1161gtk_application_insert_action_group (GtkApplication *application,
1162 const char *name,
1163 GActionGroup *action_group)
1164{
1165 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
1166
1167 gtk_action_muxer_insert (muxer: priv->muxer, prefix: name, action_group);
1168}
1169
1170void
1171gtk_application_handle_window_realize (GtkApplication *application,
1172 GtkWindow *window)
1173{
1174 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
1175
1176 if (priv->impl)
1177 gtk_application_impl_handle_window_realize (impl: priv->impl, window);
1178}
1179
1180void
1181gtk_application_handle_window_map (GtkApplication *application,
1182 GtkWindow *window)
1183{
1184 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
1185
1186 if (priv->impl)
1187 gtk_application_impl_handle_window_map (impl: priv->impl, window);
1188}
1189
1190/**
1191 * gtk_application_get_menu_by_id:
1192 * @application: a `GtkApplication`
1193 * @id: the id of the menu to look up
1194 *
1195 * Gets a menu from automatically loaded resources.
1196 *
1197 * See [the section on Automatic resources](class.Application.html#automatic-resources)
1198 * for more information.
1199 *
1200 * Returns: (nullable) (transfer none): Gets the menu with the
1201 * given id from the automatically loaded resources
1202 */
1203GMenu *
1204gtk_application_get_menu_by_id (GtkApplication *application,
1205 const char *id)
1206{
1207 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
1208 GObject *object;
1209
1210 g_return_val_if_fail (GTK_IS_APPLICATION (application), NULL);
1211 g_return_val_if_fail (id != NULL, NULL);
1212
1213 if (!priv->menus_builder)
1214 return NULL;
1215
1216 object = gtk_builder_get_object (builder: priv->menus_builder, name: id);
1217
1218 if (!object || !G_IS_MENU (object))
1219 return NULL;
1220
1221 return G_MENU (object);
1222}
1223
1224void
1225gtk_application_set_screensaver_active (GtkApplication *application,
1226 gboolean active)
1227{
1228 GtkApplicationPrivate *priv = gtk_application_get_instance_private (self: application);
1229
1230 if (priv->screensaver_active != active)
1231 {
1232 priv->screensaver_active = active;
1233 g_object_notify (G_OBJECT (application), property_name: "screensaver-active");
1234 }
1235}
1236

source code of gtk/gtk/gtkapplication.c