1/* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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 License, 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, see <http://www.gnu.org/licenses/>.
16 */
17
18/*
19 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
20 * file for a list of people on the GTK+ Team. See the ChangeLog
21 * files for a list of changes. These files are distributed with
22 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
23 */
24
25#include "config.h"
26
27#include "gtkwindowprivate.h"
28
29#include "gtkaccessibleprivate.h"
30#include "gtkaccelgroupprivate.h"
31#include "gtkactionable.h"
32#include "gtkapplicationprivate.h"
33#include "gtkbox.h"
34#include "gtkbuildable.h"
35#include "gtkbuilderprivate.h"
36#include "gtkcheckbutton.h"
37#include "gtkcsscornervalueprivate.h"
38#include "gtkcsscolorvalueprivate.h"
39#include "gtkcssshadowvalueprivate.h"
40#include "gtkdroptargetasync.h"
41#include "gtkeventcontrollerlegacy.h"
42#include "gtkeventcontrollerkey.h"
43#include "gtkeventcontrollermotion.h"
44#include "gtkgestureclick.h"
45#include "gtkheaderbar.h"
46#include "gtkicontheme.h"
47#include "gtkintl.h"
48#include "gtkmain.h"
49#include "gtkmarshalers.h"
50#include "gtkmessagedialog.h"
51#include "gtkpointerfocusprivate.h"
52#include "gtkprivate.h"
53#include "gtkroot.h"
54#include "gtknativeprivate.h"
55#include "gtksettings.h"
56#include "gtkshortcut.h"
57#include "gtkshortcutcontrollerprivate.h"
58#include "gtkshortcutmanager.h"
59#include "gtkshortcuttrigger.h"
60#include "gtksizerequest.h"
61#include "gtksnapshot.h"
62#include "gtktypebuiltins.h"
63#include "gtkwidgetprivate.h"
64#include "gtkwindowgroup.h"
65#include "gtkpopovermenubarprivate.h"
66#include "gtkcssboxesimplprivate.h"
67#include "gtktooltipprivate.h"
68#include "gtkmenubutton.h"
69
70#include "inspector/window.h"
71
72#include "gdk/gdkprofilerprivate.h"
73#include "gdk/gdksurfaceprivate.h"
74#include "gdk/gdktextureprivate.h"
75
76#include <cairo-gobject.h>
77#include <errno.h>
78#include <graphene.h>
79#include <limits.h>
80#include <string.h>
81#include <stdlib.h>
82
83#ifdef GDK_WINDOWING_X11
84#include "x11/gdkx.h"
85#endif
86
87#ifdef GDK_WINDOWING_WIN32
88#include "win32/gdkwin32.h"
89#endif
90
91#ifdef GDK_WINDOWING_WAYLAND
92#include "wayland/gdkwayland.h"
93#include "wayland/gdkdisplay-wayland.h"
94#include "wayland/gdksurface-wayland.h"
95#endif
96
97#ifdef GDK_WINDOWING_BROADWAY
98#include "broadway/gdkbroadway.h"
99#endif
100
101/**
102 * GtkWindow:
103 *
104 * A `GtkWindow` is a toplevel window which can contain other widgets.
105 *
106 * ![An example GtkWindow](window.png)
107 *
108 * Windows normally have decorations that are under the control
109 * of the windowing system and allow the user to manipulate the window
110 * (resize it, move it, close it,...).
111 *
112 * # GtkWindow as GtkBuildable
113 *
114 * The `GtkWindow` implementation of the [iface@Gtk.Buildable] interface supports
115 * setting a child as the titlebar by specifying “titlebar” as the “type”
116 * attribute of a <child> element.
117 *
118 * # CSS nodes
119 *
120 * ```
121 * window.background [.csd / .solid-csd / .ssd] [.maximized / .fullscreen / .tiled]
122 * ├── <child>
123 * ╰── <titlebar child>.titlebar [.default-decoration]
124 * ```
125 *
126 * `GtkWindow` has a main CSS node with name window and style class .background.
127 *
128 * Style classes that are typically used with the main CSS node are .csd (when
129 * client-side decorations are in use), .solid-csd (for client-side decorations
130 * without invisible borders), .ssd (used by mutter when rendering server-side
131 * decorations). GtkWindow also represents window states with the following
132 * style classes on the main node: .maximized, .fullscreen, .tiled (when supported,
133 * also .tiled-top, .tiled-left, .tiled-right, .tiled-bottom).
134 *
135 * `GtkWindow` subclasses often add their own discriminating style classes,
136 * such as .dialog, .popup or .tooltip.
137 *
138 * Generally, some CSS properties don't make sense on the toplevel window node,
139 * such as margins or padding. When client-side decorations without invisible
140 * borders are in use (i.e. the .solid-csd style class is added to the
141 * main window node), the CSS border of the toplevel window is used for
142 * resize drags. In the .csd case, the shadow area outside of the window
143 * can be used to resize it.
144 *
145 * `GtkWindow` adds the .titlebar and .default-decoration style classes to the
146 * widget that is added as a titlebar child.
147 *
148 * # Accessibility
149 *
150 * `GtkWindow` uses the %GTK_ACCESSIBLE_ROLE_WINDOW role.
151 *
152 * # Actions
153 *
154 * `GtkWindow` defines a set of built-in actions:
155 * - `default.activate`: Activate the default widget.
156 * - `window.minimize`: Minimize the window.
157 * - `window.toggle-maximized`: Maximize or restore the window.
158 * - `window.close`: Close the window.
159 */
160
161#define MENU_BAR_ACCEL GDK_KEY_F10
162#define RESIZE_HANDLE_SIZE 12 /* Width of resize borders */
163#define RESIZE_HANDLE_CORNER_SIZE 24 /* How resize corners extend */
164#define MNEMONICS_DELAY 300 /* ms */
165#define NO_CONTENT_CHILD_NAT 200 /* ms */
166#define VISIBLE_FOCUS_DURATION 3 /* s */
167
168
169/* In case the content (excluding header bar and shadows) of the window
170 * would be empty, either because there is no visible child widget or only an
171 * empty container widget, we use NO_CONTENT_CHILD_NAT as natural width/height
172 * instead.
173 */
174
175typedef struct _GtkWindowGeometryInfo GtkWindowGeometryInfo;
176
177typedef struct
178{
179 GtkWidget *child;
180
181 GtkWidget *default_widget;
182 GtkWidget *focus_widget;
183 GtkWidget *move_focus_widget;
184 GtkWindow *transient_parent;
185 GtkWindowGeometryInfo *geometry_info;
186 GtkWindowGroup *group;
187 GdkDisplay *display;
188 GtkApplication *application;
189
190 int default_width;
191 int default_height;
192
193 char *startup_id;
194 char *title;
195
196 guint keys_changed_handler;
197
198 guint32 initial_timestamp;
199
200 guint mnemonics_display_timeout_id;
201
202 guint focus_visible_timeout;
203
204 int scale;
205
206 int title_height;
207 GtkWidget *title_box;
208 GtkWidget *titlebar;
209 GtkWidget *key_press_focus;
210
211 GdkMonitor *initial_fullscreen_monitor;
212 guint edge_constraints;
213
214 GdkToplevelState state;
215
216 /* The following flags are initially TRUE (before a window is mapped).
217 * They cause us to compute a configure request that involves
218 * default-only parameters. Once mapped, we set them to FALSE.
219 * Then we set them to TRUE again on unmap (for position)
220 * and on unrealize (for size).
221 */
222 guint need_default_size : 1;
223
224 guint decorated : 1;
225 guint deletable : 1;
226 guint destroy_with_parent : 1;
227 guint minimize_initially : 1;
228 guint is_active : 1;
229 guint mnemonics_visible : 1;
230 guint focus_visible : 1;
231 guint modal : 1;
232 guint resizable : 1;
233 guint transient_parent_group : 1;
234 guint csd_requested : 1;
235 guint client_decorated : 1; /* Decorations drawn client-side */
236 guint use_client_shadow : 1; /* Decorations use client-side shadows */
237 guint maximized : 1;
238 guint fullscreen : 1;
239 guint tiled : 1;
240
241 guint hide_on_close : 1;
242 guint in_emit_close_request : 1;
243 guint move_focus : 1;
244 guint unset_default : 1;
245
246
247 GtkGesture *click_gesture;
248 GtkEventController *application_shortcut_controller;
249
250 GdkSurface *surface;
251 GskRenderer *renderer;
252
253 GList *foci;
254
255 GtkConstraintSolver *constraint_solver;
256
257 int surface_width;
258 int surface_height;
259
260 GdkCursor *resize_cursor;
261
262 GtkEventController *menubar_controller;
263} GtkWindowPrivate;
264
265enum {
266 SET_FOCUS,
267 ACTIVATE_FOCUS,
268 ACTIVATE_DEFAULT,
269 KEYS_CHANGED,
270 ENABLE_DEBUGGING,
271 CLOSE_REQUEST,
272 LAST_SIGNAL
273};
274
275enum {
276 PROP_0,
277
278 /* Normal Props */
279 PROP_TITLE,
280 PROP_RESIZABLE,
281 PROP_MODAL,
282 PROP_DEFAULT_WIDTH,
283 PROP_DEFAULT_HEIGHT,
284 PROP_DESTROY_WITH_PARENT,
285 PROP_HIDE_ON_CLOSE,
286 PROP_ICON_NAME,
287 PROP_DISPLAY,
288 PROP_DECORATED,
289 PROP_DELETABLE,
290 PROP_TRANSIENT_FOR,
291 PROP_APPLICATION,
292 PROP_DEFAULT_WIDGET,
293 PROP_FOCUS_WIDGET,
294 PROP_CHILD,
295 PROP_TITLEBAR,
296 PROP_HANDLE_MENUBAR_ACCEL,
297
298 /* Readonly properties */
299 PROP_IS_ACTIVE,
300
301 /* Writeonly properties */
302 PROP_STARTUP_ID,
303
304 PROP_MNEMONICS_VISIBLE,
305 PROP_FOCUS_VISIBLE,
306
307 PROP_MAXIMIZED,
308 PROP_FULLSCREENED,
309
310 LAST_ARG
311};
312
313static GParamSpec *window_props[LAST_ARG] = { NULL, };
314
315/* Must be kept in sync with GdkSurfaceEdge ! */
316typedef enum
317{
318 GTK_WINDOW_REGION_EDGE_NW,
319 GTK_WINDOW_REGION_EDGE_N,
320 GTK_WINDOW_REGION_EDGE_NE,
321 GTK_WINDOW_REGION_EDGE_W,
322 GTK_WINDOW_REGION_EDGE_E,
323 GTK_WINDOW_REGION_EDGE_SW,
324 GTK_WINDOW_REGION_EDGE_S,
325 GTK_WINDOW_REGION_EDGE_SE,
326 GTK_WINDOW_REGION_CONTENT,
327} GtkWindowRegion;
328
329typedef struct
330{
331 char *icon_name;
332 guint realized : 1;
333 guint using_default_icon : 1;
334 guint using_themed_icon : 1;
335} GtkWindowIconInfo;
336
337typedef struct {
338 GdkGeometry geometry; /* Last set of geometry hints we set */
339 GdkSurfaceHints flags;
340 GdkRectangle configure_request;
341} GtkWindowLastGeometryInfo;
342
343struct _GtkWindowGeometryInfo
344{
345 GtkWindowLastGeometryInfo last;
346};
347
348static void gtk_window_constructed (GObject *object);
349static void gtk_window_dispose (GObject *object);
350static void gtk_window_finalize (GObject *object);
351static void gtk_window_show (GtkWidget *widget);
352static void gtk_window_hide (GtkWidget *widget);
353static void gtk_window_map (GtkWidget *widget);
354static void gtk_window_unmap (GtkWidget *widget);
355static void gtk_window_realize (GtkWidget *widget);
356static void gtk_window_unrealize (GtkWidget *widget);
357static void gtk_window_size_allocate (GtkWidget *widget,
358 int width,
359 int height,
360 int baseline);
361static gboolean gtk_window_close_request (GtkWindow *window);
362static gboolean gtk_window_handle_focus (GtkWidget *widget,
363 GdkEvent *event,
364 double x,
365 double y);
366static gboolean gtk_window_key_pressed (GtkWidget *widget,
367 guint keyval,
368 guint keycode,
369 GdkModifierType state,
370 gpointer data);
371static gboolean gtk_window_key_released (GtkWidget *widget,
372 guint keyval,
373 guint keycode,
374 GdkModifierType state,
375 gpointer data);
376
377static void surface_state_changed (GtkWidget *widget);
378static void surface_size_changed (GtkWidget *widget,
379 int width,
380 int height);
381static gboolean surface_render (GdkSurface *surface,
382 cairo_region_t *region,
383 GtkWidget *widget);
384static gboolean surface_event (GdkSurface *surface,
385 GdkEvent *event,
386 GtkWidget *widget);
387static void after_paint (GdkFrameClock *clock,
388 GtkWindow *window);
389
390static int gtk_window_focus (GtkWidget *widget,
391 GtkDirectionType direction);
392static void gtk_window_move_focus (GtkWidget *widget,
393 GtkDirectionType dir);
394
395static void gtk_window_get_remembered_size (GtkWindow *window,
396 int *width,
397 int *height);
398
399static void gtk_window_real_activate_default (GtkWindow *window);
400static void gtk_window_real_activate_focus (GtkWindow *window);
401static void gtk_window_keys_changed (GtkWindow *window);
402static gboolean gtk_window_enable_debugging (GtkWindow *window,
403 gboolean toggle);
404static void gtk_window_unset_transient_for (GtkWindow *window);
405static void gtk_window_transient_parent_realized (GtkWidget *parent,
406 GtkWidget *window);
407static void gtk_window_transient_parent_unrealized (GtkWidget *parent,
408 GtkWidget *window);
409
410static GtkWindowGeometryInfo* gtk_window_get_geometry_info (GtkWindow *window,
411 gboolean create);
412
413static void gtk_window_set_default_size_internal (GtkWindow *window,
414 gboolean change_width,
415 int width,
416 gboolean change_height,
417 int height);
418
419static void update_themed_icon (GtkWindow *window);
420static GList *icon_list_from_theme (GtkWindow *window,
421 const char *name);
422static void gtk_window_realize_icon (GtkWindow *window);
423static void gtk_window_unrealize_icon (GtkWindow *window);
424static void update_window_actions (GtkWindow *window);
425static void get_shadow_width (GtkWindow *window,
426 GtkBorder *shadow_width);
427
428static gboolean gtk_window_activate_menubar (GtkWidget *widget,
429 GVariant *args,
430 gpointer unused);
431#ifdef GDK_WINDOWING_X11
432static void gtk_window_on_theme_variant_changed (GtkSettings *settings,
433 GParamSpec *pspec,
434 GtkWindow *window);
435#endif
436static void gtk_window_set_theme_variant (GtkWindow *window);
437
438static void gtk_window_activate_default_activate (GtkWidget *widget,
439 const char *action_name,
440 GVariant *parameter);
441static void gtk_window_activate_minimize (GtkWidget *widget,
442 const char *action_name,
443 GVariant *parameter);
444static void gtk_window_activate_toggle_maximized (GtkWidget *widget,
445 const char *name,
446 GVariant *parameter);
447static void gtk_window_activate_close (GtkWidget *widget,
448 const char *action_name,
449 GVariant *parameter);
450
451static void gtk_window_css_changed (GtkWidget *widget,
452 GtkCssStyleChange *change);
453static void _gtk_window_set_is_active (GtkWindow *window,
454 gboolean is_active);
455static void gtk_window_present_toplevel (GtkWindow *window);
456static void gtk_window_update_toplevel (GtkWindow *window,
457 GdkToplevelLayout *layout);
458
459static void gtk_window_release_application (GtkWindow *window);
460
461static GListStore *toplevel_list = NULL;
462static guint window_signals[LAST_SIGNAL] = { 0 };
463static char *default_icon_name = NULL;
464static gboolean disable_startup_notification = FALSE;
465
466static GQuark quark_gtk_window_icon_info = 0;
467
468static GtkBuildableIface *parent_buildable_iface;
469
470static void gtk_window_set_property (GObject *object,
471 guint prop_id,
472 const GValue *value,
473 GParamSpec *pspec);
474static void gtk_window_get_property (GObject *object,
475 guint prop_id,
476 GValue *value,
477 GParamSpec *pspec);
478
479/* GtkBuildable */
480static void gtk_window_buildable_interface_init (GtkBuildableIface *iface);
481static void gtk_window_buildable_add_child (GtkBuildable *buildable,
482 GtkBuilder *builder,
483 GObject *child,
484 const char *type);
485
486static void gtk_window_shortcut_manager_interface_init (GtkShortcutManagerInterface *iface);
487/* GtkRoot */
488static void gtk_window_root_interface_init (GtkRootInterface *iface);
489static void gtk_window_native_interface_init (GtkNativeInterface *iface);
490
491static void gtk_window_accessible_interface_init (GtkAccessibleInterface *iface);
492
493
494static void ensure_state_flag_backdrop (GtkWidget *widget);
495static void unset_titlebar (GtkWindow *window);
496
497#define INCLUDE_CSD_SIZE 1
498#define EXCLUDE_CSD_SIZE -1
499
500static void
501gtk_window_update_csd_size (GtkWindow *window,
502 int *width,
503 int *height,
504 int apply);
505
506G_DEFINE_TYPE_WITH_CODE (GtkWindow, gtk_window, GTK_TYPE_WIDGET,
507 G_ADD_PRIVATE (GtkWindow)
508 G_IMPLEMENT_INTERFACE (GTK_TYPE_ACCESSIBLE,
509 gtk_window_accessible_interface_init)
510 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
511 gtk_window_buildable_interface_init)
512 G_IMPLEMENT_INTERFACE (GTK_TYPE_NATIVE,
513 gtk_window_native_interface_init)
514 G_IMPLEMENT_INTERFACE (GTK_TYPE_SHORTCUT_MANAGER,
515 gtk_window_shortcut_manager_interface_init)
516 G_IMPLEMENT_INTERFACE (GTK_TYPE_ROOT,
517 gtk_window_root_interface_init))
518
519static GtkAccessibleInterface *parent_accessible_iface;
520
521static gboolean
522gtk_window_accessible_get_platform_state (GtkAccessible *self,
523 GtkAccessiblePlatformState state)
524{
525 switch (state)
526 {
527 case GTK_ACCESSIBLE_PLATFORM_STATE_FOCUSABLE:
528 case GTK_ACCESSIBLE_PLATFORM_STATE_FOCUSED:
529 return parent_accessible_iface->get_platform_state (self, state);
530 case GTK_ACCESSIBLE_PLATFORM_STATE_ACTIVE:
531 return gtk_window_is_active (GTK_WINDOW (self));
532 default:
533 g_assert_not_reached ();
534 }
535}
536
537static void
538gtk_window_accessible_interface_init (GtkAccessibleInterface *iface)
539{
540 parent_accessible_iface = g_type_interface_peek_parent (g_iface: iface);
541 iface->get_at_context = parent_accessible_iface->get_at_context;
542 iface->get_platform_state = gtk_window_accessible_get_platform_state;
543}
544
545static void
546add_tab_bindings (GtkWidgetClass *widget_class,
547 GdkModifierType modifiers,
548 GtkDirectionType direction)
549{
550 GtkShortcut *shortcut;
551
552 shortcut = gtk_shortcut_new_with_arguments (
553 trigger: gtk_alternative_trigger_new (first: gtk_keyval_trigger_new (GDK_KEY_Tab, modifiers),
554 second: gtk_keyval_trigger_new (GDK_KEY_KP_Tab, modifiers)),
555 action: gtk_signal_action_new (signal_name: "move-focus"),
556 format_string: "(i)", direction);
557
558 gtk_widget_class_add_shortcut (widget_class, shortcut);
559
560 g_object_unref (object: shortcut);
561}
562
563static void
564add_arrow_bindings (GtkWidgetClass *widget_class,
565 guint keysym,
566 GtkDirectionType direction)
567{
568 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
569
570 gtk_widget_class_add_binding_signal (widget_class, keyval: keysym, mods: 0,
571 signal: "move-focus",
572 format_string: "(i)",
573 direction);
574 gtk_widget_class_add_binding_signal (widget_class, keyval: keysym, mods: GDK_CONTROL_MASK,
575 signal: "move-focus",
576 format_string: "(i)",
577 direction);
578 gtk_widget_class_add_binding_signal (widget_class, keyval: keypad_keysym, mods: 0,
579 signal: "move-focus",
580 format_string: "(i)",
581 direction);
582 gtk_widget_class_add_binding_signal (widget_class, keyval: keypad_keysym, mods: GDK_CONTROL_MASK,
583 signal: "move-focus",
584 format_string: "(i)",
585 direction);
586}
587
588static guint32
589extract_time_from_startup_id (const char * startup_id)
590{
591 char *timestr = g_strrstr (haystack: startup_id, needle: "_TIME");
592 guint32 retval = GDK_CURRENT_TIME;
593
594 if (timestr)
595 {
596 char *end;
597 guint32 timestamp;
598
599 /* Skip past the "_TIME" part */
600 timestr += 5;
601
602 end = NULL;
603 errno = 0;
604 timestamp = g_ascii_strtoull (nptr: timestr, endptr: &end, base: 0);
605 if (errno == 0 && end != timestr)
606 retval = timestamp;
607 }
608
609 return retval;
610}
611
612static gboolean
613startup_id_is_fake (const char * startup_id)
614{
615 return strncmp (s1: startup_id, s2: "_TIME", n: 5) == 0;
616}
617
618static void
619gtk_window_measure (GtkWidget *widget,
620 GtkOrientation orientation,
621 int for_size,
622 int *minimum,
623 int *natural,
624 int *minimum_baseline,
625 int *natural_baseline)
626{
627 GtkWindow *window = GTK_WINDOW (widget);
628 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
629 GtkWidget *child = priv->child;
630 gboolean has_size_request = gtk_widget_has_size_request (widget);
631 int title_for_size = for_size;
632 int title_min_size = 0;
633 int title_nat_size = 0;
634 int child_for_size = for_size;
635 int child_min_size = 0;
636 int child_nat_size = 0;
637
638 if (priv->decorated && !priv->fullscreen)
639 {
640 if (priv->title_box != NULL &&
641 gtk_widget_get_visible (widget: priv->title_box) &&
642 gtk_widget_get_child_visible (widget: priv->title_box))
643 {
644 if (orientation == GTK_ORIENTATION_HORIZONTAL && for_size >= 0 &&
645 child != NULL && gtk_widget_get_visible (widget: child))
646 {
647 GtkRequestedSize sizes[2];
648
649 gtk_widget_measure (widget: priv->title_box,
650 orientation: GTK_ORIENTATION_VERTICAL,
651 for_size: -1,
652 minimum: &sizes[0].minimum_size, natural: &sizes[0].natural_size,
653 NULL, NULL);
654 gtk_widget_measure (widget: child,
655 orientation: GTK_ORIENTATION_VERTICAL,
656 for_size: -1,
657 minimum: &sizes[1].minimum_size, natural: &sizes[1].natural_size,
658 NULL, NULL);
659 for_size -= sizes[0].minimum_size + sizes[1].minimum_size;
660 for_size = gtk_distribute_natural_allocation (extra_space: for_size, n_requested_sizes: 2, sizes);
661 title_for_size = sizes[0].minimum_size;
662 child_for_size = sizes[1].minimum_size + for_size;
663 }
664
665 gtk_widget_measure (widget: priv->title_box,
666 orientation,
667 for_size: title_for_size,
668 minimum: &title_min_size, natural: &title_nat_size,
669 NULL, NULL);
670 }
671 }
672
673 if (child != NULL && gtk_widget_get_visible (widget: child))
674 {
675 gtk_widget_measure (widget: child,
676 orientation,
677 for_size: child_for_size,
678 minimum: &child_min_size, natural: &child_nat_size,
679 NULL, NULL);
680
681 if (child_nat_size == 0 && !has_size_request)
682 child_nat_size = NO_CONTENT_CHILD_NAT;
683 }
684 else if (!has_size_request)
685 {
686 child_nat_size = NO_CONTENT_CHILD_NAT;
687 }
688
689 if (orientation == GTK_ORIENTATION_HORIZONTAL)
690 {
691 *minimum = MAX (title_min_size, child_min_size);
692 *natural = MAX (title_nat_size, child_nat_size);
693 }
694 else
695 {
696 *minimum = title_min_size + child_min_size;
697 *natural = title_nat_size + child_nat_size;
698 }
699}
700
701static void
702gtk_window_compute_expand (GtkWidget *widget,
703 gboolean *hexpand,
704 gboolean *vexpand)
705{
706 GtkWindow *window = GTK_WINDOW (widget);
707 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
708
709 if (priv->child)
710 {
711 *hexpand = gtk_widget_compute_expand (widget: priv->child, orientation: GTK_ORIENTATION_HORIZONTAL);
712 *vexpand = gtk_widget_compute_expand (widget: priv->child, orientation: GTK_ORIENTATION_VERTICAL);
713 }
714 else
715 {
716 *hexpand = FALSE;
717 *vexpand = FALSE;
718 }
719}
720
721static GtkSizeRequestMode
722gtk_window_get_request_mode (GtkWidget *widget)
723{
724 GtkWindow *window = GTK_WINDOW (widget);
725 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
726
727 if (priv->child)
728 return gtk_widget_get_request_mode (widget: priv->child);
729 else
730 return GTK_SIZE_REQUEST_CONSTANT_SIZE;
731}
732
733static void
734gtk_window_class_init (GtkWindowClass *klass)
735{
736 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
737 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
738
739 quark_gtk_window_icon_info = g_quark_from_static_string (string: "gtk-window-icon-info");
740
741 if (toplevel_list == NULL)
742 toplevel_list = g_list_store_new (GTK_TYPE_WIDGET);
743
744 gobject_class->constructed = gtk_window_constructed;
745 gobject_class->dispose = gtk_window_dispose;
746 gobject_class->finalize = gtk_window_finalize;
747
748 gobject_class->set_property = gtk_window_set_property;
749 gobject_class->get_property = gtk_window_get_property;
750
751 widget_class->show = gtk_window_show;
752 widget_class->hide = gtk_window_hide;
753 widget_class->map = gtk_window_map;
754 widget_class->unmap = gtk_window_unmap;
755 widget_class->realize = gtk_window_realize;
756 widget_class->unrealize = gtk_window_unrealize;
757 widget_class->size_allocate = gtk_window_size_allocate;
758 widget_class->compute_expand = gtk_window_compute_expand;
759 widget_class->get_request_mode = gtk_window_get_request_mode;
760 widget_class->focus = gtk_window_focus;
761 widget_class->move_focus = gtk_window_move_focus;
762 widget_class->measure = gtk_window_measure;
763 widget_class->css_changed = gtk_window_css_changed;
764
765 klass->activate_default = gtk_window_real_activate_default;
766 klass->activate_focus = gtk_window_real_activate_focus;
767 klass->keys_changed = gtk_window_keys_changed;
768 klass->enable_debugging = gtk_window_enable_debugging;
769 klass->close_request = gtk_window_close_request;
770
771 /**
772 * GtkWindow:title: (attributes org.gtk.Property.get=gtk_window_get_title org.gtk.Property.set=gtk_window_set_title)
773 *
774 * The title of the window.
775 */
776 window_props[PROP_TITLE] =
777 g_param_spec_string (name: "title",
778 P_("Window Title"),
779 P_("The title of the window"),
780 NULL,
781 GTK_PARAM_READWRITE);
782
783 /**
784 * GtkWindow:startup-id: (attributes org.gtk.Property.set=gtk_window_set_startup_id)
785 *
786 * A write-only property for setting window's startup notification identifier.
787 */
788 window_props[PROP_STARTUP_ID] =
789 g_param_spec_string (name: "startup-id",
790 P_("Startup ID"),
791 P_("Unique startup identifier for the window used by startup-notification"),
792 NULL,
793 GTK_PARAM_WRITABLE);
794
795 /**
796 * GtkWindow:resizable: (attributes org.gtk.Property.get=gtk_window_get_resizable org.gtk.Property.set=gtk_window_set_resizable)
797 *
798 * If %TRUE, users can resize the window.
799 */
800 window_props[PROP_RESIZABLE] =
801 g_param_spec_boolean (name: "resizable",
802 P_("Resizable"),
803 P_("If TRUE, users can resize the window"),
804 TRUE,
805 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
806
807 /**
808 * GtkWindow:modal: (attributes org.gtk.Property.get=gtk_window_get_modal org.gtk.Property.set=gtk_window_set_modal)
809 *
810 * If %TRUE, the window is modal.
811 */
812 window_props[PROP_MODAL] =
813 g_param_spec_boolean (name: "modal",
814 P_("Modal"),
815 P_("If TRUE, the window is modal (other windows are not usable while this one is up)"),
816 FALSE,
817 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
818
819 /**
820 * GtkWindow:default-width:
821 *
822 * The default width of the window.
823 */
824 window_props[PROP_DEFAULT_WIDTH] =
825 g_param_spec_int (name: "default-width",
826 P_("Default Width"),
827 P_("The default width of the window"),
828 minimum: -1, G_MAXINT,
829 default_value: 0,
830 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
831
832 /**
833 * GtkWindow:default-height:
834 *
835 * The default height of the window.
836 */
837 window_props[PROP_DEFAULT_HEIGHT] =
838 g_param_spec_int (name: "default-height",
839 P_("Default Height"),
840 P_("The default height of the window"),
841 minimum: -1, G_MAXINT,
842 default_value: 0,
843 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
844
845 /**
846 * GtkWindow:destroy-with-parent: (attributes org.gtk.Property.get=gtk_window_get_destroy_with_parent org.gtk.Property.set=gtk_window_set_destroy_with_parent)
847 *
848 * If this window should be destroyed when the parent is destroyed.
849 */
850 window_props[PROP_DESTROY_WITH_PARENT] =
851 g_param_spec_boolean (name: "destroy-with-parent",
852 P_("Destroy with Parent"),
853 P_("If this window should be destroyed when the parent is destroyed"),
854 FALSE,
855 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
856
857 /**
858 * GtkWindow:hide-on-close: (attributes org.gtk.Property.get=gtk_window_get_hide_on_close org.gtk.Property.set=gtk_window_set_hide_on_close)
859 *
860 * If this window should be hidden when the users clicks the close button.
861 */
862 window_props[PROP_HIDE_ON_CLOSE] =
863 g_param_spec_boolean (name: "hide-on-close",
864 P_("Hide on close"),
865 P_("If this window should be hidden when the user clicks the close button"),
866 FALSE,
867 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
868
869 /**
870 * GtkWindow:mnemonics-visible: (attributes org.gtk.Property.get=gtk_window_get_mnemonics_visible org.gtk.Property.set=gtk_window_set_mnemonics_visible)
871 *
872 * Whether mnemonics are currently visible in this window.
873 *
874 * This property is maintained by GTK based on user input,
875 * and should not be set by applications.
876 */
877 window_props[PROP_MNEMONICS_VISIBLE] =
878 g_param_spec_boolean (name: "mnemonics-visible",
879 P_("Mnemonics Visible"),
880 P_("Whether mnemonics are currently visible in this window"),
881 FALSE,
882 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
883
884 /**
885 * GtkWindow:focus-visible: (attributes org.gtk.Property.get=gtk_window_get_focus_visible org.gtk.Property.set=gtk_window_set_focus_visible)
886 *
887 * Whether 'focus rectangles' are currently visible in this window.
888 *
889 * This property is maintained by GTK based on user input
890 * and should not be set by applications.
891 */
892 window_props[PROP_FOCUS_VISIBLE] =
893 g_param_spec_boolean (name: "focus-visible",
894 P_("Focus Visible"),
895 P_("Whether focus rectangles are currently visible in this window"),
896 TRUE,
897 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
898
899 /**
900 * GtkWindow:icon-name: (attributes org.gtk.Property.get=gtk_window_get_icon_name org.gtk.Property.set=gtk_window_set_icon_name)
901 *
902 * Specifies the name of the themed icon to use as the window icon.
903 *
904 * See [class@Gtk.IconTheme] for more details.
905 */
906 window_props[PROP_ICON_NAME] =
907 g_param_spec_string (name: "icon-name",
908 P_("Icon Name"),
909 P_("Name of the themed icon for this window"),
910 NULL,
911 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
912
913 /**
914 * GtkWindow:display: (attributes org.gtk.Property.set=gtk_window_set_display)
915 *
916 * The display that will display this window.
917 */
918 window_props[PROP_DISPLAY] =
919 g_param_spec_object (name: "display",
920 P_("Display"),
921 P_("The display that will display this window"),
922 GDK_TYPE_DISPLAY,
923 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
924
925 /**
926 * GtkWindow:is-active: (attributes org.gtk.Property.get=gtk_window_is_active)
927 *
928 * Whether the toplevel is the currently active window.
929 */
930 window_props[PROP_IS_ACTIVE] =
931 g_param_spec_boolean (name: "is-active",
932 P_("Is Active"),
933 P_("Whether the toplevel is the current active window"),
934 FALSE,
935 GTK_PARAM_READABLE);
936
937 /**
938 * GtkWindow:decorated: (attributes org.gtk.Property.get=gtk_window_get_decorated org.gtk.Property.set=gtk_window_set_decorated)
939 *
940 * Whether the window should have a frame (also known as *decorations*).
941 */
942 window_props[PROP_DECORATED] =
943 g_param_spec_boolean (name: "decorated",
944 P_("Decorated"),
945 P_("Whether the window should be decorated by the window manager"),
946 TRUE,
947 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
948
949 /**
950 * GtkWindow:deletable: (attributes org.gtk.Property.get=gtk_window_get_deletable org.gtk.Property.set=gtk_window_set_deletable)
951 *
952 * Whether the window frame should have a close button.
953 */
954 window_props[PROP_DELETABLE] =
955 g_param_spec_boolean (name: "deletable",
956 P_("Deletable"),
957 P_("Whether the window frame should have a close button"),
958 TRUE,
959 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
960
961 /**
962 * GtkWindow:transient-for: (attributes org.gtk.Property.get=gtk_window_get_transient_for org.gtk.Property.set=gtk_window_set_transient_for)
963 *
964 * The transient parent of the window.
965 */
966 window_props[PROP_TRANSIENT_FOR] =
967 g_param_spec_object (name: "transient-for",
968 P_("Transient for Window"),
969 P_("The transient parent of the dialog"),
970 GTK_TYPE_WINDOW,
971 GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY);
972
973 /**
974 * GtkWindow:maximized: (attributes org.gtk.Property.get=gtk_window_is_maximized)
975 *
976 * Whether the window is maximized.
977 *
978 * Setting this property is the equivalent of calling
979 * [method@Gtk.Window.maximize] or [method@Gtk.Window.unmaximize];
980 * either operation is asynchronous, which means you will need to
981 * connect to the ::notify signal in order to know whether the
982 * operation was successful.
983 */
984 window_props[PROP_MAXIMIZED] =
985 g_param_spec_boolean (name: "maximized",
986 P_("Is Maximized"),
987 P_("Whether the window is maximized"),
988 FALSE,
989 GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY);
990
991 /**
992 * GtkWindow:fullscreened: (attributes org.gtk.Property.get=gtk_window_is_fullscreen)
993 *
994 * Whether the window is fullscreen.
995 *
996 * Setting this property is the equivalent of calling
997 * [method@Gtk.Window.fullscreen] or [method@Gtk.Window.unfullscreen];
998 * either operation is asynchronous, which means you will need to
999 * connect to the ::notify signal in order to know whether the
1000 * operation was successful.
1001 */
1002 window_props[PROP_FULLSCREENED] =
1003 g_param_spec_boolean (name: "fullscreened",
1004 P_("Is fullscreen"),
1005 P_("Whether the window is fullscreen"),
1006 FALSE,
1007 GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY);
1008
1009 /**
1010 * GtkWindow:application: (attributes org.gtk.Property.get=gtk_window_get_application org.gtk.Property.set=gtk_window_set_application)
1011 *
1012 * The `GtkApplication` associated with the window.
1013 *
1014 * The application will be kept alive for at least as long as it
1015 * has any windows associated with it (see g_application_hold()
1016 * for a way to keep it alive without windows).
1017 *
1018 * Normally, the connection between the application and the window
1019 * will remain until the window is destroyed, but you can explicitly
1020 * remove it by setting the :application property to %NULL.
1021 */
1022 window_props[PROP_APPLICATION] =
1023 g_param_spec_object (name: "application",
1024 P_("GtkApplication"),
1025 P_("The GtkApplication for the window"),
1026 GTK_TYPE_APPLICATION,
1027 GTK_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
1028
1029 /**
1030 * GtkWindow:default-widget: (attributes org.gtk.Property.get=gtk_window_get_default_widget org.gtk.Property.set=gtk_window_set_default_widget)
1031 *
1032 * The default widget.
1033 */
1034 window_props[PROP_DEFAULT_WIDGET] =
1035 g_param_spec_object (name: "default-widget",
1036 P_("Default widget"),
1037 P_("The default widget"),
1038 GTK_TYPE_WIDGET,
1039 GTK_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
1040
1041 /**
1042 * GtkWindow:focus-widget: (attributes org.gtk.Property.get=gtk_window_get_focus org.gtk.Property.set=gtk_window_set_focus)
1043 *
1044 * The focus widget.
1045 */
1046 window_props[PROP_FOCUS_WIDGET] =
1047 g_param_spec_object (name: "focus-widget",
1048 P_("Focus widget"),
1049 P_("The focus widget"),
1050 GTK_TYPE_WIDGET,
1051 GTK_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
1052
1053 /**
1054 * GtkWindow:child: (attributes org.gtk.Property.get=gtk_window_get_child org.gtk.Property.set=gtk_window_set_child)
1055 *
1056 * The child widget.
1057 */
1058 window_props[PROP_CHILD] =
1059 g_param_spec_object (name: "child",
1060 P_("Child"),
1061 P_("The child widget"),
1062 GTK_TYPE_WIDGET,
1063 GTK_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
1064
1065 /**
1066 * GtkWindow:titlebar: (attributes org.gtk.Property.get=gtk_window_get_titlebar org.gtk.Property.set=gtk_window_set_titlebar)
1067 *
1068 * The titlebar widget.
1069 *
1070 * Since: 4.6
1071 */
1072 window_props[PROP_TITLEBAR] =
1073 g_param_spec_object (name: "titlebar",
1074 P_("Titlebar"),
1075 P_("The titlebar widget"),
1076 GTK_TYPE_WIDGET,
1077 GTK_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
1078
1079 /**
1080 * GtkWindow:handle-menubar-accel: (attributes org.gtk.Property.get=gtk_window_get_handle_menubar_accel org.gtk.Property.set=gtk_window_set_handle_menubar_accel)
1081 *
1082 * Whether the window frame should handle F10 for activating
1083 * menubars.
1084 *
1085 * Since: 4.2
1086 */
1087 window_props[PROP_HANDLE_MENUBAR_ACCEL] =
1088 g_param_spec_boolean (name: "handle-menubar-accel",
1089 P_("Handle Menubar accels"),
1090 P_("Whether the window should handle F10"),
1091 TRUE,
1092 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1093
1094 g_object_class_install_properties (oclass: gobject_class, n_pspecs: LAST_ARG, pspecs: window_props);
1095
1096 /**
1097 * GtkWindow::activate-focus:
1098 * @window: the window which received the signal
1099 *
1100 * Emitted when the user activates the currently focused
1101 * widget of @window.
1102 *
1103 * This is a [keybinding signal](class.SignalAction.html).
1104 */
1105 window_signals[ACTIVATE_FOCUS] =
1106 g_signal_new (I_("activate-focus"),
1107 G_TYPE_FROM_CLASS (gobject_class),
1108 signal_flags: G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1109 G_STRUCT_OFFSET (GtkWindowClass, activate_focus),
1110 NULL, NULL,
1111 NULL,
1112 G_TYPE_NONE,
1113 n_params: 0);
1114
1115 /**
1116 * GtkWindow::activate-default:
1117 * @window: the window which received the signal
1118 *
1119 * Emitted when the user activates the default widget
1120 * of @window.
1121 *
1122 * This is a [keybinding signal](class.SignalAction.html).
1123 */
1124 window_signals[ACTIVATE_DEFAULT] =
1125 g_signal_new (I_("activate-default"),
1126 G_TYPE_FROM_CLASS (gobject_class),
1127 signal_flags: G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1128 G_STRUCT_OFFSET (GtkWindowClass, activate_default),
1129 NULL, NULL,
1130 NULL,
1131 G_TYPE_NONE,
1132 n_params: 0);
1133
1134 /**
1135 * GtkWindow::keys-changed:
1136 * @window: the window which received the signal
1137 *
1138 * emitted when the set of accelerators or mnemonics that
1139 * are associated with @window changes.
1140 */
1141 window_signals[KEYS_CHANGED] =
1142 g_signal_new (I_("keys-changed"),
1143 G_TYPE_FROM_CLASS (gobject_class),
1144 signal_flags: G_SIGNAL_RUN_FIRST,
1145 G_STRUCT_OFFSET (GtkWindowClass, keys_changed),
1146 NULL, NULL,
1147 NULL,
1148 G_TYPE_NONE,
1149 n_params: 0);
1150
1151 /**
1152 * GtkWindow::enable-debugging:
1153 * @window: the window on which the signal is emitted
1154 * @toggle: toggle the debugger
1155 *
1156 * Emitted when the user enables or disables interactive debugging.
1157 *
1158 * When @toggle is %TRUE, interactive debugging is toggled on or off,
1159 * when it is %FALSE, the debugger will be pointed at the widget
1160 * under the pointer.
1161 *
1162 * This is a [keybinding signal](class.SignalAction.html).
1163 *
1164 * The default bindings for this signal are Ctrl-Shift-I
1165 * and Ctrl-Shift-D.
1166 *
1167 * Return: %TRUE if the key binding was handled
1168 */
1169 window_signals[ENABLE_DEBUGGING] =
1170 g_signal_new (I_("enable-debugging"),
1171 G_TYPE_FROM_CLASS (gobject_class),
1172 signal_flags: G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1173 G_STRUCT_OFFSET (GtkWindowClass, enable_debugging),
1174 NULL, NULL,
1175 c_marshaller: _gtk_marshal_BOOLEAN__BOOLEAN,
1176 G_TYPE_BOOLEAN,
1177 n_params: 1, G_TYPE_BOOLEAN);
1178
1179 /**
1180 * GtkWindow::close-request:
1181 * @window: the window on which the signal is emitted
1182 *
1183 * Emitted when the user clicks on the close button of the window.
1184 *
1185 * Return: %TRUE to stop other handlers from being invoked for the signal
1186 */
1187 window_signals[CLOSE_REQUEST] =
1188 g_signal_new (I_("close-request"),
1189 G_TYPE_FROM_CLASS (gobject_class),
1190 signal_flags: G_SIGNAL_RUN_LAST,
1191 G_STRUCT_OFFSET (GtkWindowClass, close_request),
1192 accumulator: _gtk_boolean_handled_accumulator, NULL,
1193 NULL,
1194 G_TYPE_BOOLEAN,
1195 n_params: 0);
1196
1197 /*
1198 * Key bindings
1199 */
1200
1201 /**
1202 * GtkWindow|default.activate:
1203 *
1204 * Activate the default widget.
1205 */
1206 gtk_widget_class_install_action (widget_class, action_name: "default.activate", NULL,
1207 activate: gtk_window_activate_default_activate);
1208
1209 /**
1210 * GtkWindow|window.minimize:
1211 *
1212 * Minimize the window.
1213 */
1214 gtk_widget_class_install_action (widget_class, action_name: "window.minimize", NULL,
1215 activate: gtk_window_activate_minimize);
1216
1217 /**
1218 * GtkWindow|window.toggle-maximized:
1219 *
1220 * Maximize or restore the window.
1221 */
1222 gtk_widget_class_install_action (widget_class, action_name: "window.toggle-maximized", NULL,
1223 activate: gtk_window_activate_toggle_maximized);
1224
1225 /**
1226 * GtkWindow|window.close:
1227 *
1228 * Close the window.
1229 */
1230 gtk_widget_class_install_action (widget_class, action_name: "window.close", NULL,
1231 activate: gtk_window_activate_close);
1232
1233 gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_space, mods: 0,
1234 signal: "activate-focus", NULL);
1235 gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_KP_Space, mods: 0,
1236 signal: "activate-focus", NULL);
1237
1238 gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_Return, mods: 0,
1239 signal: "activate-default", NULL);
1240 gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_ISO_Enter, mods: 0,
1241 signal: "activate-default", NULL);
1242 gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_KP_Enter, mods: 0,
1243 signal: "activate-default", NULL);
1244
1245 gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_I, mods: GDK_CONTROL_MASK|GDK_SHIFT_MASK,
1246 signal: "enable-debugging", format_string: "(b)", FALSE);
1247 gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_D, mods: GDK_CONTROL_MASK|GDK_SHIFT_MASK,
1248 signal: "enable-debugging", format_string: "(b)", TRUE);
1249
1250 add_arrow_bindings (widget_class, GDK_KEY_Up, direction: GTK_DIR_UP);
1251 add_arrow_bindings (widget_class, GDK_KEY_Down, direction: GTK_DIR_DOWN);
1252 add_arrow_bindings (widget_class, GDK_KEY_Left, direction: GTK_DIR_LEFT);
1253 add_arrow_bindings (widget_class, GDK_KEY_Right, direction: GTK_DIR_RIGHT);
1254
1255 add_tab_bindings (widget_class, modifiers: 0, direction: GTK_DIR_TAB_FORWARD);
1256 add_tab_bindings (widget_class, modifiers: GDK_CONTROL_MASK, direction: GTK_DIR_TAB_FORWARD);
1257 add_tab_bindings (widget_class, modifiers: GDK_SHIFT_MASK, direction: GTK_DIR_TAB_BACKWARD);
1258 add_tab_bindings (widget_class, modifiers: GDK_CONTROL_MASK | GDK_SHIFT_MASK, direction: GTK_DIR_TAB_BACKWARD);
1259
1260 gtk_widget_class_set_css_name (widget_class, I_("window"));
1261
1262 gtk_widget_class_set_accessible_role (widget_class, accessible_role: GTK_ACCESSIBLE_ROLE_WINDOW);
1263}
1264
1265/**
1266 * gtk_window_is_maximized: (attributes org.gtk.Method.get_property=maximized)
1267 * @window: a `GtkWindow`
1268 *
1269 * Retrieves the current maximized state of @window.
1270 *
1271 * Note that since maximization is ultimately handled by the window
1272 * manager and happens asynchronously to an application request, you
1273 * shouldn’t assume the return value of this function changing
1274 * immediately (or at all), as an effect of calling
1275 * [method@Gtk.Window.maximize] or [method@Gtk.Window.unmaximize].
1276 *
1277 * If the window isn't yet mapped, the value returned will whether the
1278 * initial requested state is maximized.
1279 *
1280 * Returns: whether the window has a maximized state.
1281 */
1282gboolean
1283gtk_window_is_maximized (GtkWindow *window)
1284{
1285 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
1286
1287 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
1288
1289 return priv->maximized;
1290}
1291
1292/**
1293 * gtk_window_is_fullscreen: (attributes org.gtk.Property.get=fullscreened)
1294 * @window: a `GtkWindow`
1295 *
1296 * Retrieves the current fullscreen state of @window.
1297 *
1298 * Note that since fullscreening is ultimately handled by the window
1299 * manager and happens asynchronously to an application request, you
1300 * shouldn’t assume the return value of this function changing
1301 * immediately (or at all), as an effect of calling
1302 * [method@Gtk.Window.fullscreen] or [method@Gtk.Window.unfullscreen].
1303 *
1304 * If the window isn't yet mapped, the value returned will whether the
1305 * initial requested state is fullscreen.
1306 *
1307 * Returns: whether the window has a fullscreen state.
1308 */
1309gboolean
1310gtk_window_is_fullscreen (GtkWindow *window)
1311{
1312 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
1313
1314 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
1315
1316 return priv->fullscreen;
1317}
1318
1319void
1320_gtk_window_toggle_maximized (GtkWindow *window)
1321{
1322 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
1323
1324 if (priv->maximized)
1325 gtk_window_unmaximize (window);
1326 else
1327 gtk_window_maximize (window);
1328}
1329
1330/**
1331 * gtk_window_close:
1332 * @window: a `GtkWindow`
1333 *
1334 * Requests that the window is closed.
1335 *
1336 * This is similar to what happens when a window manager
1337 * close button is clicked.
1338 *
1339 * This function can be used with close buttons in custom
1340 * titlebars.
1341 */
1342void
1343gtk_window_close (GtkWindow *window)
1344{
1345 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
1346
1347 if (!_gtk_widget_get_realized (GTK_WIDGET (window)))
1348 return;
1349
1350 if (priv->in_emit_close_request)
1351 return;
1352
1353 g_object_ref (window);
1354
1355 if (!gtk_window_emit_close_request (window))
1356 gtk_window_destroy (window);
1357
1358 g_object_unref (object: window);
1359}
1360
1361static guint
1362constraints_for_edge (GdkSurfaceEdge edge)
1363{
1364 switch (edge)
1365 {
1366 case GDK_SURFACE_EDGE_NORTH_WEST:
1367 return GDK_TOPLEVEL_STATE_LEFT_RESIZABLE | GDK_TOPLEVEL_STATE_TOP_RESIZABLE;
1368 case GDK_SURFACE_EDGE_NORTH:
1369 return GDK_TOPLEVEL_STATE_TOP_RESIZABLE;
1370 case GDK_SURFACE_EDGE_NORTH_EAST:
1371 return GDK_TOPLEVEL_STATE_RIGHT_RESIZABLE | GDK_TOPLEVEL_STATE_TOP_RESIZABLE;
1372 case GDK_SURFACE_EDGE_WEST:
1373 return GDK_TOPLEVEL_STATE_LEFT_RESIZABLE;
1374 case GDK_SURFACE_EDGE_EAST:
1375 return GDK_TOPLEVEL_STATE_RIGHT_RESIZABLE;
1376 case GDK_SURFACE_EDGE_SOUTH_WEST:
1377 return GDK_TOPLEVEL_STATE_LEFT_RESIZABLE | GDK_TOPLEVEL_STATE_BOTTOM_RESIZABLE;
1378 case GDK_SURFACE_EDGE_SOUTH:
1379 return GDK_TOPLEVEL_STATE_BOTTOM_RESIZABLE;
1380 case GDK_SURFACE_EDGE_SOUTH_EAST:
1381 return GDK_TOPLEVEL_STATE_RIGHT_RESIZABLE | GDK_TOPLEVEL_STATE_BOTTOM_RESIZABLE;
1382 default:
1383 g_warn_if_reached ();
1384 return 0;
1385 }
1386}
1387
1388static int
1389get_number (GtkCssValue *value)
1390{
1391 double d = _gtk_css_number_value_get (number: value, one_hundred_percent: 100);
1392
1393 if (d < 1)
1394 return ceil (x: d);
1395 else
1396 return floor (x: d);
1397}
1398
1399static void
1400get_box_border (GtkCssStyle *style,
1401 GtkBorder *border)
1402{
1403 border->top = get_number (value: style->border->border_top_width) + get_number (value: style->size->padding_top);
1404 border->left = get_number (value: style->border->border_left_width) + get_number (value: style->size->padding_left);
1405 border->bottom = get_number (value: style->border->border_bottom_width) + get_number (value: style->size->padding_bottom);
1406 border->right = get_number (value: style->border->border_right_width) + get_number (value: style->size->padding_right);
1407}
1408
1409static int
1410get_edge_for_coordinates (GtkWindow *window,
1411 double x,
1412 double y)
1413{
1414 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
1415 gboolean supports_edge_constraints;
1416 GtkBorder handle_size;
1417 GtkCssBoxes css_boxes;
1418 const graphene_rect_t *border_rect;
1419 float left, top;
1420
1421#define edge_or_minus_one(edge) ((supports_edge_constraints && (priv->edge_constraints & constraints_for_edge (edge)) != constraints_for_edge (edge)) ? -1 : edge)
1422
1423 if (!priv->client_decorated ||
1424 !priv->resizable ||
1425 priv->fullscreen ||
1426 priv->maximized)
1427 return -1;
1428
1429 supports_edge_constraints = gdk_toplevel_supports_edge_constraints (toplevel: GDK_TOPLEVEL (ptr: priv->surface));
1430
1431 if (!supports_edge_constraints && priv->tiled)
1432 return -1;
1433
1434 gtk_css_boxes_init (boxes: &css_boxes, GTK_WIDGET (window));
1435 border_rect = gtk_css_boxes_get_content_rect (boxes: &css_boxes);
1436
1437 get_box_border (style: gtk_css_node_get_style (cssnode: gtk_widget_get_css_node (GTK_WIDGET (window))),
1438 border: &handle_size);
1439
1440 if (priv->use_client_shadow)
1441 {
1442 /* We use a maximum of RESIZE_HANDLE_SIZE pixels for the handle size */
1443 GtkBorder shadow;
1444
1445 get_shadow_width (window, shadow_width: &shadow);
1446 /* This logic is duplicated in update_realized_window_properties() */
1447 handle_size.left += shadow.left;
1448 handle_size.top += shadow.top;
1449 handle_size.right += shadow.right;
1450 handle_size.bottom += shadow.bottom;
1451 }
1452
1453 left = border_rect->origin.x;
1454 top = border_rect->origin.y;
1455
1456 if (x < left && x >= left - handle_size.left)
1457 {
1458 if (y < top + RESIZE_HANDLE_CORNER_SIZE && y >= top - handle_size.top)
1459 return edge_or_minus_one (GDK_SURFACE_EDGE_NORTH_WEST);
1460
1461 if (y > top + border_rect->size.height - RESIZE_HANDLE_CORNER_SIZE &&
1462 y <= top + border_rect->size.height + handle_size.bottom)
1463 return edge_or_minus_one (GDK_SURFACE_EDGE_SOUTH_WEST);
1464
1465 return edge_or_minus_one (GDK_SURFACE_EDGE_WEST);
1466 }
1467 else if (x > left + border_rect->size.width &&
1468 x <= left + border_rect->size.width + handle_size.right)
1469 {
1470 if (y < top + RESIZE_HANDLE_CORNER_SIZE && y >= top - handle_size.top)
1471 return edge_or_minus_one (GDK_SURFACE_EDGE_NORTH_EAST);
1472
1473 if (y > top + border_rect->size.height - RESIZE_HANDLE_CORNER_SIZE &&
1474 y <= top + border_rect->size.height + handle_size.bottom)
1475 return edge_or_minus_one (GDK_SURFACE_EDGE_SOUTH_EAST);
1476
1477 return edge_or_minus_one (GDK_SURFACE_EDGE_EAST);
1478 }
1479 else if (y < top && y >= top - handle_size.top)
1480 {
1481 if (x < left + RESIZE_HANDLE_CORNER_SIZE && x >= left - handle_size.left)
1482 return edge_or_minus_one (GDK_SURFACE_EDGE_NORTH_WEST);
1483
1484 if (x > left + border_rect->size.width - RESIZE_HANDLE_CORNER_SIZE &&
1485 x <= left + border_rect->size.width + handle_size.right)
1486 return edge_or_minus_one (GDK_SURFACE_EDGE_NORTH_EAST);
1487
1488 return edge_or_minus_one (GDK_SURFACE_EDGE_NORTH);
1489 }
1490 else if (y > top + border_rect->size.height &&
1491 y <= top + border_rect->size.height + handle_size.bottom)
1492 {
1493 if (x < left + RESIZE_HANDLE_CORNER_SIZE && x >= left - handle_size.left)
1494 return edge_or_minus_one (GDK_SURFACE_EDGE_SOUTH_WEST);
1495
1496 if (x > left + border_rect->size.width - RESIZE_HANDLE_CORNER_SIZE &&
1497 x <= left + border_rect->size.width + handle_size.right)
1498 return edge_or_minus_one (GDK_SURFACE_EDGE_SOUTH_EAST);
1499
1500 return edge_or_minus_one (GDK_SURFACE_EDGE_SOUTH);
1501 }
1502
1503 return -1;
1504}
1505
1506static void
1507click_gesture_pressed_cb (GtkGestureClick *gesture,
1508 int n_press,
1509 double x,
1510 double y,
1511 GtkWindow *window)
1512{
1513 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
1514 GdkEventSequence *sequence;
1515 GtkWindowRegion region;
1516 GdkEvent *event;
1517 GdkDevice *device;
1518 guint button;
1519 double tx, ty;
1520 int edge;
1521
1522 sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
1523 button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
1524 event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
1525 device = gtk_gesture_get_device (GTK_GESTURE (gesture));
1526
1527 if (!event)
1528 return;
1529
1530 if (button != GDK_BUTTON_PRIMARY)
1531 return;
1532
1533 if (priv->maximized)
1534 return;
1535
1536 if (gdk_display_device_is_grabbed (display: gtk_widget_get_display (GTK_WIDGET (window)), device))
1537 return;
1538
1539 if (!priv->client_decorated)
1540 return;
1541
1542 edge = get_edge_for_coordinates (window, x, y);
1543
1544 if (edge == -1)
1545 return;
1546
1547 region = (GtkWindowRegion)edge;
1548
1549 gtk_gesture_set_state (GTK_GESTURE (gesture), state: GTK_EVENT_SEQUENCE_CLAIMED);
1550
1551 gdk_event_get_position (event, x: &tx, y: &ty);
1552 gdk_toplevel_begin_resize (toplevel: GDK_TOPLEVEL (ptr: priv->surface),
1553 edge: (GdkSurfaceEdge) region,
1554 device,
1555 GDK_BUTTON_PRIMARY,
1556 x: tx, y: ty,
1557 timestamp: gdk_event_get_time (event));
1558
1559 gtk_event_controller_reset (GTK_EVENT_CONTROLLER (gesture));
1560}
1561
1562static void
1563device_removed_cb (GdkSeat *seat,
1564 GdkDevice *device,
1565 gpointer user_data)
1566{
1567 GtkWindow *window = user_data;
1568 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
1569 GList *l = priv->foci;
1570
1571 while (l)
1572 {
1573 GList *next;
1574 GtkPointerFocus *focus = l->data;
1575
1576 next = l->next;
1577
1578 if (focus->device == device)
1579 {
1580 priv->foci = g_list_delete_link (list: priv->foci, link_: l);
1581 gtk_pointer_focus_unref (focus);
1582 }
1583
1584 l = next;
1585 }
1586}
1587
1588static void
1589gtk_window_capture_motion (GtkWidget *widget,
1590 double x,
1591 double y)
1592{
1593 GtkWindow *window = GTK_WINDOW (widget);
1594 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
1595 const char *cursor_names[8] = {
1596 "nw-resize", "n-resize", "ne-resize",
1597 "w-resize", "e-resize",
1598 "sw-resize", "s-resize", "se-resize"
1599 };
1600 int edge;
1601
1602 edge = get_edge_for_coordinates (window, x, y);
1603 if (edge != -1 &&
1604 priv->resize_cursor &&
1605 strcmp (s1: gdk_cursor_get_name (cursor: priv->resize_cursor), s2: cursor_names[edge]) == 0)
1606 return;
1607
1608 g_clear_object (&priv->resize_cursor);
1609
1610 if (edge != -1)
1611 priv->resize_cursor = gdk_cursor_new_from_name (name: cursor_names[edge], NULL);
1612
1613 gtk_window_maybe_update_cursor (window, widget, NULL);
1614}
1615
1616static void
1617gtk_window_activate_default_activate (GtkWidget *widget,
1618 const char *name,
1619 GVariant *parameter)
1620{
1621 gtk_window_real_activate_default (GTK_WINDOW (widget));
1622}
1623
1624static void
1625gtk_window_activate_minimize (GtkWidget *widget,
1626 const char *name,
1627 GVariant *parameter)
1628{
1629 gtk_window_minimize (GTK_WINDOW (widget));
1630}
1631
1632static void
1633gtk_window_activate_toggle_maximized (GtkWidget *widget,
1634 const char *name,
1635 GVariant *parameter)
1636{
1637 _gtk_window_toggle_maximized (GTK_WINDOW (widget));
1638}
1639
1640static void
1641gtk_window_activate_close (GtkWidget *widget,
1642 const char *name,
1643 GVariant *parameter)
1644{
1645 gtk_window_close (GTK_WINDOW (widget));
1646}
1647
1648static gboolean
1649gtk_window_accept_rootwindow_drop (GtkDropTargetAsync *self,
1650 GdkDrop *drop,
1651 double x,
1652 double y,
1653 gpointer unused)
1654{
1655 gdk_drop_finish (self: drop, action: GDK_ACTION_MOVE);
1656
1657 return TRUE;
1658}
1659
1660static void
1661gtk_window_init (GtkWindow *window)
1662{
1663 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
1664 GtkWidget *widget;
1665 GdkSeat *seat;
1666 GtkEventController *controller;
1667 GtkDropTargetAsync *target;
1668 GtkShortcut *shortcut;
1669
1670 widget = GTK_WIDGET (window);
1671
1672 gtk_widget_set_overflow (widget, overflow: GTK_OVERFLOW_HIDDEN);
1673
1674 priv->title = NULL;
1675 priv->geometry_info = NULL;
1676 priv->focus_widget = NULL;
1677 priv->default_widget = NULL;
1678 priv->resizable = TRUE;
1679 priv->need_default_size = TRUE;
1680 priv->modal = FALSE;
1681 priv->decorated = TRUE;
1682 priv->display = gdk_display_get_default ();
1683
1684 priv->state = 0;
1685
1686 priv->deletable = TRUE;
1687 priv->startup_id = NULL;
1688 priv->initial_timestamp = GDK_CURRENT_TIME;
1689 priv->mnemonics_visible = FALSE;
1690 priv->focus_visible = TRUE;
1691 priv->initial_fullscreen_monitor = NULL;
1692
1693 g_object_ref_sink (window);
1694
1695#ifdef GDK_WINDOWING_X11
1696 g_signal_connect (gtk_settings_get_for_display (priv->display),
1697 "notify::gtk-application-prefer-dark-theme",
1698 G_CALLBACK (gtk_window_on_theme_variant_changed), window);
1699#endif
1700
1701 gtk_widget_add_css_class (widget, css_class: "background");
1702
1703 priv->scale = gtk_widget_get_scale_factor (widget);
1704
1705 target = gtk_drop_target_async_new (formats: gdk_content_formats_new (mime_types: (const char*[1]) { "application/x-rootwindow-drop" }, n_mime_types: 1),
1706 actions: GDK_ACTION_MOVE);
1707 g_signal_connect (target, "drop", G_CALLBACK (gtk_window_accept_rootwindow_drop), NULL);
1708 gtk_widget_add_controller (GTK_WIDGET (window), GTK_EVENT_CONTROLLER (target));
1709
1710 seat = gdk_display_get_default_seat (display: gtk_widget_get_display (widget));
1711 if (seat)
1712 g_signal_connect (seat, "device-removed",
1713 G_CALLBACK (device_removed_cb), window);
1714
1715 controller = gtk_event_controller_motion_new ();
1716 gtk_event_controller_set_propagation_phase (controller,
1717 phase: GTK_PHASE_CAPTURE);
1718 g_signal_connect_swapped (controller, "motion",
1719 G_CALLBACK (gtk_window_capture_motion), window);
1720 gtk_widget_add_controller (widget, controller);
1721
1722 controller = gtk_event_controller_key_new ();
1723 gtk_event_controller_set_propagation_phase (controller, phase: GTK_PHASE_CAPTURE);
1724 g_signal_connect_swapped (controller, "key-pressed",
1725 G_CALLBACK (gtk_window_key_pressed), window);
1726 g_signal_connect_swapped (controller, "key-released",
1727 G_CALLBACK (gtk_window_key_released), window);
1728 gtk_widget_add_controller (widget, controller);
1729
1730 controller = gtk_event_controller_legacy_new ();
1731 gtk_event_controller_set_name (controller, name: "gtk-window-toplevel-focus");
1732 g_signal_connect_swapped (controller, "event",
1733 G_CALLBACK (gtk_window_handle_focus), window);
1734 gtk_widget_add_controller (widget, controller);
1735
1736 controller = gtk_shortcut_controller_new ();
1737 gtk_event_controller_set_propagation_phase (controller, phase: GTK_PHASE_CAPTURE);
1738
1739 shortcut = gtk_shortcut_new (trigger: gtk_keyval_trigger_new (MENU_BAR_ACCEL, modifiers: 0),
1740 action: gtk_callback_action_new (callback: gtk_window_activate_menubar, NULL, NULL));
1741 gtk_shortcut_controller_add_shortcut (GTK_SHORTCUT_CONTROLLER (controller), shortcut);
1742 gtk_event_controller_set_name (controller, name: "gtk-window-menubar-accel");
1743 gtk_widget_add_controller (widget, controller);
1744
1745 priv->menubar_controller = controller;
1746}
1747
1748static void
1749gtk_window_constructed (GObject *object)
1750{
1751 GtkWindow *window = GTK_WINDOW (object);
1752 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
1753
1754 G_OBJECT_CLASS (gtk_window_parent_class)->constructed (object);
1755
1756 priv->click_gesture = gtk_gesture_click_new ();
1757 gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (priv->click_gesture), button: 0);
1758 gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (priv->click_gesture),
1759 phase: GTK_PHASE_BUBBLE);
1760 g_signal_connect (priv->click_gesture, "pressed",
1761 G_CALLBACK (click_gesture_pressed_cb), object);
1762 gtk_widget_add_controller (GTK_WIDGET (object), GTK_EVENT_CONTROLLER (priv->click_gesture));
1763
1764 g_list_store_append (store: toplevel_list, item: window);
1765
1766 gtk_accessible_update_state (self: GTK_ACCESSIBLE (ptr: window),
1767 first_state: GTK_ACCESSIBLE_STATE_HIDDEN, TRUE,
1768 -1);
1769
1770 g_object_unref (object: window);
1771}
1772
1773static void
1774gtk_window_set_property (GObject *object,
1775 guint prop_id,
1776 const GValue *value,
1777 GParamSpec *pspec)
1778{
1779 GtkWindow *window = GTK_WINDOW (object);
1780
1781 switch (prop_id)
1782 {
1783 case PROP_TITLE:
1784 gtk_window_set_title (window, title: g_value_get_string (value));
1785 break;
1786 case PROP_STARTUP_ID:
1787 gtk_window_set_startup_id (window, startup_id: g_value_get_string (value));
1788 break;
1789 case PROP_RESIZABLE:
1790 gtk_window_set_resizable (window, resizable: g_value_get_boolean (value));
1791 break;
1792 case PROP_MODAL:
1793 gtk_window_set_modal (window, modal: g_value_get_boolean (value));
1794 break;
1795 case PROP_DEFAULT_WIDTH:
1796 gtk_window_set_default_size_internal (window,
1797 TRUE, width: g_value_get_int (value),
1798 FALSE, height: -1);
1799 gtk_widget_queue_resize (GTK_WIDGET (window));
1800 break;
1801 case PROP_DEFAULT_HEIGHT:
1802 gtk_window_set_default_size_internal (window,
1803 FALSE, width: -1,
1804 TRUE, height: g_value_get_int (value));
1805 gtk_widget_queue_resize (GTK_WIDGET (window));
1806 break;
1807 case PROP_DESTROY_WITH_PARENT:
1808 gtk_window_set_destroy_with_parent (window, setting: g_value_get_boolean (value));
1809 break;
1810 case PROP_HIDE_ON_CLOSE:
1811 gtk_window_set_hide_on_close (window, setting: g_value_get_boolean (value));
1812 break;
1813 case PROP_ICON_NAME:
1814 gtk_window_set_icon_name (window, name: g_value_get_string (value));
1815 break;
1816 case PROP_DISPLAY:
1817 gtk_window_set_display (window, display: g_value_get_object (value));
1818 break;
1819 case PROP_DECORATED:
1820 gtk_window_set_decorated (window, setting: g_value_get_boolean (value));
1821 break;
1822 case PROP_DELETABLE:
1823 gtk_window_set_deletable (window, setting: g_value_get_boolean (value));
1824 break;
1825 case PROP_TRANSIENT_FOR:
1826 gtk_window_set_transient_for (window, parent: g_value_get_object (value));
1827 break;
1828 case PROP_APPLICATION:
1829 gtk_window_set_application (window, application: g_value_get_object (value));
1830 break;
1831 case PROP_DEFAULT_WIDGET:
1832 gtk_window_set_default_widget (window, default_widget: g_value_get_object (value));
1833 break;
1834 case PROP_MNEMONICS_VISIBLE:
1835 gtk_window_set_mnemonics_visible (window, setting: g_value_get_boolean (value));
1836 break;
1837 case PROP_FOCUS_VISIBLE:
1838 gtk_window_set_focus_visible (window, setting: g_value_get_boolean (value));
1839 break;
1840 case PROP_MAXIMIZED:
1841 if (g_value_get_boolean (value))
1842 gtk_window_maximize (window);
1843 else
1844 gtk_window_unmaximize (window);
1845 break;
1846 case PROP_FULLSCREENED:
1847 if (g_value_get_boolean (value))
1848 gtk_window_fullscreen (window);
1849 else
1850 gtk_window_unfullscreen (window);
1851 break;
1852 case PROP_FOCUS_WIDGET:
1853 gtk_window_set_focus (window, focus: g_value_get_object (value));
1854 break;
1855 case PROP_CHILD:
1856 gtk_window_set_child (window, child: g_value_get_object (value));
1857 break;
1858 case PROP_TITLEBAR:
1859 gtk_window_set_titlebar (window, titlebar: g_value_get_object (value));
1860 break;
1861 case PROP_HANDLE_MENUBAR_ACCEL:
1862 gtk_window_set_handle_menubar_accel (window, handle_menubar_accel: g_value_get_boolean (value));
1863 break;
1864 default:
1865 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1866 break;
1867 }
1868}
1869
1870static void
1871gtk_window_get_property (GObject *object,
1872 guint prop_id,
1873 GValue *value,
1874 GParamSpec *pspec)
1875{
1876 GtkWindow *window = GTK_WINDOW (object);
1877 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
1878
1879 switch (prop_id)
1880 {
1881 case PROP_TITLE:
1882 g_value_set_string (value, v_string: priv->title);
1883 break;
1884 case PROP_RESIZABLE:
1885 g_value_set_boolean (value, v_boolean: priv->resizable);
1886 break;
1887 case PROP_MODAL:
1888 g_value_set_boolean (value, v_boolean: priv->modal);
1889 break;
1890 case PROP_DEFAULT_WIDTH:
1891 g_value_set_int (value, v_int: priv->default_width);
1892 break;
1893 case PROP_DEFAULT_HEIGHT:
1894 g_value_set_int (value, v_int: priv->default_height);
1895 break;
1896 case PROP_DESTROY_WITH_PARENT:
1897 g_value_set_boolean (value, v_boolean: priv->destroy_with_parent);
1898 break;
1899 case PROP_HIDE_ON_CLOSE:
1900 g_value_set_boolean (value, v_boolean: priv->hide_on_close);
1901 break;
1902 case PROP_ICON_NAME:
1903 g_value_set_string (value, v_string: gtk_window_get_icon_name (window));
1904 break;
1905 case PROP_DISPLAY:
1906 g_value_set_object (value, v_object: priv->display);
1907 break;
1908 case PROP_IS_ACTIVE:
1909 g_value_set_boolean (value, v_boolean: priv->is_active);
1910 break;
1911 case PROP_DECORATED:
1912 g_value_set_boolean (value, v_boolean: gtk_window_get_decorated (window));
1913 break;
1914 case PROP_DELETABLE:
1915 g_value_set_boolean (value, v_boolean: gtk_window_get_deletable (window));
1916 break;
1917 case PROP_TRANSIENT_FOR:
1918 g_value_set_object (value, v_object: gtk_window_get_transient_for (window));
1919 break;
1920 case PROP_APPLICATION:
1921 g_value_set_object (value, v_object: gtk_window_get_application (window));
1922 break;
1923 case PROP_DEFAULT_WIDGET:
1924 g_value_set_object (value, v_object: gtk_window_get_default_widget (window));
1925 break;
1926 case PROP_MNEMONICS_VISIBLE:
1927 g_value_set_boolean (value, v_boolean: priv->mnemonics_visible);
1928 break;
1929 case PROP_FOCUS_VISIBLE:
1930 g_value_set_boolean (value, v_boolean: priv->focus_visible);
1931 break;
1932 case PROP_MAXIMIZED:
1933 g_value_set_boolean (value, v_boolean: gtk_window_is_maximized (window));
1934 break;
1935 case PROP_FULLSCREENED:
1936 g_value_set_boolean (value, v_boolean: gtk_window_is_fullscreen (window));
1937 break;
1938 case PROP_FOCUS_WIDGET:
1939 g_value_set_object (value, v_object: gtk_window_get_focus (window));
1940 break;
1941 case PROP_CHILD:
1942 g_value_set_object (value, v_object: gtk_window_get_child (window));
1943 break;
1944 case PROP_TITLEBAR:
1945 g_value_set_object (value, v_object: gtk_window_get_titlebar (window));
1946 break;
1947 case PROP_HANDLE_MENUBAR_ACCEL:
1948 g_value_set_boolean (value, v_boolean: gtk_window_get_handle_menubar_accel (window));
1949 break;
1950 default:
1951 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1952 break;
1953 }
1954}
1955
1956static void
1957gtk_window_buildable_interface_init (GtkBuildableIface *iface)
1958{
1959 parent_buildable_iface = g_type_interface_peek_parent (g_iface: iface);
1960 iface->add_child = gtk_window_buildable_add_child;
1961}
1962
1963static void
1964gtk_window_buildable_add_child (GtkBuildable *buildable,
1965 GtkBuilder *builder,
1966 GObject *child,
1967 const char *type)
1968{
1969 if (type && strcmp (s1: type, s2: "titlebar") == 0)
1970 gtk_window_set_titlebar (GTK_WINDOW (buildable), GTK_WIDGET (child));
1971 else if (GTK_IS_WIDGET (child))
1972 gtk_window_set_child (GTK_WINDOW (buildable), GTK_WIDGET (child));
1973 else
1974 parent_buildable_iface->add_child (buildable, builder, child, type);
1975}
1976
1977static void
1978gtk_window_shortcut_manager_interface_init (GtkShortcutManagerInterface *iface)
1979{
1980}
1981
1982static GdkDisplay *
1983gtk_window_root_get_display (GtkRoot *root)
1984{
1985 GtkWindow *window = GTK_WINDOW (root);
1986 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
1987
1988 return priv->display;
1989}
1990
1991static GdkSurface *
1992gtk_window_native_get_surface (GtkNative *native)
1993{
1994 GtkWindow *self = GTK_WINDOW (native);
1995 GtkWindowPrivate *priv = gtk_window_get_instance_private (self);
1996
1997 return priv->surface;
1998}
1999
2000static GskRenderer *
2001gtk_window_native_get_renderer (GtkNative *native)
2002{
2003 GtkWindow *self = GTK_WINDOW (native);
2004 GtkWindowPrivate *priv = gtk_window_get_instance_private (self);
2005
2006 return priv->renderer;
2007}
2008
2009static GtkConstraintSolver *
2010gtk_window_root_get_constraint_solver (GtkRoot *root)
2011{
2012 GtkWindow *self = GTK_WINDOW (root);
2013 GtkWindowPrivate *priv = gtk_window_get_instance_private (self);
2014
2015 if (!priv->constraint_solver)
2016 {
2017 /* Shared constraint solver */
2018 priv->constraint_solver = gtk_constraint_solver_new ();
2019 }
2020
2021 return priv->constraint_solver;
2022}
2023
2024static GtkWidget *
2025gtk_window_root_get_focus (GtkRoot *root)
2026{
2027 GtkWindow *self = GTK_WINDOW (root);
2028 GtkWindowPrivate *priv = gtk_window_get_instance_private (self);
2029
2030 return priv->focus_widget;
2031}
2032
2033static void synthesize_focus_change_events (GtkWindow *window,
2034 GtkWidget *old_focus,
2035 GtkWidget *new_focus,
2036 GtkCrossingType type);
2037
2038static void
2039gtk_window_root_set_focus (GtkRoot *root,
2040 GtkWidget *focus)
2041{
2042 GtkWindow *self = GTK_WINDOW (root);
2043 GtkWindowPrivate *priv = gtk_window_get_instance_private (self);
2044 GtkWidget *old_focus = NULL;
2045
2046 if (focus && !gtk_widget_is_sensitive (widget: focus))
2047 return;
2048
2049 if (focus == priv->focus_widget)
2050 {
2051 if (priv->move_focus &&
2052 focus && gtk_widget_is_visible (widget: focus))
2053 {
2054 priv->move_focus = FALSE;
2055 g_clear_object (&priv->move_focus_widget);
2056 }
2057 return;
2058 }
2059
2060 if (priv->focus_widget)
2061 old_focus = g_object_ref (priv->focus_widget);
2062 g_set_object (&priv->focus_widget, NULL);
2063
2064 if (old_focus)
2065 gtk_widget_set_has_focus (widget: old_focus, FALSE);
2066
2067 synthesize_focus_change_events (window: self, old_focus, new_focus: focus, type: GTK_CROSSING_FOCUS);
2068
2069 if (focus)
2070 gtk_widget_set_has_focus (widget: focus, TRUE);
2071
2072 g_set_object (&priv->focus_widget, focus);
2073
2074 g_clear_object (&old_focus);
2075
2076 if (priv->move_focus &&
2077 focus && gtk_widget_is_visible (widget: focus))
2078 {
2079 priv->move_focus = FALSE;
2080 g_clear_object (&priv->move_focus_widget);
2081 }
2082
2083 g_object_notify (G_OBJECT (self), property_name: "focus-widget");
2084}
2085
2086static void
2087gtk_window_native_get_surface_transform (GtkNative *native,
2088 double *x,
2089 double *y)
2090{
2091 GtkBorder shadow;
2092 GtkCssBoxes css_boxes;
2093 const graphene_rect_t *margin_rect;
2094
2095 get_shadow_width (GTK_WINDOW (native), shadow_width: &shadow);
2096 gtk_css_boxes_init (boxes: &css_boxes, GTK_WIDGET (native));
2097 margin_rect = gtk_css_boxes_get_margin_rect (boxes: &css_boxes);
2098
2099 *x = shadow.left - margin_rect->origin.x;
2100 *y = shadow.top - margin_rect->origin.y;
2101}
2102
2103static void
2104gtk_window_native_layout (GtkNative *native,
2105 int width,
2106 int height)
2107{
2108 GtkWindow *window = GTK_WINDOW (native);
2109 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
2110 GtkWidget *widget = GTK_WIDGET (native);
2111
2112 if (priv->surface_width != width || priv->surface_height != height)
2113 {
2114 surface_size_changed (widget, width, height);
2115 priv->surface_width = width;
2116 priv->surface_height = height;
2117 }
2118
2119 /* This fake motion event is needed for getting up to date pointer focus
2120 * and coordinates when tho pointer didn't move but the layout changed
2121 * within the window.
2122 */
2123 if (gtk_widget_needs_allocate (widget))
2124 {
2125 GdkSeat *seat;
2126
2127 seat = gdk_display_get_default_seat (display: gtk_widget_get_display (widget));
2128 if (seat)
2129 {
2130 GdkDevice *device;
2131 GtkWidget *focus;
2132
2133 device = gdk_seat_get_pointer (seat);
2134 focus = gtk_window_lookup_pointer_focus_widget (GTK_WINDOW (widget),
2135 device, NULL);
2136 if (focus)
2137 {
2138 GdkSurface *focus_surface =
2139 gtk_native_get_surface (self: gtk_widget_get_native (widget: focus));
2140
2141 gdk_surface_request_motion (surface: focus_surface);
2142 }
2143 }
2144 }
2145
2146 if (gtk_widget_needs_allocate (widget))
2147 {
2148 gtk_window_update_csd_size (window,
2149 width: &width, height: &height,
2150 EXCLUDE_CSD_SIZE);
2151 gtk_widget_allocate (widget, width, height, baseline: -1, NULL);
2152 }
2153 else
2154 {
2155 gtk_widget_ensure_allocate (widget);
2156 }
2157}
2158
2159static void
2160gtk_window_root_interface_init (GtkRootInterface *iface)
2161{
2162 iface->get_display = gtk_window_root_get_display;
2163 iface->get_constraint_solver = gtk_window_root_get_constraint_solver;
2164 iface->get_focus = gtk_window_root_get_focus;
2165 iface->set_focus = gtk_window_root_set_focus;
2166}
2167
2168static void
2169gtk_window_native_interface_init (GtkNativeInterface *iface)
2170{
2171 iface->get_surface = gtk_window_native_get_surface;
2172 iface->get_renderer = gtk_window_native_get_renderer;
2173 iface->get_surface_transform = gtk_window_native_get_surface_transform;
2174 iface->layout = gtk_window_native_layout;
2175}
2176
2177/**
2178 * gtk_window_new:
2179 *
2180 * Creates a new `GtkWindow`.
2181 *
2182 * To get an undecorated window (no window borders), use
2183 * [method@Gtk.Window.set_decorated].
2184 *
2185 * All top-level windows created by gtk_window_new() are stored
2186 * in an internal top-level window list. This list can be obtained
2187 * from [func@Gtk.Window.list_toplevels]. Due to GTK keeping a
2188 * reference to the window internally, gtk_window_new() does not
2189 * return a reference to the caller.
2190 *
2191 * To delete a `GtkWindow`, call [method@Gtk.Window.destroy].
2192 *
2193 * Returns: a new `GtkWindow`.
2194 */
2195GtkWidget*
2196gtk_window_new (void)
2197{
2198 return g_object_new (GTK_TYPE_WINDOW, NULL);
2199}
2200
2201/**
2202 * gtk_window_set_title: (attributes org.gtk.Method.set_property=title)
2203 * @window: a `GtkWindow`
2204 * @title: (nullable): title of the window
2205 *
2206 * Sets the title of the `GtkWindow`.
2207 *
2208 * The title of a window will be displayed in its title bar; on the
2209 * X Window System, the title bar is rendered by the window manager
2210 * so exactly how the title appears to users may vary according to a
2211 * user’s exact configuration. The title should help a user distinguish
2212 * this window from other windows they may have open. A good title might
2213 * include the application name and current document filename, for example.
2214 *
2215 * Passing %NULL does the same as setting the title to an empty string.
2216 */
2217void
2218gtk_window_set_title (GtkWindow *window,
2219 const char *title)
2220{
2221 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
2222 char *new_title;
2223
2224 g_return_if_fail (GTK_IS_WINDOW (window));
2225
2226 new_title = g_strdup (str: title);
2227 g_free (mem: priv->title);
2228 priv->title = new_title;
2229
2230 if (_gtk_widget_get_realized (GTK_WIDGET (window)))
2231 gdk_toplevel_set_title (toplevel: GDK_TOPLEVEL (ptr: priv->surface), title: new_title != NULL ? new_title : "");
2232
2233 gtk_accessible_update_property (self: GTK_ACCESSIBLE (ptr: window),
2234 first_property: GTK_ACCESSIBLE_PROPERTY_LABEL, priv->title,
2235 -1);
2236
2237 g_object_notify_by_pspec (G_OBJECT (window), pspec: window_props[PROP_TITLE]);
2238}
2239
2240/**
2241 * gtk_window_get_title: (attributes org.gtk.Method.get_property=title)
2242 * @window: a `GtkWindow`
2243 *
2244 * Retrieves the title of the window.
2245 *
2246 * Returns: (nullable): the title of the window
2247 */
2248const char *
2249gtk_window_get_title (GtkWindow *window)
2250{
2251 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
2252
2253 g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
2254
2255 return priv->title;
2256}
2257
2258/**
2259 * gtk_window_set_startup_id: (attributes org.gtk.Method.set_property=startup-id)
2260 * @window: a `GtkWindow`
2261 * @startup_id: a string with startup-notification identifier
2262 *
2263 * Sets the startup notification ID.
2264 *
2265 * Startup notification identifiers are used by desktop environment
2266 * to track application startup, to provide user feedback and other
2267 * features. This function changes the corresponding property on the
2268 * underlying `GdkSurface`.
2269 *
2270 * Normally, startup identifier is managed automatically and you should
2271 * only use this function in special cases like transferring focus from
2272 * other processes. You should use this function before calling
2273 * [method@Gtk.Window.present] or any equivalent function generating
2274 * a window map event.
2275 *
2276 * This function is only useful on X11, not with other GTK targets.
2277 */
2278void
2279gtk_window_set_startup_id (GtkWindow *window,
2280 const char *startup_id)
2281{
2282 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
2283 GtkWidget *widget;
2284
2285 g_return_if_fail (GTK_IS_WINDOW (window));
2286
2287 widget = GTK_WIDGET (window);
2288
2289 g_free (mem: priv->startup_id);
2290 priv->startup_id = g_strdup (str: startup_id);
2291
2292 if (_gtk_widget_get_realized (widget))
2293 {
2294 guint32 timestamp = extract_time_from_startup_id (startup_id: priv->startup_id);
2295
2296#ifdef GDK_WINDOWING_X11
2297 if (timestamp != GDK_CURRENT_TIME && GDK_IS_X11_SURFACE (priv->surface))
2298 gdk_x11_surface_set_user_time (surface: priv->surface, timestamp);
2299#endif
2300
2301 /* Here we differentiate real and "fake" startup notification IDs,
2302 * constructed on purpose just to pass interaction timestamp
2303 */
2304 if (startup_id_is_fake (startup_id: priv->startup_id))
2305 gtk_window_present_with_time (window, timestamp);
2306 else
2307 {
2308 gdk_toplevel_set_startup_id (toplevel: GDK_TOPLEVEL (ptr: priv->surface), startup_id: priv->startup_id);
2309
2310 /* If window is mapped, terminate the startup-notification too */
2311 if (_gtk_widget_get_mapped (widget) && !disable_startup_notification)
2312 gdk_display_notify_startup_complete (display: gtk_widget_get_display (widget), startup_id: priv->startup_id);
2313 }
2314 }
2315
2316 g_object_notify_by_pspec (G_OBJECT (window), pspec: window_props[PROP_STARTUP_ID]);
2317}
2318
2319/**
2320 * gtk_window_set_default_widget: (attributes org.gtk.Property.set=default-widget)
2321 * @window: a `GtkWindow`
2322 * @default_widget: (nullable): widget to be the default
2323 * to unset the default widget for the toplevel
2324 *
2325 * Sets the default widget.
2326 *
2327 * The default widget is the widget that is activated when the user
2328 * presses Enter in a dialog (for example).
2329 */
2330void
2331gtk_window_set_default_widget (GtkWindow *window,
2332 GtkWidget *default_widget)
2333{
2334 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
2335
2336 g_return_if_fail (GTK_IS_WINDOW (window));
2337
2338 if (priv->default_widget != default_widget)
2339 {
2340 GtkWidget *old_default_widget = NULL;
2341
2342 if (default_widget)
2343 g_object_ref (default_widget);
2344
2345 if (priv->default_widget)
2346 {
2347 old_default_widget = priv->default_widget;
2348
2349 if (priv->focus_widget != priv->default_widget ||
2350 !gtk_widget_get_receives_default (widget: priv->default_widget))
2351 _gtk_widget_set_has_default (widget: priv->default_widget, FALSE);
2352
2353 gtk_widget_queue_draw (widget: priv->default_widget);
2354 }
2355
2356 priv->default_widget = default_widget;
2357
2358 priv->unset_default = FALSE;
2359
2360 if (priv->default_widget)
2361 {
2362 if (priv->focus_widget == NULL ||
2363 !gtk_widget_get_receives_default (widget: priv->focus_widget))
2364 _gtk_widget_set_has_default (widget: priv->default_widget, TRUE);
2365
2366 gtk_widget_queue_draw (widget: priv->default_widget);
2367 }
2368
2369 if (old_default_widget)
2370 g_object_notify (G_OBJECT (old_default_widget), property_name: "has-default");
2371
2372 if (default_widget)
2373 {
2374 g_object_notify (G_OBJECT (default_widget), property_name: "has-default");
2375 g_object_unref (object: default_widget);
2376 }
2377
2378 g_object_notify_by_pspec (G_OBJECT (window), pspec: window_props[PROP_DEFAULT_WIDGET]);
2379 }
2380}
2381
2382/**
2383 * gtk_window_get_default_widget: (attributes org.gtk.Property.get=default-widget)
2384 * @window: a `GtkWindow`
2385 *
2386 * Returns the default widget for @window.
2387 *
2388 * Returns: (nullable) (transfer none): the default widget
2389 */
2390GtkWidget *
2391gtk_window_get_default_widget (GtkWindow *window)
2392{
2393 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
2394
2395 g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
2396
2397 return priv->default_widget;
2398}
2399
2400static gboolean
2401handle_keys_changed (gpointer data)
2402{
2403 GtkWindow *window = GTK_WINDOW (data);
2404 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
2405
2406 if (priv->keys_changed_handler)
2407 {
2408 g_source_remove (tag: priv->keys_changed_handler);
2409 priv->keys_changed_handler = 0;
2410 }
2411
2412 if (priv->application_shortcut_controller)
2413 gtk_shortcut_controller_update_accels (GTK_SHORTCUT_CONTROLLER (priv->application_shortcut_controller));
2414 g_signal_emit (instance: window, signal_id: window_signals[KEYS_CHANGED], detail: 0);
2415
2416 return FALSE;
2417}
2418
2419void
2420_gtk_window_notify_keys_changed (GtkWindow *window)
2421{
2422 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
2423
2424 if (!priv->keys_changed_handler)
2425 {
2426 priv->keys_changed_handler = g_idle_add (function: handle_keys_changed, data: window);
2427 gdk_source_set_static_name_by_id (tag: priv->keys_changed_handler, name: "[gtk] handle_keys_changed");
2428 }
2429}
2430
2431/**
2432 * gtk_window_get_focus: (attributes org.gtk.Property.get=focus-widget)
2433 * @window: a `GtkWindow`
2434 *
2435 * Retrieves the current focused widget within the window.
2436 *
2437 * Note that this is the widget that would have the focus
2438 * if the toplevel window focused; if the toplevel window
2439 * is not focused then `gtk_widget_has_focus (widget)` will
2440 * not be %TRUE for the widget.
2441 *
2442 * Returns: (nullable) (transfer none): the currently focused widget
2443 */
2444GtkWidget *
2445gtk_window_get_focus (GtkWindow *window)
2446{
2447 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
2448
2449 g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
2450
2451 return priv->focus_widget;
2452}
2453
2454static void
2455gtk_window_real_activate_default (GtkWindow *window)
2456{
2457 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
2458
2459 if (priv->default_widget && gtk_widget_is_sensitive (widget: priv->default_widget) &&
2460 (!priv->focus_widget || !gtk_widget_get_receives_default (widget: priv->focus_widget)))
2461 gtk_widget_activate (widget: priv->default_widget);
2462 else if (priv->focus_widget && gtk_widget_is_sensitive (widget: priv->focus_widget))
2463 gtk_widget_activate (widget: priv->focus_widget);
2464}
2465
2466/**
2467 * gtk_window_set_modal: (attributes org.gtk.Method.set_property=modal)
2468 * @window: a `GtkWindow`
2469 * @modal: whether the window is modal
2470 *
2471 * Sets a window modal or non-modal.
2472 *
2473 * Modal windows prevent interaction with other windows in the same
2474 * application. To keep modal dialogs on top of main application windows,
2475 * use [method@Gtk.Window.set_transient_for] to make the dialog transient
2476 * for the parent; most window managers will then disallow lowering the
2477 * dialog below the parent.
2478 */
2479void
2480gtk_window_set_modal (GtkWindow *window,
2481 gboolean modal)
2482{
2483 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
2484 GtkWidget *widget;
2485
2486 g_return_if_fail (GTK_IS_WINDOW (window));
2487
2488 modal = modal != FALSE;
2489 if (priv->modal == modal)
2490 return;
2491
2492 priv->modal = modal;
2493 widget = GTK_WIDGET (window);
2494
2495 if (_gtk_widget_get_realized (widget))
2496 gdk_toplevel_set_modal (toplevel: GDK_TOPLEVEL (ptr: priv->surface), modal);
2497
2498 if (gtk_widget_get_visible (widget))
2499 {
2500 if (priv->modal)
2501 gtk_grab_add (widget);
2502 else
2503 gtk_grab_remove (widget);
2504 }
2505
2506 update_window_actions (window);
2507
2508 gtk_accessible_update_property (self: GTK_ACCESSIBLE (ptr: window),
2509 first_property: GTK_ACCESSIBLE_PROPERTY_MODAL, modal,
2510 -1);
2511
2512 g_object_notify_by_pspec (G_OBJECT (window), pspec: window_props[PROP_MODAL]);
2513}
2514
2515/**
2516 * gtk_window_get_modal: (attributes org.gtk.Method.get_property=modal)
2517 * @window: a `GtkWindow`
2518 *
2519 * Returns whether the window is modal.
2520 *
2521 * Returns: %TRUE if the window is set to be modal and
2522 * establishes a grab when shown
2523 */
2524gboolean
2525gtk_window_get_modal (GtkWindow *window)
2526{
2527 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
2528
2529 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
2530
2531 return priv->modal;
2532}
2533
2534/**
2535 * gtk_window_get_toplevels:
2536 *
2537 * Returns a list of all existing toplevel windows.
2538 *
2539 * If you want to iterate through the list and perform actions involving
2540 * callbacks that might destroy the widgets or add new ones, be aware that
2541 * the list of toplevels will change and emit the "items-changed" signal.
2542 *
2543 * Returns: (transfer none) (attributes element-type=GtkWindow): the list
2544 * of toplevel widgets
2545 */
2546GListModel *
2547gtk_window_get_toplevels (void)
2548{
2549 if (toplevel_list == NULL)
2550 toplevel_list = g_list_store_new (GTK_TYPE_WIDGET);
2551
2552 return G_LIST_MODEL (ptr: toplevel_list);
2553}
2554
2555/**
2556 * gtk_window_list_toplevels:
2557 *
2558 * Returns a list of all existing toplevel windows.
2559 *
2560 * The widgets in the list are not individually referenced.
2561 * If you want to iterate through the list and perform actions
2562 * involving callbacks that might destroy the widgets, you must
2563 * call `g_list_foreach (result, (GFunc)g_object_ref, NULL)` first,
2564 * and then unref all the widgets afterwards.
2565 *
2566 * Returns: (element-type GtkWidget) (transfer container): list of
2567 * toplevel widgets
2568 */
2569GList*
2570gtk_window_list_toplevels (void)
2571{
2572 GListModel *toplevels;
2573 GList *list = NULL;
2574 guint i;
2575
2576 toplevels = gtk_window_get_toplevels ();
2577
2578 for (i = 0; i < g_list_model_get_n_items (list: toplevels); i++)
2579 {
2580 gpointer item = g_list_model_get_item (list: toplevels, position: i);
2581 list = g_list_prepend (list, data: item);
2582 g_object_unref (object: item);
2583 }
2584
2585 return list;
2586}
2587
2588static void
2589gtk_window_dispose (GObject *object)
2590{
2591 GtkWindow *window = GTK_WINDOW (object);
2592 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
2593
2594 gtk_window_release_application (window);
2595
2596 if (priv->transient_parent)
2597 gtk_window_set_transient_for (window, NULL);
2598
2599 if (priv->group)
2600 gtk_window_group_remove_window (window_group: priv->group, window);
2601
2602 g_list_free_full (list: priv->foci, free_func: (GDestroyNotify) gtk_pointer_focus_unref);
2603 priv->foci = NULL;
2604
2605 g_clear_object (&priv->move_focus_widget);
2606 gtk_window_set_focus (window, NULL);
2607 gtk_window_set_default_widget (window, NULL);
2608
2609 g_clear_pointer (&priv->child, gtk_widget_unparent);
2610 unset_titlebar (window);
2611
2612 G_OBJECT_CLASS (gtk_window_parent_class)->dispose (object);
2613}
2614
2615static void
2616gtk_window_transient_parent_destroyed (GtkWindow *parent,
2617 GtkWindow *window)
2618{
2619 GtkWindowPrivate *priv = gtk_window_get_instance_private (GTK_WINDOW (window));
2620
2621 if (priv->destroy_with_parent)
2622 gtk_window_destroy (window);
2623 else
2624 priv->transient_parent = NULL;
2625}
2626
2627static void
2628gtk_window_transient_parent_realized (GtkWidget *parent,
2629 GtkWidget *window)
2630{
2631 GtkWindowPrivate *priv = gtk_window_get_instance_private (GTK_WINDOW (window));
2632 GtkWindowPrivate *parent_priv = gtk_window_get_instance_private (GTK_WINDOW (parent));
2633 if (_gtk_widget_get_realized (widget: window))
2634 gdk_toplevel_set_transient_for (toplevel: GDK_TOPLEVEL (ptr: priv->surface), parent: parent_priv->surface);
2635}
2636
2637static void
2638gtk_window_transient_parent_unrealized (GtkWidget *parent,
2639 GtkWidget *window)
2640{
2641 GtkWindowPrivate *priv = gtk_window_get_instance_private (GTK_WINDOW (window));
2642 if (_gtk_widget_get_realized (widget: window))
2643 gdk_toplevel_set_transient_for (toplevel: GDK_TOPLEVEL (ptr: priv->surface), NULL);
2644}
2645
2646static void
2647gtk_window_transient_parent_display_changed (GtkWindow *parent,
2648 GParamSpec *pspec,
2649 GtkWindow *window)
2650{
2651 GtkWindowPrivate *parent_priv = gtk_window_get_instance_private (self: parent);
2652
2653 gtk_window_set_display (window, display: parent_priv->display);
2654}
2655
2656static void
2657gtk_window_unset_transient_for (GtkWindow *window)
2658{
2659 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
2660
2661 if (priv->transient_parent)
2662 {
2663 g_signal_handlers_disconnect_by_func (priv->transient_parent,
2664 gtk_window_transient_parent_realized,
2665 window);
2666 g_signal_handlers_disconnect_by_func (priv->transient_parent,
2667 gtk_window_transient_parent_unrealized,
2668 window);
2669 g_signal_handlers_disconnect_by_func (priv->transient_parent,
2670 gtk_window_transient_parent_display_changed,
2671 window);
2672 g_signal_handlers_disconnect_by_func (priv->transient_parent,
2673 gtk_window_transient_parent_destroyed,
2674 window);
2675
2676 priv->transient_parent = NULL;
2677
2678 if (priv->transient_parent_group)
2679 {
2680 priv->transient_parent_group = FALSE;
2681 gtk_window_group_remove_window (window_group: priv->group, window);
2682 }
2683 }
2684}
2685
2686/**
2687 * gtk_window_set_transient_for: (attributes org.gtk.Method.set_property=transient-for)
2688 * @window: a `GtkWindow`
2689 * @parent: (nullable): parent window
2690 *
2691 * Dialog windows should be set transient for the main application
2692 * window they were spawned from. This allows window managers to e.g.
2693 * keep the dialog on top of the main window, or center the dialog
2694 * over the main window. [ctor@Gtk.Dialog.new_with_buttons] and other
2695 * convenience functions in GTK will sometimes call
2696 * gtk_window_set_transient_for() on your behalf.
2697 *
2698 * Passing %NULL for @parent unsets the current transient window.
2699 *
2700 * On Windows, this function puts the child window on top of the parent,
2701 * much as the window manager would have done on X.
2702 */
2703void
2704gtk_window_set_transient_for (GtkWindow *window,
2705 GtkWindow *parent)
2706{
2707 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
2708
2709 g_return_if_fail (GTK_IS_WINDOW (window));
2710 g_return_if_fail (parent == NULL || GTK_IS_WINDOW (parent));
2711 g_return_if_fail (window != parent);
2712
2713 if (priv->transient_parent)
2714 {
2715 if (_gtk_widget_get_realized (GTK_WIDGET (window)) &&
2716 _gtk_widget_get_realized (GTK_WIDGET (priv->transient_parent)) &&
2717 (!parent || !_gtk_widget_get_realized (GTK_WIDGET (parent))))
2718 gtk_window_transient_parent_unrealized (GTK_WIDGET (priv->transient_parent),
2719 GTK_WIDGET (window));
2720 gtk_window_unset_transient_for (window);
2721 }
2722
2723 priv->transient_parent = parent;
2724
2725 if (parent)
2726 {
2727 GtkWindowPrivate *parent_priv = gtk_window_get_instance_private (self: parent);
2728 g_signal_connect (parent, "realize",
2729 G_CALLBACK (gtk_window_transient_parent_realized), window);
2730 g_signal_connect (parent, "unrealize",
2731 G_CALLBACK (gtk_window_transient_parent_unrealized), window);
2732 g_signal_connect (parent, "notify::display",
2733 G_CALLBACK (gtk_window_transient_parent_display_changed), window);
2734 g_signal_connect (parent, "destroy",
2735 G_CALLBACK (gtk_window_transient_parent_destroyed), window);
2736
2737 gtk_window_set_display (window, display: parent_priv->display);
2738
2739
2740 if (_gtk_widget_get_realized (GTK_WIDGET (window)) &&
2741 _gtk_widget_get_realized (GTK_WIDGET (parent)))
2742 gtk_window_transient_parent_realized (GTK_WIDGET (parent), GTK_WIDGET (window));
2743
2744 if (parent_priv->group)
2745 {
2746 gtk_window_group_add_window (window_group: parent_priv->group, window);
2747 priv->transient_parent_group = TRUE;
2748 }
2749 }
2750
2751 update_window_actions (window);
2752
2753 g_object_notify_by_pspec (G_OBJECT (window), pspec: window_props[PROP_TRANSIENT_FOR]);
2754}
2755
2756/**
2757 * gtk_window_get_transient_for: (attributes org.gtk.Method.get_property=transient-for)
2758 * @window: a `GtkWindow`
2759 *
2760 * Fetches the transient parent for this window.
2761 *
2762 * Returns: (nullable) (transfer none): the transient parent for this window
2763 */
2764GtkWindow *
2765gtk_window_get_transient_for (GtkWindow *window)
2766{
2767 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
2768
2769 g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
2770
2771 return priv->transient_parent;
2772}
2773
2774/**
2775 * gtk_window_get_application: (attributes org.gtk.Method.get_property=application)
2776 * @window: a `GtkWindow`
2777 *
2778 * Gets the `GtkApplication` associated with the window.
2779 *
2780 * Returns: (nullable) (transfer none): a `GtkApplication`
2781 */
2782GtkApplication *
2783gtk_window_get_application (GtkWindow *window)
2784{
2785 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
2786
2787 g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
2788
2789 return priv->application;
2790}
2791
2792static void
2793gtk_window_release_application (GtkWindow *window)
2794{
2795 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
2796
2797 if (priv->application)
2798 {
2799 GtkApplication *application;
2800
2801 /* steal reference into temp variable */
2802 application = priv->application;
2803 priv->application = NULL;
2804 gtk_widget_remove_controller (GTK_WIDGET (window),
2805 controller: priv->application_shortcut_controller);
2806 priv->application_shortcut_controller = NULL;
2807
2808 gtk_application_remove_window (application, window);
2809 g_object_unref (object: application);
2810 }
2811}
2812
2813/**
2814 * gtk_window_set_application: (attributes org.gtk.Method.set_property=application)
2815 * @window: a `GtkWindow`
2816 * @application: (nullable): a `GtkApplication`, or %NULL to unset
2817 *
2818 * Sets or unsets the `GtkApplication` associated with the window.
2819 *
2820 * The application will be kept alive for at least as long as it has
2821 * any windows associated with it (see g_application_hold() for a way
2822 * to keep it alive without windows).
2823 *
2824 * Normally, the connection between the application and the window will
2825 * remain until the window is destroyed, but you can explicitly remove
2826 * it by setting the @application to %NULL.
2827 *
2828 * This is equivalent to calling [method@Gtk.Application.remove_window]
2829 * and/or [method@Gtk.Application.add_window] on the old/new applications
2830 * as relevant.
2831 */
2832void
2833gtk_window_set_application (GtkWindow *window,
2834 GtkApplication *application)
2835{
2836 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
2837
2838 g_return_if_fail (GTK_IS_WINDOW (window));
2839
2840 if (priv->application != application)
2841 {
2842 gtk_window_release_application (window);
2843
2844 priv->application = application;
2845
2846 if (priv->application != NULL)
2847 {
2848 GtkApplicationAccels *app_accels;
2849
2850 g_object_ref (priv->application);
2851
2852 gtk_application_add_window (application: priv->application, window);
2853
2854 app_accels = gtk_application_get_application_accels (application: priv->application);
2855 priv->application_shortcut_controller = gtk_shortcut_controller_new_for_model (model: gtk_application_accels_get_shortcuts (accels: app_accels));
2856 gtk_event_controller_set_name (controller: priv->application_shortcut_controller, name: "gtk-application-shortcuts");
2857 gtk_event_controller_set_propagation_phase (controller: priv->application_shortcut_controller, phase: GTK_PHASE_CAPTURE);
2858 gtk_shortcut_controller_set_scope (GTK_SHORTCUT_CONTROLLER (priv->application_shortcut_controller), scope: GTK_SHORTCUT_SCOPE_GLOBAL);
2859 gtk_widget_add_controller (GTK_WIDGET (window), controller: priv->application_shortcut_controller);
2860 }
2861
2862 _gtk_widget_update_parent_muxer (GTK_WIDGET (window));
2863
2864 _gtk_window_notify_keys_changed (window);
2865
2866 g_object_notify_by_pspec (G_OBJECT (window), pspec: window_props[PROP_APPLICATION]);
2867 }
2868}
2869
2870/**
2871 * gtk_window_set_destroy_with_parent: (attributes org.gtk.Method.set_property=destroy-with-parent)
2872 * @window: a `GtkWindow`
2873 * @setting: whether to destroy @window with its transient parent
2874 *
2875 * If @setting is %TRUE, then destroying the transient parent of @window
2876 * will also destroy @window itself.
2877 *
2878 * This is useful for dialogs that shouldn’t persist beyond the lifetime
2879 * of the main window they are associated with, for example.
2880 */
2881void
2882gtk_window_set_destroy_with_parent (GtkWindow *window,
2883 gboolean setting)
2884{
2885 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
2886
2887 g_return_if_fail (GTK_IS_WINDOW (window));
2888
2889 if (priv->destroy_with_parent == (setting != FALSE))
2890 return;
2891
2892 priv->destroy_with_parent = setting;
2893
2894 g_object_notify_by_pspec (G_OBJECT (window), pspec: window_props[PROP_DESTROY_WITH_PARENT]);
2895}
2896
2897/**
2898 * gtk_window_get_destroy_with_parent: (attributes org.gtk.Method.get_property=destroy-with-parent)
2899 * @window: a `GtkWindow`
2900 *
2901 * Returns whether the window will be destroyed with its transient parent.
2902 *
2903 * Returns: %TRUE if the window will be destroyed with its transient parent.
2904 */
2905gboolean
2906gtk_window_get_destroy_with_parent (GtkWindow *window)
2907{
2908 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
2909
2910 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
2911
2912 return priv->destroy_with_parent;
2913}
2914
2915/**
2916 * gtk_window_set_hide_on_close: (attributes org.gtk.Method.set_property=hide-on-close)
2917 * @window: a `GtkWindow`
2918 * @setting: whether to hide the window when it is closed
2919 *
2920 * If @setting is %TRUE, then clicking the close button on the window
2921 * will not destroy it, but only hide it.
2922 */
2923void
2924gtk_window_set_hide_on_close (GtkWindow *window,
2925 gboolean setting)
2926{
2927 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
2928
2929 g_return_if_fail (GTK_IS_WINDOW (window));
2930
2931 if (priv->hide_on_close == setting)
2932 return;
2933
2934 priv->hide_on_close = setting;
2935
2936 g_object_notify_by_pspec (G_OBJECT (window), pspec: window_props[PROP_HIDE_ON_CLOSE]);
2937}
2938
2939/**
2940 * gtk_window_get_hide_on_close: (attributes org.gtk.Method.get_property=hide-on-close)
2941 * @window: a `GtkWindow`
2942 *
2943 * Returns whether the window will be hidden when the close button is clicked.
2944 *
2945 * Returns: %TRUE if the window will be hidden
2946 */
2947gboolean
2948gtk_window_get_hide_on_close (GtkWindow *window)
2949{
2950 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
2951
2952 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
2953
2954 return priv->hide_on_close;
2955}
2956
2957static GtkWindowGeometryInfo*
2958gtk_window_get_geometry_info (GtkWindow *window,
2959 gboolean create)
2960{
2961 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
2962 GtkWindowGeometryInfo *info;
2963
2964 info = priv->geometry_info;
2965 if (!info && create)
2966 {
2967 info = g_new0 (GtkWindowGeometryInfo, 1);
2968
2969 info->last.configure_request.x = 0;
2970 info->last.configure_request.y = 0;
2971 info->last.configure_request.width = -1;
2972 info->last.configure_request.height = -1;
2973 priv->geometry_info = info;
2974 }
2975
2976 return info;
2977}
2978
2979static void
2980unset_titlebar (GtkWindow *window)
2981{
2982 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
2983
2984 if (priv->title_box != NULL)
2985 {
2986 gtk_widget_unparent (widget: priv->title_box);
2987 priv->title_box = NULL;
2988 priv->titlebar = NULL;
2989 }
2990}
2991
2992static gboolean
2993gtk_window_supports_client_shadow (GtkWindow *window)
2994{
2995 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
2996 GdkDisplay *display;
2997
2998 display = priv->display;
2999
3000 if (!gdk_display_is_rgba (display))
3001 return FALSE;
3002
3003 if (!gdk_display_is_composited (display))
3004 return FALSE;
3005
3006#ifdef GDK_WINDOWING_X11
3007 if (GDK_IS_X11_DISPLAY (display))
3008 {
3009 if (!gdk_x11_screen_supports_net_wm_hint (screen: gdk_x11_display_get_screen (display),
3010 property_name: g_intern_static_string (string: "_GTK_FRAME_EXTENTS")))
3011 return FALSE;
3012 }
3013#endif
3014
3015 return TRUE;
3016}
3017
3018static void
3019gtk_window_enable_csd (GtkWindow *window)
3020{
3021 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
3022 GtkWidget *widget = GTK_WIDGET (window);
3023
3024 /* We need a visual with alpha for client shadows */
3025 if (priv->use_client_shadow)
3026 gtk_widget_add_css_class (widget, css_class: "csd");
3027 else
3028 gtk_widget_add_css_class (widget, css_class: "solid-csd");
3029
3030 priv->client_decorated = TRUE;
3031}
3032
3033/**
3034 * gtk_window_set_titlebar: (attributes org.gtk.Method.set_property=titlebar)
3035 * @window: a `GtkWindow`
3036 * @titlebar: (nullable): the widget to use as titlebar
3037 *
3038 * Sets a custom titlebar for @window.
3039 *
3040 * A typical widget used here is [class@Gtk.HeaderBar], as it
3041 * provides various features expected of a titlebar while allowing
3042 * the addition of child widgets to it.
3043 *
3044 * If you set a custom titlebar, GTK will do its best to convince
3045 * the window manager not to put its own titlebar on the window.
3046 * Depending on the system, this function may not work for a window
3047 * that is already visible, so you set the titlebar before calling
3048 * [method@Gtk.Widget.show].
3049 */
3050void
3051gtk_window_set_titlebar (GtkWindow *window,
3052 GtkWidget *titlebar)
3053{
3054 GtkWidget *widget = GTK_WIDGET (window);
3055 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
3056 gboolean was_mapped;
3057
3058 g_return_if_fail (GTK_IS_WINDOW (window));
3059
3060 if (priv->titlebar == titlebar)
3061 return;
3062
3063 if ((!priv->title_box && titlebar) || (priv->title_box && !titlebar))
3064 {
3065 was_mapped = _gtk_widget_get_mapped (widget);
3066 if (_gtk_widget_get_realized (widget))
3067 {
3068 g_warning ("gtk_window_set_titlebar() called on a realized window");
3069 gtk_widget_unrealize (widget);
3070 }
3071 }
3072 else
3073 was_mapped = FALSE;
3074
3075 unset_titlebar (window);
3076
3077 if (titlebar == NULL)
3078 {
3079 /* these are updated in realize() */
3080 priv->client_decorated = FALSE;
3081 gtk_widget_remove_css_class (widget, css_class: "csd");
3082 gtk_widget_remove_css_class (widget, css_class: "solid-csd");
3083 }
3084 else
3085 {
3086 priv->use_client_shadow = gtk_window_supports_client_shadow (window);
3087
3088 gtk_window_enable_csd (window);
3089 priv->titlebar = titlebar;
3090 priv->title_box = titlebar;
3091 gtk_widget_insert_before (widget: priv->title_box, parent: widget, NULL);
3092
3093 gtk_widget_add_css_class (widget: titlebar, css_class: "titlebar");
3094 }
3095
3096 if (was_mapped)
3097 gtk_widget_map (widget);
3098
3099 g_object_notify_by_pspec (G_OBJECT (window), pspec: window_props[PROP_TITLEBAR]);
3100}
3101
3102/**
3103 * gtk_window_get_titlebar: (attributes org.gtk.Method.get_property=titlebar)
3104 * @window: a `GtkWindow`
3105 *
3106 * Returns the custom titlebar that has been set with
3107 * gtk_window_set_titlebar().
3108 *
3109 * Returns: (nullable) (transfer none): the custom titlebar
3110 */
3111GtkWidget *
3112gtk_window_get_titlebar (GtkWindow *window)
3113{
3114 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
3115
3116 g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
3117
3118 return priv->titlebar;
3119}
3120
3121/**
3122 * gtk_window_set_decorated: (attributes org.gtk.Method.set_property=decorated)
3123 * @window: a `GtkWindow`
3124 * @setting: %TRUE to decorate the window
3125 *
3126 * Sets whether the window should be decorated.
3127 *
3128 * By default, windows are decorated with a title bar, resize
3129 * controls, etc. Some window managers allow GTK to disable these
3130 * decorations, creating a borderless window. If you set the decorated
3131 * property to %FALSE using this function, GTK will do its best to
3132 * convince the window manager not to decorate the window. Depending on
3133 * the system, this function may not have any effect when called on a
3134 * window that is already visible, so you should call it before calling
3135 * [method@Gtk.Widget.show].
3136 *
3137 * On Windows, this function always works, since there’s no window manager
3138 * policy involved.
3139 */
3140void
3141gtk_window_set_decorated (GtkWindow *window,
3142 gboolean setting)
3143{
3144 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
3145
3146 g_return_if_fail (GTK_IS_WINDOW (window));
3147
3148 setting = setting != FALSE;
3149
3150 if (setting == priv->decorated)
3151 return;
3152
3153 priv->decorated = setting;
3154
3155 if (priv->surface)
3156 gdk_toplevel_set_decorated (toplevel: GDK_TOPLEVEL (ptr: priv->surface), decorated: priv->decorated && !priv->client_decorated);
3157
3158 update_window_actions (window);
3159 gtk_widget_queue_resize (GTK_WIDGET (window));
3160
3161 g_object_notify_by_pspec (G_OBJECT (window), pspec: window_props[PROP_DECORATED]);
3162}
3163
3164/**
3165 * gtk_window_get_decorated: (attributes org.gtk.Method.get_property=decorated)
3166 * @window: a `GtkWindow`
3167 *
3168 * Returns whether the window has been set to have decorations.
3169 *
3170 * Returns: %TRUE if the window has been set to have decorations
3171 */
3172gboolean
3173gtk_window_get_decorated (GtkWindow *window)
3174{
3175 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
3176
3177 g_return_val_if_fail (GTK_IS_WINDOW (window), TRUE);
3178
3179 return priv->decorated;
3180}
3181
3182/**
3183 * gtk_window_set_deletable: (attributes org.gtk.Method.set_property=deletable)
3184 * @window: a `GtkWindow`
3185 * @setting: %TRUE to decorate the window as deletable
3186 *
3187 * Sets whether the window should be deletable.
3188 *
3189 * By default, windows have a close button in the window frame.
3190 * Some window managers allow GTK to disable this button. If you
3191 * set the deletable property to %FALSE using this function, GTK
3192 * will do its best to convince the window manager not to show a
3193 * close button. Depending on the system, this function may not
3194 * have any effect when called on a window that is already visible,
3195 * so you should call it before calling [method@Gtk.Widget.show].
3196 *
3197 * On Windows, this function always works, since there’s no window
3198 * manager policy involved.
3199 */
3200void
3201gtk_window_set_deletable (GtkWindow *window,
3202 gboolean setting)
3203{
3204 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
3205
3206 g_return_if_fail (GTK_IS_WINDOW (window));
3207
3208 setting = setting != FALSE;
3209
3210 if (setting == priv->deletable)
3211 return;
3212
3213 priv->deletable = setting;
3214
3215 if (priv->surface)
3216 gdk_toplevel_set_deletable (toplevel: GDK_TOPLEVEL (ptr: priv->surface), deletable: priv->deletable);
3217
3218 update_window_actions (window);
3219
3220 g_object_notify_by_pspec (G_OBJECT (window), pspec: window_props[PROP_DELETABLE]);
3221}
3222
3223/**
3224 * gtk_window_get_deletable: (attributes org.gtk.Method.get_property=deletable)
3225 * @window: a `GtkWindow`
3226 *
3227 * Returns whether the window has been set to have a close button.
3228 *
3229 * Returns: %TRUE if the window has been set to have a close button
3230 */
3231gboolean
3232gtk_window_get_deletable (GtkWindow *window)
3233{
3234 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
3235
3236 g_return_val_if_fail (GTK_IS_WINDOW (window), TRUE);
3237
3238 return priv->deletable;
3239}
3240
3241static GtkWindowIconInfo*
3242get_icon_info (GtkWindow *window)
3243{
3244 return g_object_get_qdata (G_OBJECT (window), quark: quark_gtk_window_icon_info);
3245}
3246
3247static void
3248free_icon_info (GtkWindowIconInfo *info)
3249{
3250 g_free (mem: info->icon_name);
3251 g_slice_free (GtkWindowIconInfo, info);
3252}
3253
3254
3255static GtkWindowIconInfo*
3256ensure_icon_info (GtkWindow *window)
3257{
3258 GtkWindowIconInfo *info;
3259
3260 info = get_icon_info (window);
3261
3262 if (info == NULL)
3263 {
3264 info = g_slice_new0 (GtkWindowIconInfo);
3265 g_object_set_qdata_full (G_OBJECT (window),
3266 quark: quark_gtk_window_icon_info,
3267 data: info,
3268 destroy: (GDestroyNotify)free_icon_info);
3269 }
3270
3271 return info;
3272}
3273
3274static int
3275icon_size_compare (GdkTexture *a,
3276 GdkTexture *b)
3277{
3278 int area_a, area_b;
3279
3280 area_a = gdk_texture_get_width (texture: a) * gdk_texture_get_height (texture: a);
3281 area_b = gdk_texture_get_width (texture: b) * gdk_texture_get_height (texture: b);
3282
3283 return area_a - area_b;
3284}
3285
3286static GdkTexture *
3287render_paintable_to_texture (GdkPaintable *paintable)
3288{
3289 GtkSnapshot *snapshot;
3290 GskRenderNode *node;
3291 int width, height;
3292 cairo_surface_t *surface;
3293 cairo_t *cr;
3294 GdkTexture *texture;
3295
3296 width = gdk_paintable_get_intrinsic_width (paintable);
3297 height = gdk_paintable_get_intrinsic_height (paintable);
3298
3299 surface = cairo_image_surface_create (format: CAIRO_FORMAT_ARGB32, width, height);
3300
3301 snapshot = gtk_snapshot_new ();
3302 gdk_paintable_snapshot (paintable, snapshot, width, height);
3303 node = gtk_snapshot_free_to_node (snapshot);
3304
3305 cr = cairo_create (target: surface);
3306 gsk_render_node_draw (node, cr);
3307 cairo_destroy (cr);
3308
3309 gsk_render_node_unref (node);
3310
3311 texture = gdk_texture_new_for_surface (surface);
3312 cairo_surface_destroy (surface);
3313
3314 return texture;
3315}
3316
3317static GList *
3318icon_list_from_theme (GtkWindow *window,
3319 const char *name)
3320{
3321 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
3322 GList *list;
3323 GtkIconTheme *icon_theme;
3324 GtkIconPaintable *info;
3325 GdkTexture *texture;
3326 int *sizes;
3327 int i;
3328
3329 icon_theme = gtk_icon_theme_get_for_display (display: priv->display);
3330
3331 sizes = gtk_icon_theme_get_icon_sizes (self: icon_theme, icon_name: name);
3332
3333 list = NULL;
3334 for (i = 0; sizes[i]; i++)
3335 {
3336 /* FIXME
3337 * We need an EWMH extension to handle scalable icons
3338 * by passing their name to the WM. For now just use a
3339 * fixed size of 48.
3340 */
3341 if (sizes[i] == -1)
3342 info = gtk_icon_theme_lookup_icon (self: icon_theme, icon_name: name, NULL,
3343 size: 48, scale: priv->scale,
3344 direction: gtk_widget_get_direction (GTK_WIDGET (window)),
3345 flags: 0);
3346 else
3347 info = gtk_icon_theme_lookup_icon (self: icon_theme, icon_name: name, NULL,
3348 size: sizes[i], scale: priv->scale,
3349 direction: gtk_widget_get_direction (GTK_WIDGET (window)),
3350 flags: 0);
3351
3352 texture = render_paintable_to_texture (paintable: GDK_PAINTABLE (ptr: info));
3353 list = g_list_insert_sorted (list, data: texture, func: (GCompareFunc) icon_size_compare);
3354 g_object_unref (object: info);
3355 }
3356
3357 g_free (mem: sizes);
3358
3359 return list;
3360}
3361
3362static void
3363gtk_window_realize_icon (GtkWindow *window)
3364{
3365 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
3366 GtkWindowIconInfo *info;
3367 GList *icon_list = NULL;
3368
3369 g_return_if_fail (priv->surface != NULL);
3370
3371 info = ensure_icon_info (window);
3372
3373 if (info->realized)
3374 return;
3375
3376 info->using_default_icon = FALSE;
3377 info->using_themed_icon = FALSE;
3378
3379 /* Look up themed icon */
3380 if (icon_list == NULL && info->icon_name)
3381 {
3382 icon_list = icon_list_from_theme (window, name: info->icon_name);
3383 if (icon_list)
3384 info->using_themed_icon = TRUE;
3385 }
3386
3387 /* Look up themed icon */
3388 if (icon_list == NULL && default_icon_name)
3389 {
3390 icon_list = icon_list_from_theme (window, name: default_icon_name);
3391 info->using_default_icon = TRUE;
3392 info->using_themed_icon = TRUE;
3393 }
3394
3395 info->realized = TRUE;
3396
3397 gdk_toplevel_set_icon_list (toplevel: GDK_TOPLEVEL (ptr: priv->surface), surfaces: icon_list);
3398
3399 if (info->using_themed_icon)
3400 g_list_free_full (list: icon_list, free_func: g_object_unref);
3401}
3402
3403GdkPaintable *
3404gtk_window_get_icon_for_size (GtkWindow *window,
3405 int size)
3406{
3407 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
3408 const char *name;
3409 GtkIconPaintable *info;
3410
3411 name = gtk_window_get_icon_name (window);
3412
3413 if (!name)
3414 name = default_icon_name;
3415 if (!name)
3416 return NULL;
3417
3418 info = gtk_icon_theme_lookup_icon (self: gtk_icon_theme_get_for_display (display: gtk_widget_get_display (GTK_WIDGET (window))),
3419 icon_name: name, NULL, size, scale: priv->scale,
3420 direction: gtk_widget_get_direction (GTK_WIDGET (window)),
3421 flags: 0);
3422 if (info == NULL)
3423 return NULL;
3424
3425 return GDK_PAINTABLE (ptr: info);
3426}
3427
3428static void
3429gtk_window_unrealize_icon (GtkWindow *window)
3430{
3431 GtkWindowIconInfo *info;
3432
3433 info = get_icon_info (window);
3434
3435 if (info == NULL)
3436 return;
3437
3438 /* We don't clear the properties on the window, just figure the
3439 * window is going away.
3440 */
3441
3442 info->realized = FALSE;
3443
3444}
3445
3446static void
3447update_themed_icon (GtkWindow *window)
3448{
3449 g_object_notify_by_pspec (G_OBJECT (window), pspec: window_props[PROP_ICON_NAME]);
3450
3451 gtk_window_unrealize_icon (window);
3452
3453 if (_gtk_widget_get_realized (GTK_WIDGET (window)))
3454 gtk_window_realize_icon (window);
3455}
3456
3457/**
3458 * gtk_window_set_icon_name: (attributes org.gtk.Method.set_property=icon-name)
3459 * @window: a `GtkWindow`
3460 * @name: (nullable): the name of the themed icon
3461 *
3462 * Sets the icon for the window from a named themed icon.
3463 *
3464 * See the docs for [class@Gtk.IconTheme] for more details.
3465 * On some platforms, the window icon is not used at all.
3466 *
3467 * Note that this has nothing to do with the WM_ICON_NAME
3468 * property which is mentioned in the ICCCM.
3469 */
3470void
3471gtk_window_set_icon_name (GtkWindow *window,
3472 const char *name)
3473{
3474 GtkWindowIconInfo *info;
3475 char *tmp;
3476
3477 g_return_if_fail (GTK_IS_WINDOW (window));
3478
3479 info = ensure_icon_info (window);
3480
3481 if (g_strcmp0 (str1: info->icon_name, str2: name) == 0)
3482 return;
3483
3484 tmp = info->icon_name;
3485 info->icon_name = g_strdup (str: name);
3486 g_free (mem: tmp);
3487
3488 update_themed_icon (window);
3489
3490 g_object_notify_by_pspec (G_OBJECT (window), pspec: window_props[PROP_ICON_NAME]);
3491}
3492
3493/**
3494 * gtk_window_get_icon_name: (attributes org.gtk.Method.get_property=icon-name)
3495 * @window: a `GtkWindow`
3496 *
3497 * Returns the name of the themed icon for the window.
3498 *
3499 * Returns: (nullable): the icon name
3500 */
3501const char *
3502gtk_window_get_icon_name (GtkWindow *window)
3503{
3504 GtkWindowIconInfo *info;
3505
3506 g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
3507
3508 info = ensure_icon_info (window);
3509
3510 return info->icon_name;
3511}
3512
3513/**
3514 * gtk_window_set_default_icon_name:
3515 * @name: the name of the themed icon
3516 *
3517 * Sets an icon to be used as fallback.
3518 *
3519 * The fallback icon is used for windows that
3520 * haven't had [method@Gtk.Window.set_icon_name]
3521 * called on them.
3522 */
3523void
3524gtk_window_set_default_icon_name (const char *name)
3525{
3526 GList *tmp_list;
3527 GList *toplevels;
3528
3529 g_free (mem: default_icon_name);
3530 default_icon_name = g_strdup (str: name);
3531
3532 /* Update all toplevels */
3533 toplevels = gtk_window_list_toplevels ();
3534 tmp_list = toplevels;
3535 while (tmp_list != NULL)
3536 {
3537 GtkWindowIconInfo *info;
3538 GtkWindow *w = tmp_list->data;
3539
3540 info = get_icon_info (window: w);
3541 if (info && info->using_default_icon && info->using_themed_icon)
3542 {
3543 gtk_window_unrealize_icon (window: w);
3544 if (_gtk_widget_get_realized (GTK_WIDGET (w)))
3545 gtk_window_realize_icon (window: w);
3546 }
3547
3548 tmp_list = tmp_list->next;
3549 }
3550 g_list_free (list: toplevels);
3551}
3552
3553/**
3554 * gtk_window_get_default_icon_name:
3555 *
3556 * Returns the fallback icon name for windows.
3557 *
3558 * The returned string is owned by GTK and should not
3559 * be modified. It is only valid until the next call to
3560 * [func@Gtk.Window.set_default_icon_name].
3561 *
3562 * Returns: (nullable): the fallback icon name for windows
3563 */
3564const char *
3565gtk_window_get_default_icon_name (void)
3566{
3567 return default_icon_name;
3568}
3569
3570static void
3571gtk_window_update_csd_size (GtkWindow *window,
3572 int *width,
3573 int *height,
3574 int apply)
3575{
3576 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
3577 GtkBorder window_border = { 0 };
3578 int w, h;
3579
3580 if (!priv->decorated ||
3581 priv->fullscreen)
3582 return;
3583
3584 get_shadow_width (window, shadow_width: &window_border);
3585 w = *width + apply * (window_border.left + window_border.right);
3586 h = *height + apply * (window_border.top + window_border.bottom);
3587
3588 /* Make sure the size remains acceptable */
3589 if (w < 1)
3590 w = 1;
3591 if (h < 1)
3592 h = 1;
3593
3594 /* Only update given size if not negative */
3595 if (*width > -1)
3596 *width = w;
3597 if (*height > -1)
3598 *height = h;
3599}
3600
3601static void
3602gtk_window_set_default_size_internal (GtkWindow *window,
3603 gboolean change_width,
3604 int width,
3605 gboolean change_height,
3606 int height)
3607{
3608 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
3609
3610 g_return_if_fail (change_width == FALSE || width >= -1);
3611 g_return_if_fail (change_height == FALSE || height >= -1);
3612
3613 g_object_freeze_notify (G_OBJECT (window));
3614
3615 if (change_width)
3616 {
3617 if (priv->default_width != width)
3618 {
3619 priv->default_width = width;
3620 g_object_notify_by_pspec (G_OBJECT (window), pspec: window_props[PROP_DEFAULT_WIDTH]);
3621 }
3622 }
3623
3624 if (change_height)
3625 {
3626 if (priv->default_height != height)
3627 {
3628 priv->default_height = height;
3629 g_object_notify_by_pspec (G_OBJECT (window), pspec: window_props[PROP_DEFAULT_HEIGHT]);
3630 }
3631 }
3632
3633 g_object_thaw_notify (G_OBJECT (window));
3634}
3635
3636/**
3637 * gtk_window_set_default_size:
3638 * @window: a `GtkWindow`
3639 * @width: width in pixels, or -1 to unset the default width
3640 * @height: height in pixels, or -1 to unset the default height
3641 *
3642 * Sets the default size of a window.
3643 *
3644 * If the window’s “natural” size (its size request) is larger than
3645 * the default, the default will be ignored.
3646 *
3647 * Unlike [method@Gtk.Widget.set_size_request], which sets a size
3648 * request for a widget and thus would keep users from shrinking
3649 * the window, this function only sets the initial size, just as
3650 * if the user had resized the window themselves. Users can still
3651 * shrink the window again as they normally would. Setting a default
3652 * size of -1 means to use the “natural” default size (the size request
3653 * of the window).
3654 *
3655 * The default size of a window only affects the first time a window is
3656 * shown; if a window is hidden and re-shown, it will remember the size
3657 * it had prior to hiding, rather than using the default size.
3658 *
3659 * Windows can’t actually be 0x0 in size, they must be at least 1x1, but
3660 * passing 0 for @width and @height is OK, resulting in a 1x1 default size.
3661 *
3662 * If you use this function to reestablish a previously saved window size,
3663 * note that the appropriate size to save is the one returned by
3664 * [method@Gtk.Window.get_default_size]. Using the window allocation
3665 * directly will not work in all circumstances and can lead to growing
3666 * or shrinking windows.
3667 */
3668void
3669gtk_window_set_default_size (GtkWindow *window,
3670 int width,
3671 int height)
3672{
3673 g_return_if_fail (GTK_IS_WINDOW (window));
3674 g_return_if_fail (width >= -1);
3675 g_return_if_fail (height >= -1);
3676
3677 gtk_window_set_default_size_internal (window, TRUE, width, TRUE, height);
3678 gtk_widget_queue_resize (GTK_WIDGET (window));
3679}
3680
3681/**
3682 * gtk_window_get_default_size:
3683 * @window: a `GtkWindow`
3684 * @width: (out) (optional): location to store the default width
3685 * @height: (out) (optional): location to store the default height
3686 *
3687 * Gets the default size of the window.
3688 *
3689 * A value of 0 for the width or height indicates that a default
3690 * size has not been explicitly set for that dimension, so the
3691 * “natural” size of the window will be used.
3692 */
3693void
3694gtk_window_get_default_size (GtkWindow *window,
3695 int *width,
3696 int *height)
3697{
3698 g_return_if_fail (GTK_IS_WINDOW (window));
3699
3700 gtk_window_get_remembered_size (window, width, height);
3701}
3702
3703static gboolean
3704gtk_window_close_request (GtkWindow *window)
3705{
3706 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
3707
3708 if (priv->hide_on_close)
3709 {
3710 gtk_widget_hide (GTK_WIDGET (window));
3711 return TRUE;
3712 }
3713
3714 return FALSE;
3715}
3716
3717gboolean
3718gtk_window_emit_close_request (GtkWindow *window)
3719{
3720 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
3721 gboolean handled;
3722
3723 /* Avoid re-entrancy issues when calling gtk_window_close from a
3724 * close-request handler */
3725 if (priv->in_emit_close_request)
3726 return TRUE;
3727
3728 priv->in_emit_close_request = TRUE;
3729 g_signal_emit (instance: window, signal_id: window_signals[CLOSE_REQUEST], detail: 0, &handled);
3730 priv->in_emit_close_request = FALSE;
3731
3732 return handled;
3733}
3734
3735static void
3736gtk_window_finalize (GObject *object)
3737{
3738 GtkWindow *window = GTK_WINDOW (object);
3739 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
3740 GdkSeat *seat;
3741
3742 g_free (mem: priv->title);
3743 gtk_window_release_application (window);
3744
3745 if (priv->geometry_info)
3746 {
3747 g_free (mem: priv->geometry_info);
3748 }
3749
3750 if (priv->keys_changed_handler)
3751 {
3752 g_source_remove (tag: priv->keys_changed_handler);
3753 priv->keys_changed_handler = 0;
3754 }
3755
3756 seat = gdk_display_get_default_seat (display: priv->display);
3757 if (seat)
3758 g_signal_handlers_disconnect_by_func (seat, device_removed_cb, window);
3759
3760#ifdef GDK_WINDOWING_X11
3761 g_signal_handlers_disconnect_by_func (gtk_settings_get_for_display (priv->display),
3762 gtk_window_on_theme_variant_changed,
3763 window);
3764#endif
3765
3766 g_free (mem: priv->startup_id);
3767
3768 if (priv->mnemonics_display_timeout_id)
3769 {
3770 g_source_remove (tag: priv->mnemonics_display_timeout_id);
3771 priv->mnemonics_display_timeout_id = 0;
3772 }
3773
3774 if (priv->focus_visible_timeout)
3775 {
3776 g_source_remove (tag: priv->focus_visible_timeout);
3777 priv->focus_visible_timeout = 0;
3778 }
3779
3780 g_clear_object (&priv->constraint_solver);
3781 g_clear_object (&priv->renderer);
3782 g_clear_object (&priv->resize_cursor);
3783
3784 G_OBJECT_CLASS (gtk_window_parent_class)->finalize (object);
3785}
3786
3787static gboolean
3788update_csd_visibility (GtkWindow *window)
3789{
3790 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
3791 gboolean visible;
3792
3793 if (priv->title_box == NULL)
3794 return FALSE;
3795
3796 visible = !priv->fullscreen &&
3797 priv->decorated;
3798
3799 gtk_widget_set_child_visible (widget: priv->title_box, child_visible: visible);
3800
3801 return visible;
3802}
3803
3804static void
3805update_window_actions (GtkWindow *window)
3806{
3807 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
3808 gboolean is_sovereign_window = !priv->modal && !priv->transient_parent;
3809
3810 gtk_widget_action_set_enabled (GTK_WIDGET (window), action_name: "window.minimize",
3811 enabled: is_sovereign_window);
3812 gtk_widget_action_set_enabled (GTK_WIDGET (window), action_name: "window.toggle-maximized",
3813 enabled: priv->resizable && is_sovereign_window);
3814 gtk_widget_action_set_enabled (GTK_WIDGET (window), action_name: "window.close",
3815 enabled: priv->deletable);
3816
3817 update_csd_visibility (window);
3818}
3819
3820void
3821_gtk_window_request_csd (GtkWindow *window)
3822{
3823 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
3824
3825 priv->csd_requested = TRUE;
3826}
3827
3828static gboolean
3829gtk_window_should_use_csd (GtkWindow *window)
3830{
3831 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
3832 const char *csd_env;
3833
3834 if (priv->csd_requested)
3835 return TRUE;
3836
3837 if (!priv->decorated)
3838 return FALSE;
3839
3840 csd_env = g_getenv (variable: "GTK_CSD");
3841
3842#ifdef GDK_WINDOWING_BROADWAY
3843 if (GDK_IS_BROADWAY_DISPLAY (gtk_widget_get_display (GTK_WIDGET (window))))
3844 return TRUE;
3845#endif
3846
3847#ifdef GDK_WINDOWING_WAYLAND
3848 if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (GTK_WIDGET (window))))
3849 {
3850 GdkDisplay *gdk_display = gtk_widget_get_display (GTK_WIDGET (window));
3851 return !gdk_wayland_display_prefers_ssd (display: gdk_display);
3852 }
3853#endif
3854
3855#ifdef GDK_WINDOWING_WIN32
3856 if (g_strcmp0 (csd_env, "0") != 0 &&
3857 GDK_IS_WIN32_DISPLAY (gtk_widget_get_display (GTK_WIDGET (window))))
3858 return TRUE;
3859#endif
3860
3861 return (g_strcmp0 (str1: csd_env, str2: "1") == 0);
3862}
3863
3864static void
3865gtk_window_show (GtkWidget *widget)
3866{
3867 GtkWindow *window = GTK_WINDOW (widget);
3868 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
3869
3870 _gtk_widget_set_visible_flag (widget, TRUE);
3871
3872 gtk_css_node_validate (cssnode: gtk_widget_get_css_node (widget));
3873
3874 gtk_widget_realize (widget);
3875
3876 gtk_window_present_toplevel (window);
3877
3878 gtk_widget_map (widget);
3879
3880 if (!priv->focus_widget)
3881 gtk_window_move_focus (widget, dir: GTK_DIR_TAB_FORWARD);
3882
3883 if (priv->modal)
3884 gtk_grab_add (widget);
3885}
3886
3887static void
3888gtk_window_hide (GtkWidget *widget)
3889{
3890 GtkWindow *window = GTK_WINDOW (widget);
3891 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
3892
3893 _gtk_widget_set_visible_flag (widget, FALSE);
3894 gtk_widget_unmap (widget);
3895
3896 if (priv->modal)
3897 gtk_grab_remove (widget);
3898}
3899
3900static GdkToplevelLayout *
3901gtk_window_compute_base_layout (GtkWindow *window)
3902{
3903 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
3904 GdkToplevelLayout *layout;
3905
3906 layout = gdk_toplevel_layout_new ();
3907
3908 gdk_toplevel_layout_set_resizable (layout, resizable: priv->resizable);
3909
3910 return layout;
3911}
3912
3913static void
3914gtk_window_present_toplevel (GtkWindow *window)
3915{
3916 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
3917 GdkToplevelLayout *layout;
3918
3919 layout = gtk_window_compute_base_layout (window);
3920 gdk_toplevel_layout_set_maximized (layout, maximized: priv->maximized);
3921 gdk_toplevel_layout_set_fullscreen (layout, fullscreen: priv->fullscreen,
3922 monitor: priv->initial_fullscreen_monitor);
3923 gdk_toplevel_present (toplevel: GDK_TOPLEVEL (ptr: priv->surface), layout);
3924 gdk_toplevel_layout_unref (layout);
3925}
3926
3927static void
3928gtk_window_update_toplevel (GtkWindow *window,
3929 GdkToplevelLayout *layout)
3930{
3931 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
3932
3933 if (_gtk_widget_get_mapped (GTK_WIDGET (window)))
3934 gdk_toplevel_present (toplevel: GDK_TOPLEVEL (ptr: priv->surface), layout);
3935 gdk_toplevel_layout_unref (layout);
3936}
3937
3938static void
3939gtk_window_map (GtkWidget *widget)
3940{
3941 GtkWindow *window = GTK_WINDOW (widget);
3942 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
3943 GtkWidget *child = priv->child;
3944
3945 GTK_WIDGET_CLASS (gtk_window_parent_class)->map (widget);
3946
3947 if (child != NULL && gtk_widget_get_visible (widget: child))
3948 gtk_widget_map (widget: child);
3949
3950 if (priv->title_box != NULL &&
3951 gtk_widget_get_visible (widget: priv->title_box) &&
3952 gtk_widget_get_child_visible (widget: priv->title_box))
3953 gtk_widget_map (widget: priv->title_box);
3954
3955 gtk_window_present_toplevel (window);
3956
3957 if (priv->minimize_initially)
3958 gdk_toplevel_minimize (toplevel: GDK_TOPLEVEL (ptr: priv->surface));
3959
3960 gtk_window_set_theme_variant (window);
3961
3962 if (!disable_startup_notification)
3963 {
3964 /* Do we have a custom startup-notification id? */
3965 if (priv->startup_id != NULL)
3966 {
3967 /* Make sure we have a "real" id */
3968 if (!startup_id_is_fake (startup_id: priv->startup_id))
3969 gdk_display_notify_startup_complete (display: gtk_widget_get_display (widget), startup_id: priv->startup_id);
3970
3971 g_free (mem: priv->startup_id);
3972 priv->startup_id = NULL;
3973 }
3974 else
3975 gdk_display_notify_startup_complete (display: gtk_widget_get_display (widget), NULL);
3976 }
3977
3978 /* inherit from transient parent, so that a dialog that is
3979 * opened via keynav shows focus initially
3980 */
3981 if (priv->transient_parent)
3982 gtk_window_set_focus_visible (window, setting: gtk_window_get_focus_visible (window: priv->transient_parent));
3983 else
3984 gtk_window_set_focus_visible (window, FALSE);
3985
3986 if (priv->application)
3987 gtk_application_handle_window_map (application: priv->application, window);
3988
3989 gtk_widget_realize_at_context (widget);
3990}
3991
3992static void
3993gtk_window_unmap (GtkWidget *widget)
3994{
3995 GtkWindow *window = GTK_WINDOW (widget);
3996 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
3997 GtkWidget *child = priv->child;
3998
3999 GTK_WIDGET_CLASS (gtk_window_parent_class)->unmap (widget);
4000 gdk_surface_hide (surface: priv->surface);
4001
4002 gtk_widget_unrealize_at_context (widget);
4003
4004 if (priv->title_box != NULL)
4005 gtk_widget_unmap (widget: priv->title_box);
4006
4007 if (child != NULL)
4008 gtk_widget_unmap (widget: child);
4009}
4010
4011static void
4012gtk_window_get_remembered_size (GtkWindow *window,
4013 int *width,
4014 int *height)
4015{
4016 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
4017
4018 *width = priv->default_width;
4019 *height = priv->default_height;
4020}
4021
4022static void
4023check_scale_changed (GtkWindow *window)
4024{
4025 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
4026 GtkWidget *widget = GTK_WIDGET (window);
4027 int old_scale;
4028
4029 old_scale = priv->scale;
4030 priv->scale = gtk_widget_get_scale_factor (widget);
4031 if (old_scale != priv->scale)
4032 _gtk_widget_scale_changed (widget);
4033}
4034
4035static void
4036get_shadow_width (GtkWindow *window,
4037 GtkBorder *shadow_width)
4038{
4039 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
4040 GtkCssStyle *style;
4041
4042 if (!priv->decorated)
4043 goto out;
4044
4045 if (!priv->client_decorated ||
4046 !priv->use_client_shadow)
4047 goto out;
4048
4049 if (priv->maximized ||
4050 priv->fullscreen)
4051 goto out;
4052
4053 style = gtk_css_node_get_style (cssnode: gtk_widget_get_css_node (GTK_WIDGET (window)));
4054
4055 /* Calculate the size of the drop shadows ... */
4056 gtk_css_shadow_value_get_extents (shadow: style->background->box_shadow, border: shadow_width);
4057
4058 shadow_width->left = MAX (shadow_width->left, RESIZE_HANDLE_SIZE);
4059 shadow_width->top = MAX (shadow_width->top, RESIZE_HANDLE_SIZE);
4060 shadow_width->bottom = MAX (shadow_width->bottom, RESIZE_HANDLE_SIZE);
4061 shadow_width->right = MAX (shadow_width->right, RESIZE_HANDLE_SIZE);
4062
4063 return;
4064
4065out:
4066 *shadow_width = (GtkBorder) {0, 0, 0, 0};
4067}
4068
4069static void
4070update_opaque_region (GtkWindow *window)
4071{
4072 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
4073 gboolean subtract_decoration_corners;
4074 gboolean subtract_shadow;
4075
4076 subtract_decoration_corners = (priv->client_decorated &&
4077 priv->decorated &&
4078 !priv->fullscreen &&
4079 !priv->maximized);
4080 subtract_shadow = (priv->client_decorated &&
4081 priv->decorated &&
4082 priv->use_client_shadow &&
4083 !priv->maximized &&
4084 !priv->fullscreen);
4085
4086 gtk_native_update_opaque_region (native: GTK_NATIVE (ptr: window),
4087 NULL,
4088 subtract_decoration_corners,
4089 subtract_shadow,
4090 RESIZE_HANDLE_SIZE);
4091}
4092
4093static void
4094update_realized_window_properties (GtkWindow *window)
4095{
4096 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
4097 GdkRectangle rect;
4098 GtkCssBoxes css_boxes;
4099 const graphene_rect_t *border_rect;
4100 double native_x, native_y;
4101
4102 update_opaque_region (window);
4103
4104 if (!priv->client_decorated || !priv->use_client_shadow)
4105 return;
4106
4107 gtk_native_get_surface_transform (self: GTK_NATIVE (ptr: window), x: &native_x, y: &native_y);
4108
4109 /* update the input shape, which makes it so that clicks
4110 * outside the border windows go through. */
4111 gtk_css_boxes_init (boxes: &css_boxes, GTK_WIDGET (window));
4112 border_rect = gtk_css_boxes_get_border_rect (boxes: &css_boxes);
4113
4114 /* This logic is duplicated in get_edge_for_coordinates() */
4115 rect.x = native_x + border_rect->origin.x - RESIZE_HANDLE_SIZE;
4116 rect.y = native_y + border_rect->origin.y - RESIZE_HANDLE_SIZE;
4117 rect.width = border_rect->size.width + 2 * RESIZE_HANDLE_SIZE;
4118 rect.height = border_rect->size.height + 2 * RESIZE_HANDLE_SIZE;
4119
4120 if (rect.width > 0 && rect.height > 0)
4121 {
4122 cairo_region_t *region = cairo_region_create_rectangle (rectangle: &rect);
4123
4124 gdk_surface_set_input_region (surface: priv->surface, region);
4125 cairo_region_destroy (region);
4126 }
4127}
4128
4129/* NB: When orientation is VERTICAL, width/height are flipped.
4130 * The code uses the terms nonetheless to make it more intuitive
4131 * to understand.
4132 */
4133static void
4134gtk_window_compute_min_size (GtkWidget *window,
4135 GtkOrientation orientation,
4136 double ideal_ratio,
4137 int *min_width,
4138 int *min_height)
4139{
4140 int start, end, mid, other;
4141 double ratio;
4142
4143 /* start = min width, end = min width for min height (ie max width) */
4144 gtk_widget_measure (widget: window, orientation, for_size: -1, minimum: &start, NULL, NULL, NULL);
4145 gtk_widget_measure (widget: window, OPPOSITE_ORIENTATION (orientation), for_size: start, minimum: &other, NULL, NULL, NULL);
4146 if ((double) start / other >= ideal_ratio)
4147 {
4148 *min_width = start;
4149 *min_height = other;
4150 return;
4151 }
4152 gtk_widget_measure (widget: window, OPPOSITE_ORIENTATION (orientation), for_size: -1, minimum: &other, NULL, NULL, NULL);
4153 gtk_widget_measure (widget: window, orientation, for_size: other, minimum: &end, NULL, NULL, NULL);
4154 if ((double) end / other <= ideal_ratio)
4155 {
4156 *min_width = end;
4157 *min_height = other;
4158 return;
4159 }
4160
4161 while (start < end)
4162 {
4163 mid = (start + end) / 2;
4164
4165 gtk_widget_measure (widget: window, OPPOSITE_ORIENTATION (orientation), for_size: mid, minimum: &other, NULL, NULL, NULL);
4166 ratio = (double) mid / other;
4167 if(ratio == ideal_ratio)
4168 {
4169 *min_width = mid;
4170 *min_height = other;
4171 return;
4172 }
4173 else if (ratio < ideal_ratio)
4174 start = mid + 1;
4175 else
4176 end = mid - 1;
4177 }
4178
4179 gtk_widget_measure (widget: window, orientation, for_size: other, minimum: &start, NULL, NULL, NULL);
4180 *min_width = start;
4181 *min_height = other;
4182}
4183
4184static void
4185gtk_window_compute_default_size (GtkWindow *window,
4186 int cur_width,
4187 int cur_height,
4188 int max_width,
4189 int max_height,
4190 int *min_width,
4191 int *min_height,
4192 int *width,
4193 int *height)
4194{
4195 GtkWidget *widget = GTK_WIDGET (window);
4196 GtkSizeRequestMode request_mode = gtk_widget_get_request_mode (widget);
4197
4198 if (request_mode == GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT)
4199 {
4200 int minimum, natural;
4201
4202 gtk_widget_measure (widget, orientation: GTK_ORIENTATION_VERTICAL, for_size: -1,
4203 minimum: &minimum, natural: &natural,
4204 NULL, NULL);
4205 *min_height = minimum;
4206 if (cur_height <= 0)
4207 cur_height = natural;
4208 *height = MAX (minimum, MIN (max_height, cur_height));
4209
4210 gtk_widget_measure (widget, orientation: GTK_ORIENTATION_HORIZONTAL,
4211 for_size: *height,
4212 minimum: &minimum, natural: &natural,
4213 NULL, NULL);
4214 *min_width = minimum;
4215 if (cur_width <= 0)
4216 cur_width = natural;
4217 *width = MAX (minimum, MIN (max_width, cur_width));
4218
4219 gtk_window_compute_min_size (window: widget, orientation: GTK_ORIENTATION_VERTICAL, ideal_ratio: (double) *height / *width, min_width: min_height, min_height: min_width);
4220 }
4221 else /* GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH or CONSTANT_SIZE */
4222 {
4223 int minimum, natural;
4224
4225 gtk_widget_measure (widget, orientation: GTK_ORIENTATION_HORIZONTAL, for_size: -1,
4226 minimum: &minimum, natural: &natural,
4227 NULL, NULL);
4228 *min_width = minimum;
4229 if (cur_width <= 0)
4230 cur_width = natural;
4231 *width = MAX (minimum, MIN (max_width, cur_width));
4232
4233 gtk_widget_measure (widget, orientation: GTK_ORIENTATION_VERTICAL,
4234 for_size: *width,
4235 minimum: &minimum, natural: &natural,
4236 NULL, NULL);
4237 *min_height = minimum;
4238 if (cur_height <= 0)
4239 cur_height = natural;
4240
4241 *height = MAX (minimum, MIN (max_height, cur_height));
4242
4243 if (request_mode != GTK_SIZE_REQUEST_CONSTANT_SIZE)
4244 gtk_window_compute_min_size (window: widget, orientation: GTK_ORIENTATION_HORIZONTAL, ideal_ratio: (double) *width / *height, min_width, min_height);
4245 }
4246}
4247
4248static gboolean
4249should_remember_size (GtkWindow *window)
4250{
4251 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
4252
4253 if (!priv->resizable)
4254 return FALSE;
4255
4256 return !(priv->state & (GDK_TOPLEVEL_STATE_FULLSCREEN |
4257 GDK_TOPLEVEL_STATE_MAXIMIZED |
4258 GDK_TOPLEVEL_STATE_TILED |
4259 GDK_TOPLEVEL_STATE_TOP_TILED |
4260 GDK_TOPLEVEL_STATE_RIGHT_TILED |
4261 GDK_TOPLEVEL_STATE_BOTTOM_TILED |
4262 GDK_TOPLEVEL_STATE_LEFT_TILED |
4263 GDK_TOPLEVEL_STATE_MINIMIZED));
4264}
4265
4266static void
4267toplevel_compute_size (GdkToplevel *toplevel,
4268 GdkToplevelSize *size,
4269 GtkWidget *widget)
4270{
4271 GtkWindow *window = GTK_WINDOW (widget);
4272 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
4273 int width, height;
4274 GtkBorder shadow;
4275 int bounds_width, bounds_height;
4276 int min_width, min_height;
4277
4278 gdk_toplevel_size_get_bounds (size, bounds_width: &bounds_width, bounds_height: &bounds_height);
4279
4280 gtk_window_compute_default_size (window,
4281 cur_width: priv->default_width, cur_height: priv->default_height,
4282 max_width: bounds_width, max_height: bounds_height,
4283 min_width: &min_width, min_height: &min_height,
4284 width: &width, height: &height);
4285
4286 if (width < min_width)
4287 width = min_width;
4288 if (height < min_height)
4289 height = min_height;
4290
4291 if (should_remember_size (window))
4292 gtk_window_set_default_size_internal (window, TRUE, width, TRUE, height);
4293
4294 gtk_window_update_csd_size (window,
4295 width: &width, height: &height,
4296 INCLUDE_CSD_SIZE);
4297 gtk_window_update_csd_size (window,
4298 width: &min_width, height: &min_height,
4299 INCLUDE_CSD_SIZE);
4300
4301 gdk_toplevel_size_set_min_size (size, min_width, min_height);
4302
4303 gdk_toplevel_size_set_size (size, width, height);
4304
4305 if (priv->use_client_shadow)
4306 {
4307 get_shadow_width (window, shadow_width: &shadow);
4308 gdk_toplevel_size_set_shadow_width (size,
4309 left: shadow.left, right: shadow.right,
4310 top: shadow.top, bottom: shadow.bottom);
4311 }
4312
4313 gtk_widget_ensure_resize (widget);
4314}
4315
4316static void
4317gtk_window_realize (GtkWidget *widget)
4318{
4319 GtkWindow *window = GTK_WINDOW (widget);
4320 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
4321 GdkSurface *surface;
4322 GdkFrameClock *frame_clock;
4323
4324 /* Create default title bar */
4325 if (!priv->client_decorated && gtk_window_should_use_csd (window))
4326 {
4327 priv->use_client_shadow = gtk_window_supports_client_shadow (window);
4328 if (priv->use_client_shadow)
4329 {
4330 gtk_window_enable_csd (window);
4331
4332 if (priv->title_box == NULL)
4333 {
4334 priv->title_box = gtk_header_bar_new ();
4335 gtk_widget_add_css_class (widget: priv->title_box, css_class: "titlebar");
4336 gtk_widget_add_css_class (widget: priv->title_box, css_class: "default-decoration");
4337
4338 gtk_widget_insert_before (widget: priv->title_box, parent: widget, NULL);
4339 }
4340
4341 update_window_actions (window);
4342 }
4343 }
4344
4345 surface = gdk_surface_new_toplevel (display: gtk_widget_get_display (widget));
4346 priv->surface = surface;
4347 gdk_surface_set_widget (self: surface, widget);
4348
4349 if (priv->renderer == NULL)
4350 priv->renderer = gsk_renderer_new_for_surface (surface);
4351
4352 g_signal_connect_swapped (surface, "notify::state", G_CALLBACK (surface_state_changed), widget);
4353 g_signal_connect_swapped (surface, "notify::mapped", G_CALLBACK (surface_state_changed), widget);
4354 g_signal_connect (surface, "render", G_CALLBACK (surface_render), widget);
4355 g_signal_connect (surface, "event", G_CALLBACK (surface_event), widget);
4356 g_signal_connect (surface, "compute-size", G_CALLBACK (toplevel_compute_size), widget);
4357
4358 frame_clock = gdk_surface_get_frame_clock (surface);
4359 g_signal_connect (frame_clock, "after-paint", G_CALLBACK (after_paint), widget);
4360
4361 GTK_WIDGET_CLASS (gtk_window_parent_class)->realize (widget);
4362
4363 gtk_root_start_layout (self: GTK_ROOT (ptr: window));
4364
4365 if (priv->transient_parent &&
4366 _gtk_widget_get_realized (GTK_WIDGET (priv->transient_parent)))
4367 {
4368 GtkWindowPrivate *parent_priv = gtk_window_get_instance_private (self: priv->transient_parent);
4369 gdk_toplevel_set_transient_for (toplevel: GDK_TOPLEVEL (ptr: surface), parent: parent_priv->surface);
4370 }
4371
4372 if (priv->title)
4373 gdk_toplevel_set_title (toplevel: GDK_TOPLEVEL (ptr: surface), title: priv->title);
4374
4375 gdk_toplevel_set_decorated (toplevel: GDK_TOPLEVEL (ptr: surface), decorated: priv->decorated && !priv->client_decorated);
4376 gdk_toplevel_set_deletable (toplevel: GDK_TOPLEVEL (ptr: surface), deletable: priv->deletable);
4377
4378#ifdef GDK_WINDOWING_WAYLAND
4379 if (GDK_IS_WAYLAND_SURFACE (surface))
4380 {
4381 if (priv->client_decorated)
4382 gdk_wayland_toplevel_announce_csd (toplevel: GDK_TOPLEVEL (ptr: surface));
4383 else
4384 gdk_wayland_toplevel_announce_ssd (toplevel: GDK_TOPLEVEL (ptr: surface));
4385 }
4386#endif
4387
4388 gdk_toplevel_set_modal (toplevel: GDK_TOPLEVEL (ptr: surface), modal: priv->modal);
4389
4390 if (priv->startup_id)
4391 {
4392#ifdef GDK_WINDOWING_X11
4393 if (GDK_IS_X11_SURFACE (surface))
4394 {
4395 guint32 timestamp = extract_time_from_startup_id (startup_id: priv->startup_id);
4396 if (timestamp != GDK_CURRENT_TIME)
4397 gdk_x11_surface_set_user_time (surface, timestamp);
4398 }
4399#endif
4400 if (!startup_id_is_fake (startup_id: priv->startup_id))
4401 gdk_toplevel_set_startup_id (toplevel: GDK_TOPLEVEL (ptr: surface), startup_id: priv->startup_id);
4402 }
4403
4404#ifdef GDK_WINDOWING_X11
4405 if (priv->initial_timestamp != GDK_CURRENT_TIME)
4406 {
4407 if (GDK_IS_X11_SURFACE (surface))
4408 gdk_x11_surface_set_user_time (surface, timestamp: priv->initial_timestamp);
4409 }
4410#endif
4411
4412 update_realized_window_properties (window);
4413
4414 if (priv->application)
4415 gtk_application_handle_window_realize (application: priv->application, window);
4416
4417 /* Icons */
4418 gtk_window_realize_icon (window);
4419
4420 check_scale_changed (window);
4421
4422 gtk_native_realize (self: GTK_NATIVE (ptr: window));
4423}
4424
4425static void
4426gtk_window_unrealize (GtkWidget *widget)
4427{
4428 GtkWindow *window = GTK_WINDOW (widget);
4429 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
4430 GtkWindowGeometryInfo *info;
4431 GdkSurface *surface;
4432 GdkFrameClock *frame_clock;
4433
4434 gtk_native_unrealize (self: GTK_NATIVE (ptr: window));
4435
4436 /* On unrealize, we reset the size of the window such
4437 * that we will re-apply the default sizing stuff
4438 * next time we show the window.
4439 *
4440 * Default positioning is reset on unmap, instead of unrealize.
4441 */
4442 priv->need_default_size = TRUE;
4443 info = gtk_window_get_geometry_info (window, FALSE);
4444 if (info)
4445 {
4446 info->last.configure_request.x = 0;
4447 info->last.configure_request.y = 0;
4448 info->last.configure_request.width = -1;
4449 info->last.configure_request.height = -1;
4450 /* be sure we reset geom hints on re-realize */
4451 info->last.flags = 0;
4452 }
4453
4454 gsk_renderer_unrealize (renderer: priv->renderer);
4455
4456 /* Icons */
4457 gtk_window_unrealize_icon (window);
4458
4459 if (priv->title_box)
4460 gtk_widget_unrealize (widget: priv->title_box);
4461
4462 if (priv->child)
4463 gtk_widget_unrealize (widget: priv->child);
4464
4465 g_clear_object (&priv->renderer);
4466
4467 surface = priv->surface;
4468
4469 g_signal_handlers_disconnect_by_func (surface, surface_state_changed, widget);
4470 g_signal_handlers_disconnect_by_func (surface, surface_render, widget);
4471 g_signal_handlers_disconnect_by_func (surface, surface_event, widget);
4472
4473 frame_clock = gdk_surface_get_frame_clock (surface);
4474
4475 g_signal_handlers_disconnect_by_func (frame_clock, after_paint, widget);
4476
4477 gtk_root_stop_layout (self: GTK_ROOT (ptr: window));
4478
4479 GTK_WIDGET_CLASS (gtk_window_parent_class)->unrealize (widget);
4480
4481 gdk_surface_set_widget (self: surface, NULL);
4482 gdk_surface_destroy (surface);
4483 g_clear_object (&priv->surface);
4484}
4485
4486static void
4487update_window_style_classes (GtkWindow *window)
4488{
4489 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
4490 GtkWidget *widget = GTK_WIDGET (window);
4491 guint edge_constraints;
4492
4493 edge_constraints = priv->edge_constraints;
4494
4495 if (!priv->edge_constraints)
4496 {
4497 if (priv->tiled)
4498 gtk_widget_add_css_class (widget, css_class: "tiled");
4499 else
4500 gtk_widget_remove_css_class (widget, css_class: "tiled");
4501 }
4502 else
4503 {
4504 if (edge_constraints & GDK_TOPLEVEL_STATE_TOP_TILED)
4505 gtk_widget_add_css_class (widget, css_class: "tiled-top");
4506 else
4507 gtk_widget_remove_css_class (widget, css_class: "tiled-top");
4508
4509 if (edge_constraints & GDK_TOPLEVEL_STATE_RIGHT_TILED)
4510 gtk_widget_add_css_class (widget, css_class: "tiled-right");
4511 else
4512 gtk_widget_remove_css_class (widget, css_class: "tiled-right");
4513
4514 if (edge_constraints & GDK_TOPLEVEL_STATE_BOTTOM_TILED)
4515 gtk_widget_add_css_class (widget, css_class: "tiled-bottom");
4516 else
4517 gtk_widget_remove_css_class (widget, css_class: "tiled-bottom");
4518
4519 if (edge_constraints & GDK_TOPLEVEL_STATE_LEFT_TILED)
4520 gtk_widget_add_css_class (widget, css_class: "tiled-left");
4521 else
4522 gtk_widget_remove_css_class (widget, css_class: "tiled-left");
4523 }
4524
4525 if (priv->maximized)
4526 gtk_widget_add_css_class (widget, css_class: "maximized");
4527 else
4528 gtk_widget_remove_css_class (widget, css_class: "maximized");
4529
4530 if (priv->fullscreen)
4531 gtk_widget_add_css_class (widget, css_class: "fullscreen");
4532 else
4533 gtk_widget_remove_css_class (widget, css_class: "fullscreen");
4534}
4535
4536/* _gtk_window_set_allocation:
4537 * @window: a `GtkWindow`
4538 * @allocation: the original allocation for the window
4539 * @allocation_out: @allocation taking decorations into
4540 * consideration
4541 *
4542 * This function is like gtk_widget_set_allocation()
4543 * but does the necessary extra work to update
4544 * the resize grip positioning, etc.
4545 *
4546 * Call this instead of gtk_widget_set_allocation()
4547 * when overriding ::size_allocate in a GtkWindow
4548 * subclass without chaining up.
4549 *
4550 * The @allocation parameter will be adjusted to
4551 * reflect any internal decorations that the window
4552 * may have. That revised allocation will then be
4553 * returned in the @allocation_out parameter.
4554 */
4555void
4556_gtk_window_set_allocation (GtkWindow *window,
4557 int width,
4558 int height,
4559 GtkAllocation *allocation_out)
4560{
4561 GtkWidget *widget = (GtkWidget *)window;
4562 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
4563 GtkAllocation child_allocation;
4564
4565 g_assert (allocation_out != NULL);
4566
4567 child_allocation.x = 0;
4568 child_allocation.y = 0;
4569 child_allocation.width = width;
4570 child_allocation.height = height;
4571
4572 if (_gtk_widget_get_realized (widget))
4573 {
4574 update_realized_window_properties (window);
4575 }
4576
4577 priv->title_height = 0;
4578
4579 if (priv->title_box != NULL &&
4580 gtk_widget_get_visible (widget: priv->title_box) &&
4581 gtk_widget_get_child_visible (widget: priv->title_box) &&
4582 priv->decorated &&
4583 !priv->fullscreen)
4584 {
4585 GtkAllocation title_allocation;
4586
4587 title_allocation.x = 0;
4588 title_allocation.y = 0;
4589 title_allocation.width = width;
4590
4591 gtk_widget_measure (widget: priv->title_box, orientation: GTK_ORIENTATION_VERTICAL,
4592 for_size: title_allocation.width,
4593 NULL, natural: &priv->title_height,
4594 NULL, NULL);
4595
4596 title_allocation.height = priv->title_height;
4597
4598 gtk_widget_size_allocate (widget: priv->title_box, allocation: &title_allocation, baseline: -1);
4599 }
4600
4601 if (priv->decorated &&
4602 !priv->fullscreen)
4603 {
4604 child_allocation.y += priv->title_height;
4605 child_allocation.height -= priv->title_height;
4606 }
4607
4608 *allocation_out = child_allocation;
4609}
4610
4611static void
4612gtk_window_size_allocate (GtkWidget *widget,
4613 int width,
4614 int height,
4615 int baseline)
4616{
4617 GtkWindow *window = GTK_WINDOW (widget);
4618 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
4619 GtkWidget *child = priv->child;
4620 GtkAllocation child_allocation;
4621
4622 _gtk_window_set_allocation (window, width, height, allocation_out: &child_allocation);
4623
4624 if (child && gtk_widget_get_visible (widget: child))
4625 gtk_widget_size_allocate (widget: child, allocation: &child_allocation, baseline: -1);
4626
4627 gtk_tooltip_maybe_allocate (native: GTK_NATIVE (ptr: widget));
4628}
4629
4630static void
4631update_edge_constraints (GtkWindow *window,
4632 GdkToplevelState state)
4633{
4634 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
4635
4636 priv->edge_constraints = (state & GDK_TOPLEVEL_STATE_TOP_TILED) |
4637 (state & GDK_TOPLEVEL_STATE_TOP_RESIZABLE) |
4638 (state & GDK_TOPLEVEL_STATE_RIGHT_TILED) |
4639 (state & GDK_TOPLEVEL_STATE_RIGHT_RESIZABLE) |
4640 (state & GDK_TOPLEVEL_STATE_BOTTOM_TILED) |
4641 (state & GDK_TOPLEVEL_STATE_BOTTOM_RESIZABLE) |
4642 (state & GDK_TOPLEVEL_STATE_LEFT_TILED) |
4643 (state & GDK_TOPLEVEL_STATE_LEFT_RESIZABLE);
4644
4645 priv->tiled = (state & GDK_TOPLEVEL_STATE_TILED) ? 1 : 0;
4646}
4647
4648static void
4649surface_state_changed (GtkWidget *widget)
4650{
4651 GtkWindow *window = GTK_WINDOW (widget);
4652 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
4653 GdkToplevelState new_surface_state;
4654 GdkToplevelState changed_mask;
4655
4656 new_surface_state = gdk_toplevel_get_state (toplevel: GDK_TOPLEVEL (ptr: priv->surface));
4657 changed_mask = new_surface_state ^ priv->state;
4658 priv->state = new_surface_state;
4659
4660 if (changed_mask & GDK_TOPLEVEL_STATE_FOCUSED)
4661 {
4662 gboolean focused = new_surface_state & GDK_TOPLEVEL_STATE_FOCUSED;
4663
4664 ensure_state_flag_backdrop (widget);
4665
4666 if (!focused)
4667 gtk_window_set_mnemonics_visible (window, FALSE);
4668 }
4669
4670 if (changed_mask & GDK_TOPLEVEL_STATE_FULLSCREEN)
4671 {
4672 priv->fullscreen = (new_surface_state & GDK_TOPLEVEL_STATE_FULLSCREEN) ? TRUE : FALSE;
4673
4674 g_object_notify_by_pspec (G_OBJECT (widget), pspec: window_props[PROP_FULLSCREENED]);
4675 }
4676
4677 if (changed_mask & GDK_TOPLEVEL_STATE_MAXIMIZED)
4678 {
4679 priv->maximized = (new_surface_state & GDK_TOPLEVEL_STATE_MAXIMIZED) ? TRUE : FALSE;
4680
4681 g_object_notify_by_pspec (G_OBJECT (widget), pspec: window_props[PROP_MAXIMIZED]);
4682 }
4683
4684 update_edge_constraints (window, state: new_surface_state);
4685
4686 if (changed_mask & (GDK_TOPLEVEL_STATE_FULLSCREEN |
4687 GDK_TOPLEVEL_STATE_MAXIMIZED |
4688 GDK_TOPLEVEL_STATE_TILED |
4689 GDK_TOPLEVEL_STATE_TOP_TILED |
4690 GDK_TOPLEVEL_STATE_RIGHT_TILED |
4691 GDK_TOPLEVEL_STATE_BOTTOM_TILED |
4692 GDK_TOPLEVEL_STATE_LEFT_TILED |
4693 GDK_TOPLEVEL_STATE_MINIMIZED))
4694 {
4695 update_window_style_classes (window);
4696 update_window_actions (window);
4697 gtk_widget_queue_resize (widget);
4698 }
4699}
4700
4701static void
4702surface_size_changed (GtkWidget *widget,
4703 int width,
4704 int height)
4705{
4706 GtkWindow *window = GTK_WINDOW (widget);
4707
4708 check_scale_changed (GTK_WINDOW (widget));
4709
4710 if (should_remember_size (window))
4711 {
4712 int width_to_remember;
4713 int height_to_remember;
4714
4715 width_to_remember = width;
4716 height_to_remember = height;
4717 gtk_window_update_csd_size (window,
4718 width: &width_to_remember, height: &height_to_remember,
4719 EXCLUDE_CSD_SIZE);
4720 gtk_window_set_default_size_internal (window,
4721 TRUE, width: width_to_remember,
4722 TRUE, height: height_to_remember);
4723 }
4724
4725 gtk_widget_queue_allocate (widget);
4726}
4727
4728static void
4729maybe_unset_focus_and_default (GtkWindow *window)
4730{
4731 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
4732
4733 if (priv->move_focus)
4734 {
4735 GtkWidget *parent;
4736
4737 parent = _gtk_widget_get_parent (widget: priv->move_focus_widget);
4738
4739 while (parent)
4740 {
4741 if (_gtk_widget_get_visible (widget: parent))
4742 {
4743 if (gtk_widget_grab_focus (widget: parent))
4744 break;
4745 }
4746
4747 parent = _gtk_widget_get_parent (widget: parent);
4748 }
4749
4750 if (!parent)
4751 gtk_widget_child_focus (GTK_WIDGET (window), direction: GTK_DIR_TAB_FORWARD);
4752
4753 priv->move_focus = FALSE;
4754 g_clear_object (&priv->move_focus_widget);
4755 }
4756
4757 if (priv->unset_default)
4758 gtk_window_set_default_widget (window, NULL);
4759}
4760
4761static gboolean
4762surface_render (GdkSurface *surface,
4763 cairo_region_t *region,
4764 GtkWidget *widget)
4765{
4766 gtk_widget_render (widget, surface, region);
4767
4768 return TRUE;
4769}
4770
4771static void
4772after_paint (GdkFrameClock *clock,
4773 GtkWindow *window)
4774{
4775 maybe_unset_focus_and_default (window);
4776}
4777
4778static gboolean
4779surface_event (GdkSurface *surface,
4780 GdkEvent *event,
4781 GtkWidget *widget)
4782{
4783 gtk_main_do_event (event);
4784 return TRUE;
4785}
4786
4787static void
4788gtk_window_real_activate_focus (GtkWindow *window)
4789{
4790 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
4791
4792 if (priv->focus_widget && gtk_widget_is_sensitive (widget: priv->focus_widget))
4793 gtk_widget_activate (widget: priv->focus_widget);
4794}
4795
4796static gboolean
4797gtk_window_has_mnemonic_modifier_pressed (GtkWindow *window)
4798{
4799 GList *seats, *s;
4800 gboolean retval = FALSE;
4801
4802 seats = gdk_display_list_seats (display: gtk_widget_get_display (GTK_WIDGET (window)));
4803
4804 for (s = seats; s; s = s->next)
4805 {
4806 GdkDevice *dev = gdk_seat_get_keyboard (seat: s->data);
4807 GdkModifierType mask;
4808
4809 mask = gdk_device_get_modifier_state (device: dev);
4810 if ((mask & gtk_accelerator_get_default_mod_mask ()) == GDK_ALT_MASK)
4811 {
4812 retval = TRUE;
4813 break;
4814 }
4815 }
4816
4817 g_list_free (list: seats);
4818
4819 return retval;
4820}
4821
4822static gboolean
4823gtk_window_handle_focus (GtkWidget *widget,
4824 GdkEvent *event,
4825 double x,
4826 double y)
4827{
4828 GtkWindow *window = GTK_WINDOW (widget);
4829
4830 if (gdk_event_get_event_type (event) != GDK_FOCUS_CHANGE)
4831 return FALSE;
4832
4833 if (gdk_focus_event_get_in (event))
4834 {
4835 _gtk_window_set_is_active (window, TRUE);
4836
4837 if (gtk_window_has_mnemonic_modifier_pressed (window))
4838 _gtk_window_schedule_mnemonics_visible (window);
4839 }
4840 else
4841 {
4842 _gtk_window_set_is_active (window, FALSE);
4843
4844 gtk_window_set_mnemonics_visible (window, FALSE);
4845 }
4846
4847 return TRUE;
4848}
4849
4850static void
4851update_mnemonics_visible (GtkWindow *window,
4852 guint keyval,
4853 GdkModifierType state,
4854 gboolean visible)
4855{
4856 if ((keyval == GDK_KEY_Alt_L || keyval == GDK_KEY_Alt_R) &&
4857 ((state & (gtk_accelerator_get_default_mod_mask ()) & ~(GDK_ALT_MASK)) == 0))
4858 {
4859 if (visible)
4860 _gtk_window_schedule_mnemonics_visible (window);
4861 else
4862 gtk_window_set_mnemonics_visible (window, FALSE);
4863 }
4864}
4865
4866void
4867_gtk_window_update_focus_visible (GtkWindow *window,
4868 guint keyval,
4869 GdkModifierType state,
4870 gboolean visible)
4871{
4872 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
4873
4874 if (visible)
4875 {
4876 if (priv->focus_visible)
4877 priv->key_press_focus = NULL;
4878 else
4879 priv->key_press_focus = priv->focus_widget;
4880
4881 if ((keyval == GDK_KEY_Alt_L || keyval == GDK_KEY_Alt_R) &&
4882 ((state & (gtk_accelerator_get_default_mod_mask ()) & ~(GDK_ALT_MASK)) == 0))
4883 gtk_window_set_focus_visible (window, TRUE);
4884 }
4885 else
4886 {
4887 if (priv->key_press_focus == priv->focus_widget)
4888 gtk_window_set_focus_visible (window, FALSE);
4889 else
4890 gtk_window_set_focus_visible (window, TRUE);
4891
4892 priv->key_press_focus = NULL;
4893 }
4894}
4895
4896static gboolean
4897gtk_window_key_pressed (GtkWidget *widget,
4898 guint keyval,
4899 guint keycode,
4900 GdkModifierType state,
4901 gpointer data)
4902{
4903 GtkWindow *window = GTK_WINDOW (widget);
4904
4905 _gtk_window_update_focus_visible (window, keyval, state, TRUE);
4906 update_mnemonics_visible (window, keyval, state, TRUE);
4907
4908 return FALSE;
4909}
4910
4911static gboolean
4912gtk_window_key_released (GtkWidget *widget,
4913 guint keyval,
4914 guint keycode,
4915 GdkModifierType state,
4916 gpointer data)
4917{
4918 GtkWindow *window = GTK_WINDOW (widget);
4919
4920 _gtk_window_update_focus_visible (window, keyval, state, FALSE);
4921 update_mnemonics_visible (window, keyval, state, FALSE);
4922
4923 return FALSE;
4924}
4925
4926static gboolean
4927gtk_window_focus (GtkWidget *widget,
4928 GtkDirectionType direction)
4929{
4930 GtkWindow *window = GTK_WINDOW (widget);
4931 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
4932 GtkWidget *child;
4933 GtkWidget *old_focus_child;
4934 GtkWidget *parent;
4935
4936 old_focus_child = gtk_widget_get_focus_child (widget);
4937
4938 /* We need a special implementation here to deal properly with wrapping
4939 * around in the tab chain without the danger of going into an
4940 * infinite loop.
4941 */
4942 if (old_focus_child)
4943 {
4944 if (gtk_widget_child_focus (widget: old_focus_child, direction))
4945 return TRUE;
4946 }
4947
4948 if (priv->focus_widget)
4949 {
4950 if (direction == GTK_DIR_LEFT ||
4951 direction == GTK_DIR_RIGHT ||
4952 direction == GTK_DIR_UP ||
4953 direction == GTK_DIR_DOWN)
4954 {
4955 return FALSE;
4956 }
4957
4958 /* Wrapped off the end, clear the focus setting for the toplpevel */
4959 parent = _gtk_widget_get_parent (widget: priv->focus_widget);
4960 while (parent)
4961 {
4962 gtk_widget_set_focus_child (widget: parent, NULL);
4963 parent = _gtk_widget_get_parent (widget: parent);
4964 }
4965
4966 gtk_window_set_focus (window, NULL);
4967 }
4968
4969 /* Now try to focus the first widget in the window,
4970 * taking care to hook titlebar widgets into the
4971 * focus chain.
4972 */
4973 if (priv->title_box != NULL &&
4974 old_focus_child != NULL &&
4975 priv->title_box != old_focus_child)
4976 child = priv->title_box;
4977 else
4978 child = priv->child;
4979
4980 if (child)
4981 {
4982 if (gtk_widget_child_focus (widget: child, direction))
4983 return TRUE;
4984 else if (priv->title_box != NULL &&
4985 priv->title_box != child &&
4986 gtk_widget_child_focus (widget: priv->title_box, direction))
4987 return TRUE;
4988 else if (priv->title_box == child &&
4989 gtk_widget_child_focus (widget: priv->child, direction))
4990 return TRUE;
4991 }
4992
4993 return FALSE;
4994}
4995
4996static void
4997gtk_window_move_focus (GtkWidget *widget,
4998 GtkDirectionType dir)
4999{
5000 gtk_widget_child_focus (widget, direction: dir);
5001
5002 if (!gtk_widget_get_focus_child (widget))
5003 gtk_window_set_focus (GTK_WINDOW (widget), NULL);
5004}
5005
5006void
5007check_crossing_invariants (GtkWidget *widget,
5008 GtkCrossingData *crossing)
5009{
5010#ifdef G_ENBABLE_DEBUG
5011 if (crossing->old_target == NULL)
5012 g_assert (crossing->old_descendent == NULL);
5013 else if (crossing->old_descendent == NULL)
5014 g_assert (crossing->old_target == widget || !gtk_widget_is_ancestor (crossing->old_target, widget));
5015 else
5016 {
5017 g_assert (gtk_widget_get_parent (crossing->old_descendent) == widget);
5018 g_assert (gtk_widget_is_ancestor (crossing->old_descendent, widget));
5019 g_assert (crossing->old_target == crossing->old_descendent || gtk_widget_is_ancestor (crossing->old_target, crossing->old_descendent));
5020 }
5021 if (crossing->new_target == NULL)
5022 g_assert (crossing->new_descendent == NULL);
5023 else if (crossing->new_descendent == NULL)
5024 g_assert (crossing->new_target == widget || !gtk_widget_is_ancestor (crossing->new_target, widget));
5025 else
5026 {
5027 g_assert (gtk_widget_get_parent (crossing->new_descendent) == widget);
5028 g_assert (gtk_widget_is_ancestor (crossing->new_descendent, widget));
5029 g_assert (crossing->new_target == crossing->new_descendent || gtk_widget_is_ancestor (crossing->new_target, crossing->new_descendent));
5030 }
5031#endif
5032}
5033
5034static void
5035synthesize_focus_change_events (GtkWindow *window,
5036 GtkWidget *old_focus,
5037 GtkWidget *new_focus,
5038 GtkCrossingType type)
5039{
5040 GtkCrossingData crossing;
5041 GtkWidget *ancestor;
5042 GtkWidget *widget, *focus_child;
5043 GList *list, *l;
5044 GtkStateFlags flags;
5045 GtkWidget *prev;
5046 gboolean seen_ancestor;
5047
5048 if (old_focus == new_focus)
5049 return;
5050
5051 if (old_focus && new_focus)
5052 ancestor = gtk_widget_common_ancestor (widget_a: old_focus, widget_b: new_focus);
5053 else
5054 ancestor = NULL;
5055
5056 flags = GTK_STATE_FLAG_FOCUSED | GTK_STATE_FLAG_FOCUS_WITHIN;
5057 if (gtk_window_get_focus_visible (GTK_WINDOW (window)))
5058 flags |= GTK_STATE_FLAG_FOCUS_VISIBLE;
5059
5060 crossing.type = type;
5061 crossing.mode = GDK_CROSSING_NORMAL;
5062 crossing.old_target = old_focus;
5063 crossing.old_descendent = NULL;
5064 crossing.new_target = new_focus;
5065 crossing.new_descendent = NULL;
5066
5067 crossing.direction = GTK_CROSSING_OUT;
5068
5069 prev = NULL;
5070 seen_ancestor = FALSE;
5071 widget = old_focus;
5072 while (widget)
5073 {
5074 crossing.old_descendent = prev;
5075 if (seen_ancestor)
5076 {
5077 crossing.new_descendent = new_focus ? prev : NULL;
5078 }
5079 else if (widget == ancestor)
5080 {
5081 GtkWidget *w;
5082
5083 crossing.new_descendent = NULL;
5084 for (w = new_focus; w != ancestor; w = gtk_widget_get_parent (widget: w))
5085 crossing.new_descendent = w;
5086
5087 seen_ancestor = TRUE;
5088 }
5089 else
5090 {
5091 crossing.new_descendent = NULL;
5092 }
5093
5094 check_crossing_invariants (widget, crossing: &crossing);
5095 gtk_widget_handle_crossing (widget, crossing: &crossing, x: 0, y: 0);
5096 gtk_widget_unset_state_flags (widget, flags);
5097 gtk_widget_set_focus_child (widget, NULL);
5098 prev = widget;
5099 widget = gtk_widget_get_parent (widget);
5100
5101 flags = flags & ~GTK_STATE_FLAG_FOCUSED;
5102 }
5103
5104 flags = GTK_STATE_FLAG_FOCUS_WITHIN;
5105 if (gtk_window_get_focus_visible (GTK_WINDOW (window)))
5106 flags |= GTK_STATE_FLAG_FOCUS_VISIBLE;
5107
5108 list = NULL;
5109 for (widget = new_focus; widget; widget = gtk_widget_get_parent (widget))
5110 list = g_list_prepend (list, data: widget);
5111
5112 crossing.direction = GTK_CROSSING_IN;
5113
5114 seen_ancestor = FALSE;
5115 for (l = list; l; l = l->next)
5116 {
5117 widget = l->data;
5118 if (l->next)
5119 focus_child = l->next->data;
5120 else
5121 focus_child = NULL;
5122
5123 crossing.new_descendent = focus_child;
5124 if (seen_ancestor)
5125 {
5126 crossing.old_descendent = NULL;
5127 }
5128 else if (widget == ancestor)
5129 {
5130 GtkWidget *w;
5131
5132 crossing.old_descendent = NULL;
5133 for (w = old_focus; w != ancestor; w = gtk_widget_get_parent (widget: w))
5134 {
5135 crossing.old_descendent = w;
5136 }
5137
5138 seen_ancestor = TRUE;
5139 }
5140 else
5141 {
5142 crossing.old_descendent = old_focus ? focus_child : NULL;
5143 }
5144 check_crossing_invariants (widget, crossing: &crossing);
5145 gtk_widget_handle_crossing (widget, crossing: &crossing, x: 0, y: 0);
5146
5147 if (l->next == NULL)
5148 flags = flags | GTK_STATE_FLAG_FOCUSED;
5149
5150 gtk_widget_set_state_flags (widget, flags, FALSE);
5151 gtk_widget_set_focus_child (widget, child: focus_child);
5152 }
5153
5154 g_list_free (list);
5155}
5156
5157/**
5158 * gtk_window_set_focus: (attributes org.gtk.Method.set_property=focus-widget)
5159 * @window: a `GtkWindow`
5160 * @focus: (nullable): widget to be the new focus widget, or %NULL to unset
5161 * any focus widget for the toplevel window.
5162 *
5163 * Sets the focus widget.
5164 *
5165 * If @focus is not the current focus widget, and is focusable,
5166 * sets it as the focus widget for the window. If @focus is %NULL,
5167 * unsets the focus widget for this window. To set the focus to a
5168 * particular widget in the toplevel, it is usually more convenient
5169 * to use [method@Gtk.Widget.grab_focus] instead of this function.
5170 */
5171void
5172gtk_window_set_focus (GtkWindow *window,
5173 GtkWidget *focus)
5174{
5175 g_return_if_fail (GTK_IS_WINDOW (window));
5176
5177 if (focus)
5178 gtk_widget_grab_focus (widget: focus);
5179 else
5180 gtk_window_root_set_focus (root: GTK_ROOT (ptr: window), NULL);
5181}
5182
5183static void
5184gtk_window_css_changed (GtkWidget *widget,
5185 GtkCssStyleChange *change)
5186{
5187 GtkWindow *window = GTK_WINDOW (widget);
5188
5189 GTK_WIDGET_CLASS (gtk_window_parent_class)->css_changed (widget, change);
5190
5191 if (!_gtk_widget_get_alloc_needed (widget) &&
5192 (change == NULL || gtk_css_style_change_changes_property (change, id: GTK_CSS_PROPERTY_BACKGROUND_COLOR)))
5193 update_opaque_region (window);
5194}
5195
5196/*
5197 * _gtk_window_unset_focus_and_default:
5198 * @window: a `GtkWindow`
5199 * @widget: a widget inside of @window
5200 *
5201 * Checks whether the focus and default widgets of @window are
5202 * @widget or a descendent of @widget, and if so, unset them.
5203 */
5204void
5205_gtk_window_unset_focus_and_default (GtkWindow *window,
5206 GtkWidget *widget)
5207
5208{
5209 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
5210 GtkWidget *child;
5211
5212 child = priv->focus_widget;
5213 if (child && (child == widget || gtk_widget_is_ancestor (widget: child, ancestor: widget)))
5214 {
5215 priv->move_focus_widget = g_object_ref (widget);
5216 priv->move_focus = TRUE;
5217 }
5218
5219 child = priv->default_widget;
5220 if (child && (child == widget || gtk_widget_is_ancestor (widget: child, ancestor: widget)))
5221 priv->unset_default = TRUE;
5222
5223 if ((priv->move_focus || priv->unset_default) &&
5224 priv->surface != NULL)
5225 {
5226 GdkFrameClock *frame_clock;
5227
5228 frame_clock = gdk_surface_get_frame_clock (surface: priv->surface);
5229 gdk_frame_clock_request_phase (frame_clock,
5230 phase: GDK_FRAME_CLOCK_PHASE_AFTER_PAINT);
5231 }
5232}
5233
5234#undef INCLUDE_CSD_SIZE
5235#undef EXCLUDE_CSD_SIZE
5236
5237/**
5238 * gtk_window_present:
5239 * @window: a `GtkWindow`
5240 *
5241 * Presents a window to the user.
5242 *
5243 * This function should not be used as when it is called,
5244 * it is too late to gather a valid timestamp to allow focus
5245 * stealing prevention to work correctly.
5246 */
5247void
5248gtk_window_present (GtkWindow *window)
5249{
5250 gtk_window_present_with_time (window, GDK_CURRENT_TIME);
5251}
5252
5253/**
5254 * gtk_window_present_with_time:
5255 * @window: a `GtkWindow`
5256 * @timestamp: the timestamp of the user interaction (typically a
5257 * button or key press event) which triggered this call
5258 *
5259 * Presents a window to the user.
5260 *
5261 * This may mean raising the window in the stacking order,
5262 * unminimizing it, moving it to the current desktop, and/or
5263 * giving it the keyboard focus, possibly dependent on the user’s
5264 * platform, window manager, and preferences.
5265 *
5266 * If @window is hidden, this function calls [method@Gtk.Widget.show]
5267 * as well.
5268 *
5269 * This function should be used when the user tries to open a window
5270 * that’s already open. Say for example the preferences dialog is
5271 * currently open, and the user chooses Preferences from the menu
5272 * a second time; use [method@Gtk.Window.present] to move the
5273 * already-open dialog where the user can see it.
5274 *
5275 * Presents a window to the user in response to a user interaction.
5276 * The timestamp should be gathered when the window was requested
5277 * to be shown (when clicking a link for example), rather than once
5278 * the window is ready to be shown.
5279 */
5280void
5281gtk_window_present_with_time (GtkWindow *window,
5282 guint32 timestamp)
5283{
5284 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
5285 GtkWidget *widget;
5286 GdkSurface *surface;
5287
5288 g_return_if_fail (GTK_IS_WINDOW (window));
5289
5290 widget = GTK_WIDGET (window);
5291
5292 if (gtk_widget_get_visible (widget))
5293 {
5294 surface = priv->surface;
5295
5296 g_assert (surface != NULL);
5297
5298 /* Translate a timestamp of GDK_CURRENT_TIME appropriately */
5299 if (timestamp == GDK_CURRENT_TIME)
5300 {
5301#ifdef GDK_WINDOWING_X11
5302 if (GDK_IS_X11_SURFACE (surface))
5303 {
5304 GdkDisplay *display;
5305
5306 display = gtk_widget_get_display (widget);
5307 timestamp = gdk_x11_display_get_user_time (display);
5308 }
5309 else
5310#endif
5311 timestamp = gtk_get_current_event_time ();
5312 }
5313 }
5314 else
5315 {
5316 priv->initial_timestamp = timestamp;
5317 gtk_widget_show (widget);
5318 }
5319
5320 g_assert (priv->surface != NULL);
5321 gdk_toplevel_focus (toplevel: GDK_TOPLEVEL (ptr: priv->surface), timestamp);
5322}
5323
5324/**
5325 * gtk_window_minimize:
5326 * @window: a `GtkWindow`
5327 *
5328 * Asks to minimize the specified @window.
5329 *
5330 * Note that you shouldn’t assume the window is definitely minimized
5331 * afterward, because the windowing system might not support this
5332 * functionality; other entities (e.g. the user or the window manager
5333 * could unminimize it again, or there may not be a window manager in
5334 * which case minimization isn’t possible, etc.
5335 *
5336 * It’s permitted to call this function before showing a window,
5337 * in which case the window will be minimized before it ever appears
5338 * onscreen.
5339 *
5340 * You can track result of this operation via the
5341 * [property@Gdk.Toplevel:state] property.
5342 */
5343void
5344gtk_window_minimize (GtkWindow *window)
5345{
5346 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
5347
5348 g_return_if_fail (GTK_IS_WINDOW (window));
5349
5350 priv->minimize_initially = TRUE;
5351
5352 if (priv->surface)
5353 gdk_toplevel_minimize (toplevel: GDK_TOPLEVEL (ptr: priv->surface));
5354}
5355
5356/**
5357 * gtk_window_unminimize:
5358 * @window: a `GtkWindow`
5359 *
5360 * Asks to unminimize the specified @window.
5361 *
5362 * Note that you shouldn’t assume the window is definitely unminimized
5363 * afterward, because the windowing system might not support this
5364 * functionality; other entities (e.g. the user or the window manager
5365 * could minimize it again, or there may not be a window manager in
5366 * which case minimization isn’t possible, etc.
5367 *
5368 * You can track result of this operation via the
5369 * [property@Gdk.Toplevel:state] property.
5370 */
5371void
5372gtk_window_unminimize (GtkWindow *window)
5373{
5374 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
5375
5376 g_return_if_fail (GTK_IS_WINDOW (window));
5377
5378 priv->minimize_initially = FALSE;
5379
5380 gtk_window_update_toplevel (window,
5381 layout: gtk_window_compute_base_layout (window));
5382}
5383
5384/**
5385 * gtk_window_maximize:
5386 * @window: a `GtkWindow`
5387 *
5388 * Asks to maximize @window, so that it fills the screen.
5389 *
5390 * Note that you shouldn’t assume the window is definitely maximized
5391 * afterward, because other entities (e.g. the user or window manager
5392 * could unmaximize it again, and not all window managers support
5393 * maximization.
5394 *
5395 * It’s permitted to call this function before showing a window,
5396 * in which case the window will be maximized when it appears onscreen
5397 * initially.
5398 *
5399 * You can track the result of this operation via the
5400 * [property@Gdk.Toplevel:state] property, or by listening to
5401 * notifications on the [property@Gtk.Window:maximized]
5402 * property.
5403 */
5404void
5405gtk_window_maximize (GtkWindow *window)
5406{
5407 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
5408
5409 g_return_if_fail (GTK_IS_WINDOW (window));
5410
5411 if (_gtk_widget_get_mapped (GTK_WIDGET (window)))
5412 {
5413 GdkToplevelLayout *layout;
5414
5415 layout = gtk_window_compute_base_layout (window);
5416 gdk_toplevel_layout_set_maximized (layout, TRUE);
5417 gtk_window_update_toplevel (window, layout);
5418 }
5419 else if (!priv->maximized)
5420 {
5421 priv->maximized = TRUE;
5422 g_object_notify_by_pspec (G_OBJECT (window), pspec: window_props[PROP_MAXIMIZED]);
5423 }
5424}
5425
5426/**
5427 * gtk_window_unmaximize:
5428 * @window: a `GtkWindow`
5429 *
5430 * Asks to unmaximize @window.
5431 *
5432 * Note that you shouldn’t assume the window is definitely unmaximized
5433 * afterward, because other entities (e.g. the user or window manager
5434 * maximize it again, and not all window managers honor requests to
5435 * unmaximize.
5436 *
5437 * You can track the result of this operation via the
5438 * [property@Gdk.Toplevel:state] property, or by listening to
5439 * notifications on the [property@Gtk.Window:maximized] property.
5440 */
5441void
5442gtk_window_unmaximize (GtkWindow *window)
5443{
5444 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
5445
5446 g_return_if_fail (GTK_IS_WINDOW (window));
5447
5448 if (_gtk_widget_get_mapped (GTK_WIDGET (window)))
5449 {
5450 GdkToplevelLayout *layout;
5451
5452 layout = gtk_window_compute_base_layout (window);
5453 gdk_toplevel_layout_set_maximized (layout, FALSE);
5454 gtk_window_update_toplevel (window, layout);
5455 }
5456 else if (priv->maximized)
5457 {
5458 priv->maximized = FALSE;
5459 g_object_notify_by_pspec (G_OBJECT (window), pspec: window_props[PROP_MAXIMIZED]);
5460 }
5461}
5462
5463static void
5464unset_fullscreen_monitor (GtkWindow *window)
5465{
5466 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
5467
5468 if (priv->initial_fullscreen_monitor)
5469 {
5470 g_signal_handlers_disconnect_by_func (priv->initial_fullscreen_monitor, unset_fullscreen_monitor, window);
5471 g_object_unref (object: priv->initial_fullscreen_monitor);
5472 priv->initial_fullscreen_monitor = NULL;
5473 }
5474}
5475
5476/**
5477 * gtk_window_fullscreen:
5478 * @window: a `GtkWindow`
5479 *
5480 * Asks to place @window in the fullscreen state.
5481 *
5482 * Note that you shouldn’t assume the window is definitely fullscreen
5483 * afterward, because other entities (e.g. the user or window manager
5484 * unfullscreen it again, and not all window managers honor requests
5485 * to fullscreen windows.
5486 *
5487 * You can track the result of this operation via the
5488 * [property@Gdk.Toplevel:state] property, or by listening to
5489 * notifications of the [property@Gtk.Window:fullscreened] property.
5490 */
5491void
5492gtk_window_fullscreen (GtkWindow *window)
5493{
5494 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
5495
5496 g_return_if_fail (GTK_IS_WINDOW (window));
5497
5498 unset_fullscreen_monitor (window);
5499
5500 if (_gtk_widget_get_mapped (GTK_WIDGET (window)))
5501 {
5502 GdkToplevelLayout *layout;
5503
5504 layout = gtk_window_compute_base_layout (window);
5505 gdk_toplevel_layout_set_fullscreen (layout, TRUE, NULL);
5506 gtk_window_update_toplevel (window, layout);
5507 }
5508 else if (!priv->fullscreen)
5509 {
5510 priv->fullscreen = TRUE;
5511 g_object_notify_by_pspec (G_OBJECT (window), pspec: window_props[PROP_FULLSCREENED]);
5512 }
5513}
5514
5515/**
5516 * gtk_window_fullscreen_on_monitor:
5517 * @window: a `GtkWindow`
5518 * @monitor: which monitor to go fullscreen on
5519 *
5520 * Asks to place @window in the fullscreen state on the given @monitor.
5521 *
5522 * Note that you shouldn't assume the window is definitely fullscreen
5523 * afterward, or that the windowing system allows fullscreen windows on
5524 * any given monitor.
5525 *
5526 * You can track the result of this operation via the
5527 * [property@Gdk.Toplevel:state] property, or by listening to
5528 * notifications of the [property@Gtk.Window:fullscreened] property.
5529 */
5530void
5531gtk_window_fullscreen_on_monitor (GtkWindow *window,
5532 GdkMonitor *monitor)
5533{
5534 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
5535
5536 g_return_if_fail (GTK_IS_WINDOW (window));
5537 g_return_if_fail (GDK_IS_MONITOR (monitor));
5538 g_return_if_fail (gdk_monitor_is_valid (monitor));
5539
5540 gtk_window_set_display (window, display: gdk_monitor_get_display (monitor));
5541
5542 unset_fullscreen_monitor (window);
5543 priv->initial_fullscreen_monitor = monitor;
5544 g_signal_connect_swapped (priv->initial_fullscreen_monitor, "invalidate",
5545 G_CALLBACK (unset_fullscreen_monitor), window);
5546 g_object_ref (priv->initial_fullscreen_monitor);
5547
5548 if (_gtk_widget_get_mapped (GTK_WIDGET (window)))
5549 {
5550 GdkToplevelLayout *layout;
5551
5552 layout = gtk_window_compute_base_layout (window);
5553 gdk_toplevel_layout_set_fullscreen (layout, TRUE, monitor);
5554 gtk_window_update_toplevel (window, layout);
5555 }
5556 else if (!priv->fullscreen)
5557 {
5558 priv->fullscreen = TRUE;
5559 g_object_notify_by_pspec (G_OBJECT (window), pspec: window_props[PROP_FULLSCREENED]);
5560 }
5561}
5562
5563/**
5564 * gtk_window_unfullscreen:
5565 * @window: a `GtkWindow`
5566 *
5567 * Asks to remove the fullscreen state for @window, and return to
5568 * its previous state.
5569 *
5570 * Note that you shouldn’t assume the window is definitely not
5571 * fullscreen afterward, because other entities (e.g. the user or
5572 * window manager could fullscreen it again, and not all window
5573 * managers honor requests to unfullscreen windows; normally the
5574 * window will end up restored to its normal state. Just don’t
5575 * write code that crashes if not.
5576 *
5577 * You can track the result of this operation via the
5578 * [property@Gdk.Toplevel:state] property, or by listening to
5579 * notifications of the [property@Gtk.Window:fullscreened] property.
5580 */
5581void
5582gtk_window_unfullscreen (GtkWindow *window)
5583{
5584 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
5585
5586 g_return_if_fail (GTK_IS_WINDOW (window));
5587
5588 unset_fullscreen_monitor (window);
5589
5590 if (_gtk_widget_get_mapped (GTK_WIDGET (window)))
5591 {
5592 GdkToplevelLayout *layout;
5593
5594 layout = gtk_window_compute_base_layout (window);
5595 gdk_toplevel_layout_set_fullscreen (layout, FALSE, NULL);
5596 gtk_window_update_toplevel (window, layout);
5597 }
5598 else if (priv->fullscreen)
5599 {
5600 priv->fullscreen = FALSE;
5601 g_object_notify_by_pspec (G_OBJECT (window), pspec: window_props[PROP_FULLSCREENED]);
5602 }
5603}
5604
5605/**
5606 * gtk_window_set_resizable: (attributes org.gtk.Method.set_property=resizable)
5607 * @window: a `GtkWindow`
5608 * @resizable: %TRUE if the user can resize this window
5609 *
5610 * Sets whether the user can resize a window.
5611 *
5612 * Windows are user resizable by default.
5613 **/
5614void
5615gtk_window_set_resizable (GtkWindow *window,
5616 gboolean resizable)
5617{
5618 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
5619
5620 g_return_if_fail (GTK_IS_WINDOW (window));
5621
5622 resizable = (resizable != FALSE);
5623
5624 if (priv->resizable != resizable)
5625 {
5626 priv->resizable = resizable;
5627
5628 update_window_actions (window);
5629
5630 gtk_window_update_toplevel (window,
5631 layout: gtk_window_compute_base_layout (window));
5632
5633 gtk_widget_queue_resize (GTK_WIDGET (window));
5634
5635 g_object_notify_by_pspec (G_OBJECT (window), pspec: window_props[PROP_RESIZABLE]);
5636 }
5637}
5638
5639/**
5640 * gtk_window_get_resizable: (attributes org.gtk.Method.get_property=resizable)
5641 * @window: a `GtkWindow`
5642 *
5643 * Gets the value set by gtk_window_set_resizable().
5644 *
5645 * Returns: %TRUE if the user can resize the window
5646 **/
5647gboolean
5648gtk_window_get_resizable (GtkWindow *window)
5649{
5650 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
5651
5652 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
5653
5654 return priv->resizable;
5655}
5656
5657/**
5658 * gtk_window_set_display: (attributes org.gtk.Method.set_property=display)
5659 * @window: a `GtkWindow`
5660 * @display: a `GdkDisplay`
5661 *
5662 * Sets the `GdkDisplay` where the @window is displayed.
5663 *
5664 * If the window is already mapped, it will be unmapped,
5665 * and then remapped on the new display.
5666 */
5667void
5668gtk_window_set_display (GtkWindow *window,
5669 GdkDisplay *display)
5670{
5671 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
5672 GtkWidget *widget;
5673 gboolean was_mapped;
5674
5675 g_return_if_fail (GTK_IS_WINDOW (window));
5676 g_return_if_fail (GDK_IS_DISPLAY (display));
5677
5678 if (display == priv->display)
5679 return;
5680
5681 /* reset initial_fullscreen_monitor since they are relative to the screen */
5682 unset_fullscreen_monitor (window);
5683
5684 widget = GTK_WIDGET (window);
5685
5686 was_mapped = _gtk_widget_get_mapped (widget);
5687
5688 if (was_mapped)
5689 gtk_widget_unmap (widget);
5690 if (_gtk_widget_get_realized (widget))
5691 gtk_widget_unrealize (widget);
5692
5693 if (priv->transient_parent && gtk_widget_get_display (GTK_WIDGET (priv->transient_parent)) != display)
5694 gtk_window_set_transient_for (window, NULL);
5695
5696#ifdef GDK_WINDOWING_X11
5697 g_signal_handlers_disconnect_by_func (gtk_settings_get_for_display (priv->display),
5698 gtk_window_on_theme_variant_changed, window);
5699 g_signal_connect (gtk_settings_get_for_display (display),
5700 "notify::gtk-application-prefer-dark-theme",
5701 G_CALLBACK (gtk_window_on_theme_variant_changed), window);
5702#endif
5703
5704 gtk_widget_unroot (widget);
5705 priv->display = display;
5706
5707 gtk_widget_root (widget);
5708
5709 g_object_notify_by_pspec (G_OBJECT (window), pspec: window_props[PROP_DISPLAY]);
5710
5711 if (was_mapped)
5712 gtk_widget_map (widget);
5713
5714 check_scale_changed (window);
5715
5716 gtk_widget_system_setting_changed (GTK_WIDGET (window), setting: GTK_SYSTEM_SETTING_DISPLAY);
5717}
5718
5719static void
5720gtk_window_set_theme_variant (GtkWindow *window)
5721{
5722#ifdef GDK_WINDOWING_X11
5723 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
5724 gboolean dark_theme_requested;
5725
5726 g_object_get (object: gtk_settings_get_for_display (display: priv->display),
5727 first_property_name: "gtk-application-prefer-dark-theme", &dark_theme_requested,
5728 NULL);
5729
5730 if (GDK_IS_X11_SURFACE (priv->surface))
5731 gdk_x11_surface_set_theme_variant (surface: priv->surface,
5732 variant: dark_theme_requested ? "dark" : NULL);
5733#endif
5734}
5735
5736#ifdef GDK_WINDOWING_X11
5737static void
5738gtk_window_on_theme_variant_changed (GtkSettings *settings,
5739 GParamSpec *pspec,
5740 GtkWindow *window)
5741{
5742 gtk_window_set_theme_variant (window);
5743}
5744#endif
5745
5746/**
5747 * gtk_window_is_active: (attributes org.gtk.Method.get_property=is-active)
5748 * @window: a `GtkWindow`
5749 *
5750 * Returns whether the window is part of the current active toplevel.
5751 *
5752 * The active toplevel is the window receiving keystrokes.
5753 *
5754 * The return value is %TRUE if the window is active toplevel itself.
5755 * You might use this function if you wanted to draw a widget
5756 * differently in an active window from a widget in an inactive window.
5757 *
5758 * Returns: %TRUE if the window part of the current active window.
5759 */
5760gboolean
5761gtk_window_is_active (GtkWindow *window)
5762{
5763 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
5764
5765 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
5766
5767 return priv->is_active;
5768}
5769
5770/**
5771 * gtk_window_get_group:
5772 * @window: (nullable): a `GtkWindow`
5773 *
5774 * Returns the group for @window.
5775 *
5776 * If the window has no group, then the default group is returned.
5777 *
5778 * Returns: (transfer none): the `GtkWindowGroup` for a window
5779 * or the default group
5780 */
5781GtkWindowGroup *
5782gtk_window_get_group (GtkWindow *window)
5783{
5784 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
5785
5786 if (window && priv->group)
5787 return priv->group;
5788 else
5789 {
5790 static GtkWindowGroup *default_group = NULL;
5791
5792 if (!default_group)
5793 default_group = gtk_window_group_new ();
5794
5795 return default_group;
5796 }
5797}
5798
5799/**
5800 * gtk_window_has_group:
5801 * @window: a `GtkWindow`
5802 *
5803 * Returns whether @window has an explicit window group.
5804 *
5805 * Returns: %TRUE if @window has an explicit window group.
5806 */
5807gboolean
5808gtk_window_has_group (GtkWindow *window)
5809{
5810 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
5811
5812 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
5813
5814 return priv->group != NULL;
5815}
5816
5817GtkWindowGroup *
5818_gtk_window_get_window_group (GtkWindow *window)
5819{
5820 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
5821
5822 return priv->group;
5823}
5824
5825void
5826_gtk_window_set_window_group (GtkWindow *window,
5827 GtkWindowGroup *group)
5828{
5829 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
5830
5831 priv->group = group;
5832}
5833
5834static gboolean
5835gtk_window_activate_menubar (GtkWidget *widget,
5836 GVariant *args,
5837 gpointer unused)
5838{
5839 GtkWindow *window = GTK_WINDOW (widget);
5840 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
5841 GList *tmp_menubars, *l;
5842 GPtrArray *menubars;
5843 GtkWidget *focus;
5844 GtkWidget *first;
5845
5846 tmp_menubars = gtk_popover_menu_bar_get_viewable_menu_bars (window);
5847 if (tmp_menubars == NULL)
5848 {
5849 focus = gtk_window_get_focus (window);
5850 return priv->title_box != NULL &&
5851 (focus == NULL || !gtk_widget_is_ancestor (widget: focus, ancestor: priv->title_box)) &&
5852 gtk_widget_child_focus (widget: priv->title_box, direction: GTK_DIR_TAB_FORWARD);
5853 }
5854
5855 menubars = g_ptr_array_sized_new (reserved_size: g_list_length (list: tmp_menubars));;
5856 for (l = tmp_menubars; l; l = l->next)
5857 g_ptr_array_add (array: menubars, data: l->data);
5858
5859 g_list_free (list: tmp_menubars);
5860
5861 gtk_widget_focus_sort (GTK_WIDGET (window), direction: GTK_DIR_TAB_FORWARD, focus_order: menubars);
5862
5863 first = g_ptr_array_index (menubars, 0);
5864 if (GTK_IS_POPOVER_MENU_BAR (first))
5865 gtk_popover_menu_bar_select_first (GTK_POPOVER_MENU_BAR (first));
5866 else if (GTK_IS_MENU_BUTTON (first))
5867 gtk_menu_button_popup (GTK_MENU_BUTTON (first));
5868
5869 g_ptr_array_free (array: menubars, TRUE);
5870
5871 return TRUE;
5872}
5873
5874static void
5875gtk_window_keys_changed (GtkWindow *window)
5876{
5877}
5878
5879/*
5880 * _gtk_window_set_is_active:
5881 * @window: a `GtkWindow`
5882 * @is_active: %TRUE if the window is in the currently active toplevel
5883 *
5884 * Internal function that sets whether the `GtkWindow` is part
5885 * of the currently active toplevel window (taking into account
5886 * inter-process embedding.)
5887 */
5888static void
5889_gtk_window_set_is_active (GtkWindow *window,
5890 gboolean is_active)
5891{
5892 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
5893
5894 if (priv->is_active == is_active)
5895 return;
5896
5897 priv->is_active = is_active;
5898
5899 if (priv->focus_widget)
5900 {
5901 GtkWidget *focus;
5902
5903 focus = g_object_ref (priv->focus_widget);
5904
5905 if (is_active)
5906 {
5907 synthesize_focus_change_events (window, NULL, new_focus: focus, type: GTK_CROSSING_ACTIVE);
5908 gtk_widget_set_has_focus (widget: focus, TRUE);
5909 }
5910 else
5911 {
5912 synthesize_focus_change_events (window, old_focus: focus, NULL, type: GTK_CROSSING_ACTIVE);
5913 gtk_widget_set_has_focus (widget: focus, FALSE);
5914 }
5915
5916 g_object_unref (object: focus);
5917 }
5918
5919 gtk_accessible_platform_changed (self: GTK_ACCESSIBLE (ptr: window), change: GTK_ACCESSIBLE_PLATFORM_CHANGE_ACTIVE);
5920
5921 g_object_notify_by_pspec (G_OBJECT (window), pspec: window_props[PROP_IS_ACTIVE]);
5922}
5923
5924/**
5925 * gtk_window_set_auto_startup_notification:
5926 * @setting: %TRUE to automatically do startup notification
5927 *
5928 * Sets whether the window should request startup notification.
5929 *
5930 * By default, after showing the first `GtkWindow`, GTK calls
5931 * [method@Gdk.Display.notify_startup_complete]. Call this function
5932 * to disable the automatic startup notification. You might do this
5933 * if your first window is a splash screen, and you want to delay
5934 * notification until after your real main window has been shown,
5935 * for example.
5936 *
5937 * In that example, you would disable startup notification
5938 * temporarily, show your splash screen, then re-enable it so that
5939 * showing the main window would automatically result in notification.
5940 */
5941void
5942gtk_window_set_auto_startup_notification (gboolean setting)
5943{
5944 disable_startup_notification = !setting;
5945}
5946
5947/**
5948 * gtk_window_get_mnemonics_visible: (attributes org.gtk.Method.get_property=mnemonics-visible)
5949 * @window: a `GtkWindow`
5950 *
5951 * Gets whether mnemonics are supposed to be visible.
5952 *
5953 * Returns: %TRUE if mnemonics are supposed to be visible
5954 * in this window.
5955 */
5956gboolean
5957gtk_window_get_mnemonics_visible (GtkWindow *window)
5958{
5959 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
5960
5961 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
5962
5963 return priv->mnemonics_visible;
5964}
5965
5966/**
5967 * gtk_window_set_mnemonics_visible: (attributes org.gtk.Method.set_property=mnemonics-visible)
5968 * @window: a `GtkWindow`
5969 * @setting: the new value
5970 *
5971 * Sets whether mnemonics are supposed to be visible.
5972 */
5973void
5974gtk_window_set_mnemonics_visible (GtkWindow *window,
5975 gboolean setting)
5976{
5977 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
5978
5979 g_return_if_fail (GTK_IS_WINDOW (window));
5980
5981 setting = setting != FALSE;
5982
5983 if (priv->mnemonics_visible != setting)
5984 {
5985 priv->mnemonics_visible = setting;
5986 g_object_notify_by_pspec (G_OBJECT (window), pspec: window_props[PROP_MNEMONICS_VISIBLE]);
5987 }
5988
5989 if (priv->mnemonics_display_timeout_id)
5990 {
5991 g_source_remove (tag: priv->mnemonics_display_timeout_id);
5992 priv->mnemonics_display_timeout_id = 0;
5993 }
5994}
5995
5996static gboolean
5997schedule_mnemonics_visible_cb (gpointer data)
5998{
5999 GtkWindow *window = data;
6000 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
6001
6002 priv->mnemonics_display_timeout_id = 0;
6003
6004 gtk_window_set_mnemonics_visible (window, TRUE);
6005
6006 return FALSE;
6007}
6008
6009void
6010_gtk_window_schedule_mnemonics_visible (GtkWindow *window)
6011{
6012 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
6013
6014 g_return_if_fail (GTK_IS_WINDOW (window));
6015
6016 if (priv->mnemonics_display_timeout_id)
6017 return;
6018
6019 priv->mnemonics_display_timeout_id =
6020 g_timeout_add (MNEMONICS_DELAY, function: schedule_mnemonics_visible_cb, data: window);
6021 gdk_source_set_static_name_by_id (tag: priv->mnemonics_display_timeout_id, name: "[gtk] schedule_mnemonics_visible_cb");
6022}
6023
6024/**
6025 * gtk_window_get_focus_visible: (attributes org.gtk.Method.get_property=focus-visible)
6026 * @window: a `GtkWindow`
6027 *
6028 * Gets whether “focus rectangles” are supposed to be visible.
6029 *
6030 * Returns: %TRUE if “focus rectangles” are supposed to be visible
6031 * in this window.
6032 */
6033gboolean
6034gtk_window_get_focus_visible (GtkWindow *window)
6035{
6036 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
6037
6038 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
6039
6040 return priv->focus_visible;
6041}
6042
6043static gboolean
6044unset_focus_visible (gpointer data)
6045{
6046 GtkWindow *window = data;
6047 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
6048
6049 priv->focus_visible_timeout = 0;
6050
6051 gtk_window_set_focus_visible (window, FALSE);
6052
6053 return G_SOURCE_REMOVE;
6054}
6055
6056/**
6057 * gtk_window_set_focus_visible: (attributes org.gtk.MEthod.set_property=focus-visible)
6058 * @window: a `GtkWindow`
6059 * @setting: the new value
6060 *
6061 * Sets whether “focus rectangles” are supposed to be visible.
6062 */
6063void
6064gtk_window_set_focus_visible (GtkWindow *window,
6065 gboolean setting)
6066{
6067 gboolean changed;
6068
6069 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
6070
6071 g_return_if_fail (GTK_IS_WINDOW (window));
6072
6073 changed = priv->focus_visible != setting;
6074
6075 priv->focus_visible = setting;
6076
6077 if (priv->focus_visible_timeout)
6078 {
6079 g_source_remove (tag: priv->focus_visible_timeout);
6080 priv->focus_visible_timeout = 0;
6081 }
6082
6083 if (priv->focus_visible)
6084 priv->focus_visible_timeout = g_timeout_add_seconds (VISIBLE_FOCUS_DURATION, function: unset_focus_visible, data: window);
6085
6086 if (changed)
6087 {
6088 if (priv->focus_widget)
6089 {
6090 GtkWidget *widget;
6091
6092 for (widget = priv->focus_widget; widget; widget = gtk_widget_get_parent (widget))
6093 {
6094 if (priv->focus_visible)
6095 gtk_widget_set_state_flags (widget, flags: GTK_STATE_FLAG_FOCUS_VISIBLE, FALSE);
6096 else
6097 gtk_widget_unset_state_flags (widget, flags: GTK_STATE_FLAG_FOCUS_VISIBLE);
6098 }
6099 }
6100 g_object_notify_by_pspec (G_OBJECT (window), pspec: window_props[PROP_FOCUS_VISIBLE]);
6101 }
6102}
6103
6104static void
6105ensure_state_flag_backdrop (GtkWidget *widget)
6106{
6107 GtkWindowPrivate *priv = gtk_window_get_instance_private (GTK_WINDOW (widget));
6108 gboolean surface_focused = TRUE;
6109
6110 surface_focused = gdk_toplevel_get_state (toplevel: GDK_TOPLEVEL (ptr: priv->surface)) & GDK_TOPLEVEL_STATE_FOCUSED;
6111
6112 if (!surface_focused)
6113 gtk_widget_set_state_flags (widget, flags: GTK_STATE_FLAG_BACKDROP, FALSE);
6114 else
6115 gtk_widget_unset_state_flags (widget, flags: GTK_STATE_FLAG_BACKDROP);
6116}
6117
6118static void set_warn_again (gboolean warn);
6119static void gtk_window_set_debugging (GdkDisplay *display,
6120 gboolean enable,
6121 gboolean toggle,
6122 gboolean select,
6123 gboolean warn);
6124
6125static void
6126warn_response (GtkDialog *dialog,
6127 int response)
6128{
6129 GtkWidget *check;
6130 gboolean remember;
6131 GtkWidget *inspector_window;
6132 GdkDisplay *display;
6133
6134 inspector_window = GTK_WIDGET (gtk_window_get_transient_for (GTK_WINDOW (dialog)));
6135 display = gtk_inspector_window_get_inspected_display (GTK_INSPECTOR_WINDOW (inspector_window));
6136
6137 check = g_object_get_data (G_OBJECT (dialog), key: "check");
6138 remember = gtk_check_button_get_active (GTK_CHECK_BUTTON (check));
6139
6140 gtk_window_destroy (GTK_WINDOW (dialog));
6141 g_object_set_data (G_OBJECT (inspector_window), key: "warning_dialog", NULL);
6142
6143 if (response == GTK_RESPONSE_NO)
6144 gtk_window_set_debugging (display, FALSE, FALSE, FALSE, FALSE);
6145 else
6146 set_warn_again (!remember);
6147}
6148
6149static void
6150gtk_window_set_debugging (GdkDisplay *display,
6151 gboolean enable,
6152 gboolean toggle,
6153 gboolean select,
6154 gboolean warn)
6155{
6156 GtkWidget *dialog = NULL;
6157 GtkWidget *area;
6158 GtkWidget *check;
6159 GtkWidget *inspector_window;
6160 gboolean was_debugging;
6161
6162 was_debugging = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (display), "-gtk-debugging-enabled"));
6163
6164 if (toggle)
6165 enable = !was_debugging;
6166
6167 g_object_set_data (G_OBJECT (display), key: "-gtk-debugging-enabled", GINT_TO_POINTER (enable));
6168
6169 if (enable)
6170 {
6171 inspector_window = gtk_inspector_window_get (display);
6172
6173 gtk_window_present (GTK_WINDOW (inspector_window));
6174
6175 if (warn)
6176 {
6177 dialog = gtk_message_dialog_new (GTK_WINDOW (inspector_window),
6178 flags: GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
6179 type: GTK_MESSAGE_QUESTION,
6180 buttons: GTK_BUTTONS_NONE,
6181 _("Do you want to use GTK Inspector?"));
6182 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
6183 _("GTK Inspector is an interactive debugger that lets you explore and "
6184 "modify the internals of any GTK application. Using it may cause the "
6185 "application to break or crash."));
6186
6187 area = gtk_message_dialog_get_message_area (GTK_MESSAGE_DIALOG (dialog));
6188 check = gtk_check_button_new_with_label (_("Don’t show this message again"));
6189 gtk_widget_set_margin_start (widget: check, margin: 10);
6190 gtk_widget_show (widget: check);
6191 gtk_box_append (GTK_BOX (area), child: check);
6192 g_object_set_data (G_OBJECT (dialog), key: "check", data: check);
6193 gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Cancel"), response_id: GTK_RESPONSE_NO);
6194 gtk_dialog_add_button (GTK_DIALOG (dialog), _("_OK"), response_id: GTK_RESPONSE_YES);
6195 g_signal_connect (dialog, "response", G_CALLBACK (warn_response), inspector_window);
6196 g_object_set_data (G_OBJECT (inspector_window), key: "warning_dialog", data: dialog);
6197
6198 gtk_widget_show (widget: dialog);
6199 }
6200
6201 if (select)
6202 gtk_inspector_window_select_widget_under_pointer (GTK_INSPECTOR_WINDOW (inspector_window));
6203 }
6204 else if (was_debugging)
6205 {
6206 inspector_window = gtk_inspector_window_get (display);
6207
6208 gtk_widget_hide (widget: inspector_window);
6209 }
6210}
6211
6212/**
6213 * gtk_window_set_interactive_debugging:
6214 * @enable: %TRUE to enable interactive debugging
6215 *
6216 * Opens or closes the [interactive debugger](running.html#interactive-debugging).
6217 *
6218 * The debugger offers access to the widget hierarchy of the application
6219 * and to useful debugging tools.
6220 */
6221void
6222gtk_window_set_interactive_debugging (gboolean enable)
6223{
6224 GdkDisplay *display = gdk_display_get_default ();
6225
6226 gtk_window_set_debugging (display, enable, FALSE, FALSE, FALSE);
6227}
6228
6229static gboolean
6230inspector_keybinding_enabled (gboolean *warn)
6231{
6232 GSettingsSchema *schema;
6233 GSettings *settings;
6234 gboolean enabled;
6235
6236 enabled = TRUE;
6237 *warn = TRUE;
6238
6239 schema = g_settings_schema_source_lookup (source: g_settings_schema_source_get_default (),
6240 schema_id: "org.gtk.gtk4.Settings.Debug",
6241 TRUE);
6242
6243 if (schema)
6244 {
6245 settings = g_settings_new_full (schema, NULL, NULL);
6246 enabled = g_settings_get_boolean (settings, key: "enable-inspector-keybinding");
6247 *warn = g_settings_get_boolean (settings, key: "inspector-warning");
6248 g_object_unref (object: settings);
6249 g_settings_schema_unref (schema);
6250 }
6251
6252 return enabled;
6253}
6254
6255static void
6256set_warn_again (gboolean warn)
6257{
6258 GSettingsSchema *schema;
6259 GSettings *settings;
6260
6261 schema = g_settings_schema_source_lookup (source: g_settings_schema_source_get_default (),
6262 schema_id: "org.gtk.gtk4.Settings.Debug",
6263 TRUE);
6264
6265 if (schema)
6266 {
6267 settings = g_settings_new_full (schema, NULL, NULL);
6268 g_settings_set_boolean (settings, key: "inspector-warning", value: warn);
6269 g_object_unref (object: settings);
6270 g_settings_schema_unref (schema);
6271 }
6272}
6273
6274static gboolean
6275gtk_window_enable_debugging (GtkWindow *window,
6276 gboolean toggle)
6277{
6278 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
6279 gboolean warn;
6280
6281 if (!inspector_keybinding_enabled (warn: &warn))
6282 return FALSE;
6283
6284 gtk_window_set_debugging (display: priv->display, TRUE, toggle, select: !toggle, warn);
6285
6286 return TRUE;
6287}
6288
6289#ifdef GDK_WINDOWING_WAYLAND
6290typedef struct {
6291 GtkWindow *window;
6292 GtkWindowHandleExported callback;
6293 gpointer user_data;
6294} WaylandSurfaceHandleExportedData;
6295
6296static void
6297wayland_surface_handle_exported (GdkToplevel *toplevel,
6298 const char *wayland_handle_str,
6299 gpointer user_data)
6300{
6301 WaylandSurfaceHandleExportedData *data = user_data;
6302 char *handle_str;
6303
6304 handle_str = g_strdup_printf (format: "wayland:%s", wayland_handle_str);
6305 data->callback (data->window, handle_str, data->user_data);
6306 g_free (mem: handle_str);
6307}
6308#endif
6309
6310gboolean
6311gtk_window_export_handle (GtkWindow *window,
6312 GtkWindowHandleExported callback,
6313 gpointer user_data)
6314{
6315 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
6316
6317#ifdef GDK_WINDOWING_X11
6318 if (GDK_IS_X11_DISPLAY (gtk_widget_get_display (GTK_WIDGET (window))))
6319 {
6320 char *handle_str;
6321 guint32 xid = (guint32) gdk_x11_surface_get_xid (surface: priv->surface);
6322
6323 handle_str = g_strdup_printf (format: "x11:%x", xid);
6324 callback (window, handle_str, user_data);
6325 g_free (mem: handle_str);
6326
6327 return TRUE;
6328 }
6329#endif
6330#ifdef GDK_WINDOWING_WAYLAND
6331 if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (GTK_WIDGET (window))))
6332 {
6333 WaylandSurfaceHandleExportedData *data;
6334
6335 data = g_new0 (WaylandSurfaceHandleExportedData, 1);
6336 data->window = window;
6337 data->callback = callback;
6338 data->user_data = user_data;
6339
6340 if (!gdk_wayland_toplevel_export_handle (toplevel: GDK_TOPLEVEL (ptr: priv->surface),
6341 callback: wayland_surface_handle_exported,
6342 user_data: data,
6343 destroy_func: g_free))
6344 {
6345 g_free (mem: data);
6346 return FALSE;
6347 }
6348 else
6349 {
6350 return TRUE;
6351 }
6352 }
6353#endif
6354
6355 g_warning ("Couldn't export handle for %s surface, unsupported windowing system",
6356 G_OBJECT_TYPE_NAME (priv->surface));
6357
6358 return FALSE;
6359}
6360
6361void
6362gtk_window_unexport_handle (GtkWindow *window)
6363{
6364 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
6365
6366#ifdef GDK_WINDOWING_WAYLAND
6367 if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (GTK_WIDGET (window))))
6368 {
6369 gdk_wayland_toplevel_unexport_handle (toplevel: GDK_TOPLEVEL (ptr: priv->surface));
6370 return;
6371 }
6372#endif
6373
6374 g_warning ("Couldn't unexport handle for %s surface, unsupported windowing system",
6375 G_OBJECT_TYPE_NAME (priv->surface));
6376}
6377
6378static GtkPointerFocus *
6379gtk_window_lookup_pointer_focus (GtkWindow *window,
6380 GdkDevice *device,
6381 GdkEventSequence *sequence)
6382{
6383 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
6384 GList *l;
6385
6386 for (l = priv->foci; l; l = l->next)
6387 {
6388 GtkPointerFocus *focus = l->data;
6389
6390 if (focus->device == device && focus->sequence == sequence)
6391 return focus;
6392 }
6393
6394 return NULL;
6395}
6396
6397GtkWidget *
6398gtk_window_lookup_pointer_focus_widget (GtkWindow *window,
6399 GdkDevice *device,
6400 GdkEventSequence *sequence)
6401{
6402 GtkPointerFocus *focus;
6403
6404 focus = gtk_window_lookup_pointer_focus (window, device, sequence);
6405 return focus ? gtk_pointer_focus_get_target (focus) : NULL;
6406}
6407
6408GtkWidget *
6409gtk_window_lookup_effective_pointer_focus_widget (GtkWindow *window,
6410 GdkDevice *device,
6411 GdkEventSequence *sequence)
6412{
6413 GtkPointerFocus *focus;
6414
6415 focus = gtk_window_lookup_pointer_focus (window, device, sequence);
6416 return focus ? gtk_pointer_focus_get_effective_target (focus) : NULL;
6417}
6418
6419GtkWidget *
6420gtk_window_lookup_pointer_focus_implicit_grab (GtkWindow *window,
6421 GdkDevice *device,
6422 GdkEventSequence *sequence)
6423{
6424 GtkPointerFocus *focus;
6425
6426 focus = gtk_window_lookup_pointer_focus (window, device, sequence);
6427 return focus ? gtk_pointer_focus_get_implicit_grab (focus) : NULL;
6428}
6429
6430void
6431gtk_window_update_pointer_focus (GtkWindow *window,
6432 GdkDevice *device,
6433 GdkEventSequence *sequence,
6434 GtkWidget *target,
6435 double x,
6436 double y)
6437{
6438 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
6439 GtkPointerFocus *focus;
6440
6441 focus = gtk_window_lookup_pointer_focus (window, device, sequence);
6442 if (focus)
6443 {
6444 gtk_pointer_focus_ref (focus);
6445
6446 if (target)
6447 {
6448 gtk_pointer_focus_set_target (focus, target);
6449 gtk_pointer_focus_set_coordinates (focus, x, y);
6450 }
6451 else
6452 {
6453 GList *pos;
6454
6455 pos = g_list_find (list: priv->foci, data: focus);
6456 if (pos)
6457 {
6458 priv->foci = g_list_remove (list: priv->foci, data: focus);
6459 gtk_pointer_focus_unref (focus);
6460 }
6461 }
6462
6463 gtk_pointer_focus_unref (focus);
6464 }
6465 else if (target)
6466 {
6467 focus = gtk_pointer_focus_new (toplevel: window, widget: target, device, sequence, x, y);
6468 priv->foci = g_list_prepend (list: priv->foci, data: focus);
6469 }
6470}
6471
6472void
6473gtk_window_update_pointer_focus_on_state_change (GtkWindow *window,
6474 GtkWidget *widget)
6475{
6476 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
6477 GList *l = priv->foci;
6478
6479 while (l)
6480 {
6481 GList *next;
6482
6483 GtkPointerFocus *focus = l->data;
6484
6485 next = l->next;
6486
6487 gtk_pointer_focus_ref (focus);
6488
6489 if (focus->grab_widget &&
6490 (focus->grab_widget == widget ||
6491 gtk_widget_is_ancestor (widget: focus->grab_widget, ancestor: widget)))
6492 gtk_pointer_focus_set_implicit_grab (focus, NULL);
6493
6494 if (GTK_WIDGET (focus->toplevel) == widget)
6495 {
6496 /* Unmapping the toplevel, remove pointer focus */
6497 priv->foci = g_list_remove_link (list: priv->foci, llink: l);
6498 gtk_pointer_focus_unref (focus);
6499 g_list_free (list: l);
6500 }
6501 else if (focus->target == widget ||
6502 gtk_widget_is_ancestor (widget: focus->target, ancestor: widget))
6503 {
6504 GtkWidget *old_target;
6505
6506 old_target = g_object_ref (focus->target);
6507 gtk_pointer_focus_repick_target (focus);
6508 gtk_synthesize_crossing_events (toplevel: GTK_ROOT (ptr: window),
6509 crossing_type: GTK_CROSSING_POINTER,
6510 old_target, new_target: focus->target,
6511 surface_x: focus->x, surface_y: focus->y,
6512 mode: GDK_CROSSING_NORMAL,
6513 NULL);
6514 g_object_unref (object: old_target);
6515 }
6516
6517 gtk_pointer_focus_unref (focus);
6518
6519 l = next;
6520 }
6521}
6522
6523void
6524gtk_window_maybe_revoke_implicit_grab (GtkWindow *window,
6525 GdkDevice *device,
6526 GtkWidget *grab_widget)
6527{
6528 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
6529 GList *l = priv->foci;
6530
6531 while (l)
6532 {
6533 GtkPointerFocus *focus = l->data;
6534
6535 l = l->next;
6536
6537 if (focus->toplevel != window)
6538 continue;
6539
6540 if ((!device || focus->device == device) &&
6541 focus->target != grab_widget &&
6542 !gtk_widget_is_ancestor (widget: focus->target, ancestor: grab_widget))
6543 gtk_window_set_pointer_focus_grab (window,
6544 device: focus->device,
6545 sequence: focus->sequence,
6546 NULL);
6547 }
6548}
6549
6550void
6551gtk_window_set_pointer_focus_grab (GtkWindow *window,
6552 GdkDevice *device,
6553 GdkEventSequence *sequence,
6554 GtkWidget *grab_widget)
6555{
6556 GtkPointerFocus *focus;
6557
6558 focus = gtk_window_lookup_pointer_focus (window, device, sequence);
6559 if (!focus && !grab_widget)
6560 return;
6561 g_assert (focus != NULL);
6562 gtk_pointer_focus_set_implicit_grab (focus, grab_widget);
6563}
6564
6565static void
6566update_cursor (GtkWindow *toplevel,
6567 GdkDevice *device,
6568 GtkWidget *grab_widget,
6569 GtkWidget *target)
6570{
6571 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: toplevel);
6572 GdkCursor *cursor = NULL;
6573 GtkNative *native;
6574 GdkSurface *surface;
6575
6576 native = gtk_widget_get_native (widget: target);
6577 surface = gtk_native_get_surface (self: native);
6578
6579 if (grab_widget && !gtk_widget_is_ancestor (widget: target, ancestor: grab_widget) && target != grab_widget)
6580 {
6581 /* Outside the grab widget, cursor stays to whatever the grab
6582 * widget says.
6583 */
6584 if (gtk_widget_get_native (widget: grab_widget) == native)
6585 cursor = gtk_widget_get_cursor (widget: grab_widget);
6586 else
6587 cursor = NULL;
6588 }
6589 else
6590 {
6591 /* Inside the grab widget or in absence of grabs, allow walking
6592 * up the hierarchy to find out the cursor.
6593 */
6594 while (target)
6595 {
6596 /* Don't inherit cursors across surfaces */
6597 if (native != gtk_widget_get_native (widget: target))
6598 break;
6599
6600 if (target == GTK_WIDGET (toplevel) && priv->resize_cursor != NULL)
6601 cursor = priv->resize_cursor;
6602 else
6603 cursor = gtk_widget_get_cursor (widget: target);
6604
6605 if (cursor)
6606 break;
6607
6608 if (grab_widget && target == grab_widget)
6609 break;
6610
6611 target = _gtk_widget_get_parent (widget: target);
6612 }
6613 }
6614
6615 gdk_surface_set_device_cursor (surface, device, cursor);
6616}
6617
6618void
6619gtk_window_maybe_update_cursor (GtkWindow *window,
6620 GtkWidget *widget,
6621 GdkDevice *device)
6622{
6623 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
6624 GList *l;
6625
6626 for (l = priv->foci; l; l = l->next)
6627 {
6628 GtkPointerFocus *focus = l->data;
6629 GtkWidget *grab_widget, *target;
6630 GtkWindowGroup *group;
6631
6632 if (focus->sequence)
6633 continue;
6634 if (device && device != focus->device)
6635 continue;
6636
6637 group = gtk_window_get_group (window);
6638
6639 grab_widget = gtk_window_group_get_current_grab (window_group: group);
6640 if (!grab_widget)
6641 grab_widget = gtk_pointer_focus_get_implicit_grab (focus);
6642
6643 target = gtk_pointer_focus_get_target (focus);
6644
6645 if (widget)
6646 {
6647 /* Check whether the changed widget affects the current cursor
6648 * lookups.
6649 */
6650 if (grab_widget && grab_widget != widget &&
6651 !gtk_widget_is_ancestor (widget, ancestor: grab_widget))
6652 continue;
6653 if (target != widget &&
6654 !gtk_widget_is_ancestor (widget: target, ancestor: widget))
6655 continue;
6656 }
6657
6658 update_cursor (toplevel: focus->toplevel, device: focus->device, grab_widget, target);
6659
6660 if (device)
6661 break;
6662 }
6663}
6664
6665/**
6666 * gtk_window_set_child: (attributes org.gtk.Method.set_property=child)
6667 * @window: a `GtkWindow`
6668 * @child: (nullable): the child widget
6669 *
6670 * Sets the child widget of @window.
6671 */
6672void
6673gtk_window_set_child (GtkWindow *window,
6674 GtkWidget *child)
6675{
6676 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
6677
6678 g_return_if_fail (GTK_IS_WINDOW (window));
6679 g_return_if_fail (child == NULL || GTK_IS_WIDGET (child));
6680
6681 g_clear_pointer (&priv->child, gtk_widget_unparent);
6682
6683 if (child)
6684 {
6685 priv->child = child;
6686 gtk_widget_insert_before (widget: child, GTK_WIDGET (window), next_sibling: priv->title_box);
6687 }
6688
6689 g_object_notify_by_pspec (G_OBJECT (window), pspec: window_props[PROP_CHILD]);
6690}
6691
6692/**
6693 * gtk_window_get_child: (attributes org.gtk.Method.get_property=child)
6694 * @window: a `GtkWindow`
6695 *
6696 * Gets the child widget of @window.
6697 *
6698 * Returns: (nullable) (transfer none): the child widget of @window
6699 */
6700GtkWidget *
6701gtk_window_get_child (GtkWindow *window)
6702{
6703 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
6704
6705 g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
6706
6707 return priv->child;
6708}
6709
6710/**
6711 * gtk_window_destroy:
6712 * @window: The window to destroy
6713 *
6714 * Drop the internal reference GTK holds on toplevel windows.
6715 */
6716void
6717gtk_window_destroy (GtkWindow *window)
6718{
6719 guint i;
6720
6721 g_return_if_fail (GTK_IS_WINDOW (window));
6722
6723 /* If gtk_window_destroy() has been called before. Can happen
6724 * when destroying a dialog manually in a ::close handler for example. */
6725 if (!g_list_store_find (store: toplevel_list, item: window, position: &i))
6726 return;
6727
6728 g_object_ref (window);
6729
6730 gtk_tooltip_unset_surface (native: GTK_NATIVE (ptr: window));
6731
6732 gtk_window_hide (GTK_WIDGET (window));
6733 gtk_accessible_update_state (self: GTK_ACCESSIBLE (ptr: window),
6734 first_state: GTK_ACCESSIBLE_STATE_HIDDEN, TRUE,
6735 -1);
6736
6737 g_list_store_remove (store: toplevel_list, position: i);
6738
6739 gtk_window_release_application (window);
6740
6741 gtk_widget_unrealize (GTK_WIDGET (window));
6742
6743 g_object_unref (object: window);
6744}
6745
6746GdkDevice**
6747gtk_window_get_foci_on_widget (GtkWindow *window,
6748 GtkWidget *widget,
6749 guint *n_devices)
6750{
6751 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
6752 GPtrArray *array = g_ptr_array_new ();
6753 GList *l;
6754
6755 for (l = priv->foci; l; l = l->next)
6756 {
6757 GtkPointerFocus *focus = l->data;
6758 GtkWidget *target;
6759
6760 target = gtk_pointer_focus_get_effective_target (focus);
6761
6762 if (target == widget || gtk_widget_is_ancestor (widget: target, ancestor: widget))
6763 g_ptr_array_add (array, data: focus->device);
6764 }
6765
6766 if (n_devices)
6767 *n_devices = array->len;
6768
6769 return (GdkDevice**) g_ptr_array_free (array, FALSE);
6770}
6771
6772static void
6773gtk_synthesize_grab_crossing (GtkWidget *child,
6774 GdkDevice *device,
6775 GtkWidget *new_grab_widget,
6776 GtkWidget *old_grab_widget,
6777 gboolean from_grab,
6778 gboolean was_shadowed,
6779 gboolean is_shadowed)
6780{
6781 g_object_ref (child);
6782
6783 if (is_shadowed)
6784 {
6785 if (!was_shadowed &&
6786 gtk_widget_is_sensitive (widget: child))
6787 _gtk_widget_synthesize_crossing (from: child,
6788 to: new_grab_widget,
6789 device,
6790 mode: GDK_CROSSING_GTK_GRAB);
6791 }
6792 else
6793 {
6794 if (was_shadowed &&
6795 gtk_widget_is_sensitive (widget: child))
6796 _gtk_widget_synthesize_crossing (from: old_grab_widget, to: child,
6797 device,
6798 mode: from_grab ? GDK_CROSSING_GTK_GRAB :
6799 GDK_CROSSING_GTK_UNGRAB);
6800 }
6801
6802 g_object_unref (object: child);
6803}
6804
6805static void
6806gtk_window_propagate_grab_notify (GtkWindow *window,
6807 GtkWidget *target,
6808 GdkDevice *device,
6809 GtkWidget *old_grab_widget,
6810 GtkWidget *new_grab_widget,
6811 gboolean from_grab)
6812{
6813 GList *l, *widgets = NULL;
6814 gboolean was_grabbed = FALSE, is_grabbed = FALSE;
6815
6816 while (target)
6817 {
6818 if (target == old_grab_widget)
6819 was_grabbed = TRUE;
6820 if (target == new_grab_widget)
6821 is_grabbed = TRUE;
6822 widgets = g_list_prepend (list: widgets, g_object_ref (target));
6823 target = gtk_widget_get_parent (widget: target);
6824 }
6825
6826 widgets = g_list_reverse (list: widgets);
6827
6828 for (l = widgets; l; l = l->next)
6829 {
6830 gboolean was_shadowed, is_shadowed;
6831
6832 was_shadowed = old_grab_widget && !was_grabbed;
6833 is_shadowed = new_grab_widget && !is_grabbed;
6834
6835 if (l->data == old_grab_widget)
6836 was_grabbed = FALSE;
6837 if (l->data == new_grab_widget)
6838 is_grabbed = FALSE;
6839
6840 if (was_shadowed == is_shadowed)
6841 break;
6842
6843 gtk_synthesize_grab_crossing (child: l->data,
6844 device,
6845 new_grab_widget: old_grab_widget,
6846 old_grab_widget: new_grab_widget,
6847 from_grab,
6848 was_shadowed,
6849 is_shadowed);
6850
6851 gtk_widget_reset_controllers (widget: l->data);
6852 }
6853
6854 g_list_free_full (list: widgets, free_func: g_object_unref);
6855}
6856
6857void
6858gtk_window_grab_notify (GtkWindow *window,
6859 GtkWidget *old_grab_widget,
6860 GtkWidget *new_grab_widget,
6861 gboolean from_grab)
6862{
6863 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
6864 GList *l;
6865
6866 for (l = priv->foci; l; l = l->next)
6867 {
6868 GtkPointerFocus *focus = l->data;
6869
6870 gtk_window_propagate_grab_notify (window,
6871 target: gtk_pointer_focus_get_effective_target (focus),
6872 device: focus->device,
6873 old_grab_widget,
6874 new_grab_widget,
6875 from_grab);
6876 }
6877}
6878
6879/**
6880 * gtk_window_set_handle_menubar_accel: (attributes org.gtk.Method.set_property=handle-menubar-accel)
6881 * @window: a `GtkWindow`
6882 * @handle_menubar_accel: %TRUE to make @window handle F10
6883 *
6884 * Sets whether this window should react to F10 key presses
6885 * by activating a menubar it contains.
6886 *
6887 * Since: 4.2
6888 */
6889void
6890gtk_window_set_handle_menubar_accel (GtkWindow *window,
6891 gboolean handle_menubar_accel)
6892{
6893 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
6894 GtkPropagationPhase phase;
6895
6896 g_return_if_fail (GTK_IS_WINDOW (window));
6897
6898 phase = handle_menubar_accel ? GTK_PHASE_CAPTURE : GTK_PHASE_NONE;
6899
6900 if (gtk_event_controller_get_propagation_phase (controller: priv->menubar_controller) == phase)
6901 return;
6902
6903 gtk_event_controller_set_propagation_phase (controller: priv->menubar_controller, phase);
6904
6905 g_object_notify_by_pspec (G_OBJECT (window), pspec: window_props[PROP_HANDLE_MENUBAR_ACCEL]);
6906}
6907
6908/**
6909 * gtk_window_get_handle_menubar_accel: (attributes org.gtk.Method.get_property=handle-menubar-accel)
6910 * @window: a `GtkWindow`
6911 *
6912 * Returns whether this window reacts to F10 key presses by
6913 * activating a menubar it contains.
6914 *
6915 * Returns: %TRUE if the window handles F10
6916 *
6917 * Since: 4.2
6918 */
6919gboolean
6920gtk_window_get_handle_menubar_accel (GtkWindow *window)
6921{
6922 GtkWindowPrivate *priv = gtk_window_get_instance_private (self: window);
6923 GtkPropagationPhase phase;
6924
6925 g_return_val_if_fail (GTK_IS_WINDOW (window), TRUE);
6926
6927 phase = gtk_event_controller_get_propagation_phase (controller: priv->menubar_controller);
6928
6929 return phase == GTK_PHASE_CAPTURE;
6930}
6931

source code of gtk/gtk/gtkwindow.c