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 | |
118 | enum { |
119 | WINDOW_ADDED, |
120 | WINDOW_REMOVED, |
121 | QUERY_END, |
122 | LAST_SIGNAL |
123 | }; |
124 | |
125 | static guint gtk_application_signals[LAST_SIGNAL]; |
126 | |
127 | enum { |
128 | PROP_ZERO, |
129 | PROP_REGISTER_SESSION, |
130 | PROP_SCREENSAVER_ACTIVE, |
131 | , |
132 | PROP_ACTIVE_WINDOW, |
133 | NUM_PROPERTIES |
134 | }; |
135 | |
136 | static GParamSpec *gtk_application_props[NUM_PROPERTIES]; |
137 | |
138 | typedef struct |
139 | { |
140 | GtkApplicationImpl *impl; |
141 | GtkApplicationAccels *accels; |
142 | |
143 | GList *windows; |
144 | |
145 | GMenuModel *; |
146 | guint last_window_id; |
147 | |
148 | gboolean register_session; |
149 | gboolean screensaver_active; |
150 | GtkActionMuxer *muxer; |
151 | GtkBuilder *; |
152 | char *help_overlay_path; |
153 | } GtkApplicationPrivate; |
154 | |
155 | G_DEFINE_TYPE_WITH_PRIVATE (GtkApplication, gtk_application, G_TYPE_APPLICATION) |
156 | |
157 | static void |
158 | gtk_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 | |
182 | static void |
183 | gtk_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 *; |
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 *; |
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 | |
247 | static void |
248 | gtk_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 | |
273 | static void |
274 | gtk_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 | |
292 | static gboolean |
293 | gtk_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 | |
303 | static void |
304 | gtk_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 | |
328 | static void |
329 | gtk_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 | |
338 | static void |
339 | gtk_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 | |
355 | static void |
356 | gtk_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 | |
365 | static void |
366 | gtk_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 | |
403 | static void |
404 | gtk_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 | |
430 | static void |
431 | gtk_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 | |
463 | static void |
464 | gtk_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 | |
488 | static void |
489 | gtk_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 | |
504 | static gboolean |
505 | gtk_application_dbus_register (GApplication *application, |
506 | GDBusConnection *connection, |
507 | const char *object_path, |
508 | GError **error) |
509 | { |
510 | return TRUE; |
511 | } |
512 | |
513 | static void |
514 | gtk_application_dbus_unregister (GApplication *application, |
515 | GDBusConnection *connection, |
516 | const char *object_path) |
517 | { |
518 | } |
519 | |
520 | static void |
521 | gtk_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 | */ |
679 | GtkApplication * |
680 | gtk_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 | **/ |
712 | void |
713 | gtk_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 | **/ |
747 | void |
748 | gtk_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 | **/ |
778 | GList * |
779 | gtk_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 | */ |
800 | GtkWindow * |
801 | gtk_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 | **/ |
832 | GtkWindow * |
833 | gtk_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 | |
842 | static void |
843 | gtk_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 | */ |
876 | void |
877 | (GtkApplication *application, |
878 | GMenuModel *) |
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 | */ |
904 | GMenuModel * |
905 | (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 | */ |
966 | guint |
967 | gtk_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 | */ |
992 | void |
993 | gtk_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 | |
1005 | GtkActionMuxer * |
1006 | gtk_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 | |
1017 | GtkApplicationAccels * |
1018 | gtk_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 | */ |
1035 | char ** |
1036 | gtk_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 | */ |
1065 | void |
1066 | gtk_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 | */ |
1100 | char ** |
1101 | gtk_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 | */ |
1138 | char ** |
1139 | gtk_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 | |
1150 | GtkActionMuxer * |
1151 | gtk_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 | |
1160 | void |
1161 | gtk_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 | |
1170 | void |
1171 | gtk_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 | |
1180 | void |
1181 | gtk_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 | */ |
1203 | GMenu * |
1204 | (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 | |
1224 | void |
1225 | gtk_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 | |