gtkwindow.c 335 KB
Newer Older
Cody Russell's avatar
Cody Russell committed
1
/* GTK - The GIMP Toolkit
Elliot Lee's avatar
Elliot Lee committed
2 3 4
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
Elliot Lee's avatar
Elliot Lee committed
6 7 8 9 10 11
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 * Lesser General Public License for more details.
Elliot Lee's avatar
Elliot Lee committed
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
Javier Jardón's avatar
Javier Jardón committed
15
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
Elliot Lee's avatar
Elliot Lee committed
16
 */
17 18

/*
19
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
20 21 22 23 24
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

25
#include "config.h"
Matthias Clasen's avatar
Matthias Clasen committed
26

27 28
#include <cairo-gobject.h>

29
#include "gtkwindow.h"
Matthias Clasen's avatar
Matthias Clasen committed
30

Elliot Lee's avatar
Elliot Lee committed
31
#include <string.h>
32 33
#include <stdlib.h>
#include <errno.h>
Elliot Lee's avatar
Elliot Lee committed
34
#include <limits.h>
35
#include <graphene.h>
36

37
#include "gtkprivate.h"
Matthias Clasen's avatar
Matthias Clasen committed
38
#include "gtkwindowprivate.h"
39
#include "gtkaccelgroupprivate.h"
Tim Janik's avatar
Tim Janik committed
40
#include "gtkbindings.h"
41
#include "gtkcontainerprivate.h"
42
#include "gtkcsscornervalueprivate.h"
43
#include "gtkcssiconthemevalueprivate.h"
44
#include "gtkcssrgbavalueprivate.h"
45
#include "gtkcssshadowsvalueprivate.h"
46
#include "gtkdebugupdatesprivate.h"
47
#include "gtkkeyhash.h"
48
#include "gtkmain.h"
49
#include "gtkmnemonichash.h"
50
#include "gtkmenubar.h"
51
#include "gtkmenushellprivate.h"
52
#include "gtkicontheme.h"
53
#include "gtkmarshalers.h"
Johan Dahlin's avatar
Johan Dahlin committed
54
#include "gtkbuildable.h"
55
#include "gtkbuilderprivate.h"
Emmanuele Bassi's avatar
Emmanuele Bassi committed
56
#include "gtkwidgetprivate.h"
57
#include "gtkcontainerprivate.h"
58
#include "gtkintl.h"
59
#include "gtkstylecontextprivate.h"
60
#include "gtktypebuiltins.h"
61 62 63
#include "gtkbox.h"
#include "gtkbutton.h"
#include "gtkheaderbar.h"
64
#include "gtkheaderbarprivate.h"
65
#include "gtkpopoverprivate.h"
66
#include "a11y/gtkwindowaccessible.h"
67
#include "a11y/gtkcontaineraccessibleprivate.h"
68
#include "gtkapplicationprivate.h"
69
#include "gtkgestureprivate.h"
70 71
#include "inspector/init.h"
#include "inspector/window.h"
72
#include "gtkcssstylepropertyprivate.h"
73
#include "gtkpointerfocusprivate.h"
Elliot Lee's avatar
Elliot Lee committed
74

75 76
#include "gdk/gdk-private.h"

77 78 79 80
#ifdef GDK_WINDOWING_X11
#include "x11/gdkx.h"
#endif

Manuel Bachmann's avatar
Manuel Bachmann committed
81 82 83 84
#ifdef GDK_WINDOWING_WIN32
#include "win32/gdkwin32.h"
#endif

85 86 87 88
#ifdef GDK_WINDOWING_WAYLAND
#include "wayland/gdkwayland.h"
#endif

89 90 91 92
#ifdef GDK_WINDOWING_BROADWAY
#include "broadway/gdkbroadway.h"
#endif

William Hua's avatar
William Hua committed
93 94 95 96
#ifdef GDK_WINDOWING_MIR
#include "mir/gdkmir.h"
#endif

97 98 99 100 101
/**
 * SECTION:gtkwindow
 * @title: GtkWindow
 * @short_description: Toplevel which can contain other widgets
 *
102 103 104 105 106
 * A GtkWindow is a toplevel window which can contain other widgets.
 * Windows normally have decorations that are under the control
 * of the windowing system and allow the user to manipulate the window
 * (resize it, move it, close it,...).
 *
107
 * # GtkWindow as GtkBuildable
Matthias Clasen's avatar
Matthias Clasen committed
108
 *
109
 * The GtkWindow implementation of the GtkBuildable interface supports a
110 111 112
 * custom <accel-groups> element, which supports any number of <group>
 * elements representing the #GtkAccelGroup objects you want to add to
 * your window (synonymous with gtk_window_add_accel_group().
Matthias Clasen's avatar
Matthias Clasen committed
113
 *
114
 * It also supports the <initial-focus> element, whose name property names
115
 * the widget to receive the focus when the window is mapped.
116
 *
Matthias Clasen's avatar
Matthias Clasen committed
117
 * An example of a UI definition fragment with accel groups:
118
 * |[
119 120 121 122
 * <object class="GtkWindow">
 *   <accel-groups>
 *     <group name="accelgroup1"/>
 *   </accel-groups>
123
 *   <initial-focus name="thunderclap"/>
124
 * </object>
Matthias Clasen's avatar
Matthias Clasen committed
125
 * 
126
 * ...
Matthias Clasen's avatar
Matthias Clasen committed
127
 * 
128
 * <object class="GtkAccelGroup" id="accelgroup1"/>
129
 * ]|
Matthias Clasen's avatar
Matthias Clasen committed
130
 * 
131 132 133
 * The GtkWindow implementation of the GtkBuildable interface supports
 * setting a child as the titlebar by specifying “titlebar” as the “type”
 * attribute of a <child> element.
134 135 136 137
 *
 * # CSS nodes
 *
 * |[<!-- language="plain" -->
Timm Bäder's avatar
Timm Bäder committed
138
 * window.background
139
 * ├── decoration
Timm Bäder's avatar
Timm Bäder committed
140
 * ├── <titlebar child>.titlebar [.default-decoration]
141
 * ╰── <child>
142 143 144
 * ]|
 *
 * GtkWindow has a main CSS node with name window and style class .background,
145 146 147 148 149 150 151 152 153
 * and a subnode with name decoration.
 *
 * Style classes that are typically used with the main CSS node are .csd (when
 * client-side decorations are in use), .solid-csd (for client-side decorations
 * without invisible borders), .ssd (used by mutter when rendering server-side
 * decorations). GtkWindow also represents window states with the following
 * style classes on the main node: .tiled, .maximized, .fullscreen. Specialized
 * types of window often add their own discriminating style classes, such as
 * .popup or .tooltip.
154 155 156
 *
 * GtkWindow adds the .titlebar and .default-decoration style classes to the
 * widget that is added as a titlebar child.
157
 */
158

159
#define MENU_BAR_ACCEL "F10"
160
#define RESIZE_HANDLE_SIZE 20
161
#define MNEMONICS_DELAY 300 /* ms */
162 163 164 165 166 167
#define NO_CONTENT_CHILD_NAT 200
/* In case the content (excluding header bar and shadows) of the window
 * would be empty, either because there is no visible child widget or only an
 * empty container widget, we use NO_CONTENT_CHILD_NAT as natural width/height
 * instead.
 */
168

169 170 171 172 173
typedef struct _GtkWindowPopover GtkWindowPopover;

struct _GtkWindowPopover
{
  GtkWidget *widget;
174
  GtkWidget *parent;
175 176
  GtkPositionType pos;
  cairo_rectangle_int_t rect;
177
  guint clamp_allocation : 1;
178
};
179 180 181 182 183

struct _GtkWindowPrivate
{
  GtkMnemonicHash       *mnemonic_hash;

184
  GtkWidget             *attach_widget;
185
  GtkWidget             *default_widget;
186
  GtkWidget             *initial_focus;
187 188 189 190
  GtkWidget             *focus_widget;
  GtkWindow             *transient_parent;
  GtkWindowGeometryInfo *geometry_info;
  GtkWindowGroup        *group;
Matthias Clasen's avatar
Matthias Clasen committed
191
  GdkDisplay            *display;
192
  GtkApplication        *application;
193

194
  GQueue                 popovers;
195

196 197 198 199 200 201 202
  GdkModifierType        mnemonic_modifier;

  gchar   *startup_id;
  gchar   *title;
  gchar   *wm_role;

  guint    keys_changed_handler;
203
  guint    delete_event_handler;
204

205 206
  guint32  initial_timestamp;

207 208
  guint16  configure_request_count;

209
  guint    mnemonics_display_timeout_id;
210

211 212
  gint     scale;

213
  gint title_height;
214
  GtkWidget *title_box;
215
  GtkWidget *titlebar;
216
  GtkWidget *popup_menu;
217

218
  GdkMonitor *initial_fullscreen_monitor;
219
  guint      edge_constraints;
Matthias Clasen's avatar
Matthias Clasen committed
220

221 222 223 224 225 226 227
  /* The following flags are initially TRUE (before a window is mapped).
   * They cause us to compute a configure request that involves
   * default-only parameters. Once mapped, we set them to FALSE.
   * Then we set them to TRUE again on unmap (for position)
   * and on unrealize (for size).
   */
  guint    need_default_position     : 1;
228
  guint    need_default_size         : 1;
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245

  guint    above_initially           : 1;
  guint    accept_focus              : 1;
  guint    below_initially           : 1;
  guint    builder_visible           : 1;
  guint    configure_notify_received : 1;
  guint    decorated                 : 1;
  guint    deletable                 : 1;
  guint    destroy_with_parent       : 1;
  guint    focus_on_map              : 1;
  guint    fullscreen_initially      : 1;
  guint    has_user_ref_count        : 1;
  guint    iconify_initially         : 1; /* gtk_window_iconify() called before realization */
  guint    is_active                 : 1;
  guint    maximize_initially        : 1;
  guint    mnemonics_visible         : 1;
  guint    mnemonics_visible_set     : 1;
246
  guint    focus_visible             : 1;
247 248 249 250 251 252 253 254 255
  guint    modal                     : 1;
  guint    position                  : 3;
  guint    resizable                 : 1;
  guint    skips_pager               : 1;
  guint    skips_taskbar             : 1;
  guint    stick_initially           : 1;
  guint    transient_parent_group    : 1;
  guint    type                      : 4; /* GtkWindowType */
  guint    urgent                    : 1;
256
  guint    gravity                   : 5; /* GdkGravity */
257
  guint    csd_requested             : 1;
258
  guint    client_decorated          : 1; /* Decorations drawn client-side */
259
  guint    use_client_shadow         : 1; /* Decorations use client-side shadows */
Matthias Clasen's avatar
Matthias Clasen committed
260
  guint    maximized                 : 1;
261
  guint    fullscreen                : 1;
Matthias Clasen's avatar
Matthias Clasen committed
262
  guint    tiled                     : 1;
Matthias Clasen's avatar
Matthias Clasen committed
263

264 265
  guint    use_subsurface            : 1;

266 267
  GdkWindowTypeHint type_hint;

268
  GtkGesture *multipress_gesture;
269
  GtkGesture *drag_gesture;
270 271

  GdkWindow *hardcoded_window;
272 273

  GtkCssNode *decoration_node;
274 275

  GskRenderer *renderer;
276 277

  GList *foci;
278 279
};

280
#ifdef GDK_WINDOWING_X11
281 282
static const char *dnd_dest_targets [] = {
  "application/x-rootwindow-drop"
283
};
284
#endif
285

Elliot Lee's avatar
Elliot Lee committed
286
enum {
287
  SET_FOCUS,
288
  FRAME_EVENT,
289 290
  ACTIVATE_FOCUS,
  ACTIVATE_DEFAULT,
291
  KEYS_CHANGED,
292
  ENABLE_DEBUGGING,
Elliot Lee's avatar
Elliot Lee committed
293 294
  LAST_SIGNAL
};
295

296
enum {
297 298 299 300 301
  PROP_0,

  /* Construct */
  PROP_TYPE,

Havoc Pennington's avatar
Havoc Pennington committed
302
  /* Normal Props */
303
  PROP_TITLE,
304
  PROP_ROLE,
Havoc Pennington's avatar
Havoc Pennington committed
305
  PROP_RESIZABLE,
306 307 308 309 310
  PROP_MODAL,
  PROP_WIN_POS,
  PROP_DEFAULT_WIDTH,
  PROP_DEFAULT_HEIGHT,
  PROP_DESTROY_WITH_PARENT,
Havoc Pennington's avatar
Havoc Pennington committed
311
  PROP_ICON,
312
  PROP_ICON_NAME,
313
  PROP_DISPLAY,
314 315 316
  PROP_TYPE_HINT,
  PROP_SKIP_TASKBAR_HINT,
  PROP_SKIP_PAGER_HINT,
317
  PROP_URGENCY_HINT,
318
  PROP_ACCEPT_FOCUS,
319
  PROP_FOCUS_ON_MAP,
320
  PROP_DECORATED,
321
  PROP_DELETABLE,
322
  PROP_GRAVITY,
Alexander Larsson's avatar
Alexander Larsson committed
323
  PROP_TRANSIENT_FOR,
324
  PROP_ATTACHED_TO,
Allison Karlitskaya's avatar
Allison Karlitskaya committed
325
  PROP_APPLICATION,
326 327
  /* Readonly properties */
  PROP_IS_ACTIVE,
328

329 330
  /* Writeonly properties */
  PROP_STARTUP_ID,
331

332
  PROP_MNEMONICS_VISIBLE,
333
  PROP_FOCUS_VISIBLE,
334

335 336
  PROP_IS_MAXIMIZED,

337
  LAST_ARG
338
};
Elliot Lee's avatar
Elliot Lee committed
339

340 341
static GParamSpec *window_props[LAST_ARG] = { NULL, };

342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
/* Must be kept in sync with GdkWindowEdge ! */
typedef enum
{
  GTK_WINDOW_REGION_EDGE_NW,
  GTK_WINDOW_REGION_EDGE_N,
  GTK_WINDOW_REGION_EDGE_NE,
  GTK_WINDOW_REGION_EDGE_W,
  GTK_WINDOW_REGION_EDGE_E,
  GTK_WINDOW_REGION_EDGE_SW,
  GTK_WINDOW_REGION_EDGE_S,
  GTK_WINDOW_REGION_EDGE_SE,
  GTK_WINDOW_REGION_CONTENT,
  GTK_WINDOW_REGION_TITLE,
} GtkWindowRegion;

Havoc Pennington's avatar
Havoc Pennington committed
357 358 359
typedef struct
{
  GList     *icon_list;
360
  gchar     *icon_name;
Havoc Pennington's avatar
Havoc Pennington committed
361 362 363
  guint      realized : 1;
  guint      using_default_icon : 1;
  guint      using_parent_icon : 1;
364
  guint      using_themed_icon : 1;
Havoc Pennington's avatar
Havoc Pennington committed
365 366
} GtkWindowIconInfo;

367
typedef struct {
368 369
  GdkGeometry    geometry; /* Last set of geometry hints we set */
  GdkWindowHints flags;
Havoc Pennington's avatar
Havoc Pennington committed
370
  GdkRectangle   configure_request;
371 372
} GtkWindowLastGeometryInfo;

373 374
struct _GtkWindowGeometryInfo
{
Havoc Pennington's avatar
Havoc Pennington committed
375 376 377 378 379
  /* from last gtk_window_resize () - if > 0, indicates that
   * we should resize to this size.
   */
  gint           resize_width;  
  gint           resize_height;
380

Havoc Pennington's avatar
Havoc Pennington committed
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
  /* From last gtk_window_move () prior to mapping -
   * only used if initial_pos_set
   */
  gint           initial_x;
  gint           initial_y;
  
  /* Default size - used only the FIRST time we map a window,
   * only if > 0.
   */
  gint           default_width; 
  gint           default_height;
  /* whether to use initial_x, initial_y */
  guint          initial_pos_set : 1;
  /* CENTER_ALWAYS or other position constraint changed since
   * we sent the last configure request.
   */
  guint          position_constraints_changed : 1;
398

399
  GtkWindowLastGeometryInfo last;
400
};
401

402

403
static void gtk_window_constructed        (GObject           *object);
Tim Janik's avatar
Tim Janik committed
404
static void gtk_window_dispose            (GObject           *object);
405
static void gtk_window_finalize           (GObject           *object);
406
static void gtk_window_destroy            (GtkWidget         *widget);
Elliot Lee's avatar
Elliot Lee committed
407 408 409 410 411
static void gtk_window_show               (GtkWidget         *widget);
static void gtk_window_hide               (GtkWidget         *widget);
static void gtk_window_map                (GtkWidget         *widget);
static void gtk_window_unmap              (GtkWidget         *widget);
static void gtk_window_realize            (GtkWidget         *widget);
412
static void gtk_window_unrealize          (GtkWidget         *widget);
413 414 415 416
static void gtk_window_size_allocate      (GtkWidget           *widget,
                                           const GtkAllocation *allocation,
                                           int                  baseline,
                                           GtkAllocation       *out_clip);
417 418
static gboolean gtk_window_map_event      (GtkWidget         *widget,
                                           GdkEventAny       *event);
Elliot Lee's avatar
Elliot Lee committed
419 420
static gint gtk_window_configure_event    (GtkWidget         *widget,
					   GdkEventConfigure *event);
421 422
static gboolean gtk_window_event          (GtkWidget         *widget,
                                           GdkEvent          *event);
Elliot Lee's avatar
Elliot Lee committed
423 424 425 426 427 428 429 430
static gint gtk_window_key_press_event    (GtkWidget         *widget,
					   GdkEventKey       *event);
static gint gtk_window_key_release_event  (GtkWidget         *widget,
					   GdkEventKey       *event);
static gint gtk_window_focus_in_event     (GtkWidget         *widget,
					   GdkEventFocus     *event);
static gint gtk_window_focus_out_event    (GtkWidget         *widget,
					   GdkEventFocus     *event);
431 432
static gboolean gtk_window_state_event    (GtkWidget          *widget,
                                           GdkEventWindowState *event);
433 434
static void gtk_window_remove             (GtkContainer      *container,
                                           GtkWidget         *widget);
435
static void gtk_window_check_resize       (GtkContainer      *container);
436 437 438
static void gtk_window_forall             (GtkContainer   *container,
					   GtkCallback     callback,
					   gpointer        callback_data);
439
static gint gtk_window_focus              (GtkWidget        *widget,
440
				           GtkDirectionType  direction);
441 442
static void gtk_window_move_focus         (GtkWidget         *widget,
                                           GtkDirectionType   dir);
443
static void gtk_window_real_set_focus     (GtkWindow         *window,
444
					   GtkWidget         *focus);
445

446 447
static void gtk_window_real_activate_default (GtkWindow         *window);
static void gtk_window_real_activate_focus   (GtkWindow         *window);
448
static void gtk_window_keys_changed          (GtkWindow         *window);
449
static gboolean gtk_window_enable_debugging  (GtkWindow         *window,
450
                                              gboolean           toggle);
451 452
static void gtk_window_snapshot                    (GtkWidget   *widget,
                                                    GtkSnapshot *snapshot);
453 454 455 456 457 458
static void gtk_window_unset_transient_for         (GtkWindow  *window);
static void gtk_window_transient_parent_realized   (GtkWidget  *parent,
						    GtkWidget  *window);
static void gtk_window_transient_parent_unrealized (GtkWidget  *parent,
						    GtkWidget  *window);

Havoc Pennington's avatar
Havoc Pennington committed
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
static GtkWindowGeometryInfo* gtk_window_get_geometry_info         (GtkWindow    *window,
                                                                    gboolean      create);

static void     gtk_window_move_resize               (GtkWindow    *window);
static gboolean gtk_window_compare_hints             (GdkGeometry  *geometry_a,
                                                      guint         flags_a,
                                                      GdkGeometry  *geometry_b,
                                                      guint         flags_b);
static void     gtk_window_constrain_size            (GtkWindow    *window,
                                                      GdkGeometry  *geometry,
                                                      guint         flags,
                                                      gint          width,
                                                      gint          height,
                                                      gint         *new_width,
                                                      gint         *new_height);
static void     gtk_window_constrain_position        (GtkWindow    *window,
                                                      gint          new_width,
                                                      gint          new_height,
                                                      gint         *x,
                                                      gint         *y);
479 480 481 482
static void     gtk_window_update_fixed_size         (GtkWindow    *window,
                                                      GdkGeometry  *new_geometry,
                                                      gint          new_width,
                                                      gint          new_height);
Havoc Pennington's avatar
Havoc Pennington committed
483 484 485 486 487 488 489 490 491 492 493 494
static void     gtk_window_compute_hints             (GtkWindow    *window,
                                                      GdkGeometry  *new_geometry,
                                                      guint        *new_flags);
static void     gtk_window_compute_configure_request (GtkWindow    *window,
                                                      GdkRectangle *request,
                                                      GdkGeometry  *geometry,
                                                      guint        *flags);

static void     gtk_window_set_default_size_internal (GtkWindow    *window,
                                                      gboolean      change_width,
                                                      gint          width,
                                                      gboolean      change_height,
495
                                                      gint          height);
Elliot Lee's avatar
Elliot Lee committed
496

497
static void     update_themed_icon                    (GtkWindow    *window);
498
static GList   *icon_list_from_theme                  (GtkWindow    *window,
499
						       const gchar  *name);
Havoc Pennington's avatar
Havoc Pennington committed
500 501
static void     gtk_window_realize_icon               (GtkWindow    *window);
static void     gtk_window_unrealize_icon             (GtkWindow    *window);
502
static void     update_window_buttons                 (GtkWindow    *window);
503
static void     get_shadow_width                      (GtkWindow    *window,
504
                                                       GtkBorder    *shadow_width);
505 506 507

static GtkKeyHash *gtk_window_get_key_hash        (GtkWindow   *window);
static void        gtk_window_free_key_hash       (GtkWindow   *window);
508
#ifdef GDK_WINDOWING_X11
509 510 511
static void        gtk_window_on_theme_variant_changed (GtkSettings *settings,
                                                        GParamSpec  *pspec,
                                                        GtkWindow   *window);
512
#endif
513
static void        gtk_window_set_theme_variant         (GtkWindow  *window);
514

515 516
static void        gtk_window_do_popup         (GtkWindow      *window,
                                                GdkEventButton *event);
517
static void gtk_window_style_updated (GtkWidget     *widget);
518 519
static void gtk_window_state_flags_changed (GtkWidget     *widget,
                                            GtkStateFlags  previous_state);
520

521 522
static GSList      *toplevel_list = NULL;
static guint        window_signals[LAST_SIGNAL] = { 0 };
Havoc Pennington's avatar
Havoc Pennington committed
523
static GList       *default_icon_list = NULL;
524
static gchar       *default_icon_name = NULL;
525
static guint        default_icon_serial = 0;
526
static gboolean     disable_startup_notification = FALSE;
Elliot Lee's avatar
Elliot Lee committed
527

528 529
static GQuark       quark_gtk_window_key_hash = 0;
static GQuark       quark_gtk_window_icon_info = 0;
530
static GQuark       quark_gtk_buildable_accels = 0;
531

Johan Dahlin's avatar
Johan Dahlin committed
532 533
static GtkBuildableIface *parent_buildable_iface;

534 535 536 537 538 539 540 541
static void gtk_window_set_property (GObject         *object,
				     guint            prop_id,
				     const GValue    *value,
				     GParamSpec      *pspec);
static void gtk_window_get_property (GObject         *object,
				     guint            prop_id,
				     GValue          *value,
				     GParamSpec      *pspec);
Elliot Lee's avatar
Elliot Lee committed
542

Johan Dahlin's avatar
Johan Dahlin committed
543 544
/* GtkBuildable */
static void gtk_window_buildable_interface_init  (GtkBuildableIface *iface);
545 546 547 548
static void gtk_window_buildable_add_child (GtkBuildable *buildable,
                                            GtkBuilder   *builder,
                                            GObject      *child,
                                            const gchar  *type);
549 550 551 552
static void gtk_window_buildable_set_buildable_property (GtkBuildable        *buildable,
							 GtkBuilder          *builder,
							 const gchar         *name,
							 const GValue        *value);
Johan Dahlin's avatar
Johan Dahlin committed
553 554
static void gtk_window_buildable_parser_finished (GtkBuildable     *buildable,
						  GtkBuilder       *builder);
555 556 557 558 559 560 561 562 563 564 565
static gboolean gtk_window_buildable_custom_tag_start (GtkBuildable  *buildable,
						       GtkBuilder    *builder,
						       GObject       *child,
						       const gchar   *tagname,
						       GMarkupParser *parser,
						       gpointer      *data);
static void gtk_window_buildable_custom_finished (GtkBuildable  *buildable,
						      GtkBuilder    *builder,
						      GObject       *child,
						      const gchar   *tagname,
						      gpointer       user_data);
Johan Dahlin's avatar
Johan Dahlin committed
566

567
static void ensure_state_flag_backdrop (GtkWidget *widget);
568
static void unset_titlebar (GtkWindow *window);
Matthias Clasen's avatar
Matthias Clasen committed
569 570 571
static void on_titlebar_title_notify (GtkHeaderBar *titlebar,
                                      GParamSpec   *pspec,
                                      GtkWindow    *self);
572 573 574 575
static GtkWindowRegion get_active_region_type (GtkWindow   *window,
                                               gint         x,
                                               gint         y);

576
static void gtk_window_update_debugging (void);
577

Johan Dahlin's avatar
Johan Dahlin committed
578
G_DEFINE_TYPE_WITH_CODE (GtkWindow, gtk_window, GTK_TYPE_BIN,
579
                         G_ADD_PRIVATE (GtkWindow)
Johan Dahlin's avatar
Johan Dahlin committed
580
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
581
						gtk_window_buildable_interface_init))
Elliot Lee's avatar
Elliot Lee committed
582

583 584 585 586 587
static void
add_tab_bindings (GtkBindingSet    *binding_set,
		  GdkModifierType   modifiers,
		  GtkDirectionType  direction)
{
588
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, modifiers,
589
                                "move-focus", 1,
590
                                GTK_TYPE_DIRECTION_TYPE, direction);
591
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, modifiers,
592
                                "move-focus", 1,
593 594 595
                                GTK_TYPE_DIRECTION_TYPE, direction);
}

596 597 598 599 600
static void
add_arrow_bindings (GtkBindingSet    *binding_set,
		    guint             keysym,
		    GtkDirectionType  direction)
{
601
  guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
602 603
  
  gtk_binding_entry_add_signal (binding_set, keysym, 0,
604
                                "move-focus", 1,
605 606
                                GTK_TYPE_DIRECTION_TYPE, direction);
  gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
607
                                "move-focus", 1,
608 609
                                GTK_TYPE_DIRECTION_TYPE, direction);
  gtk_binding_entry_add_signal (binding_set, keypad_keysym, 0,
610
                                "move-focus", 1,
611 612
                                GTK_TYPE_DIRECTION_TYPE, direction);
  gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
613
                                "move-focus", 1,
614 615 616
                                GTK_TYPE_DIRECTION_TYPE, direction);
}

617 618 619 620 621 622 623 624 625 626 627 628 629
static guint32
extract_time_from_startup_id (const gchar* startup_id)
{
  gchar *timestr = g_strrstr (startup_id, "_TIME");
  guint32 retval = GDK_CURRENT_TIME;

  if (timestr)
    {
      gchar *end;
      guint32 timestamp; 
    
      /* Skip past the "_TIME" part */
      timestr += 5;
630

631
      end = NULL;
632
      errno = 0;
633 634
      timestamp = g_ascii_strtoull (timestr, &end, 0);
      if (errno == 0 && end != timestr)
635 636 637 638 639 640 641 642 643 644 645
        retval = timestamp;
    }

  return retval;
}

static gboolean
startup_id_is_fake (const gchar* startup_id)
{
  return strncmp (startup_id, "_TIME", 5) == 0;
}
646

647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682
static void
gtk_window_measure (GtkWidget      *widget,
                    GtkOrientation  orientation,
                    int             for_size,
                    int            *minimum,
                    int            *natural,
                    int            *minimum_baseline,
                    int            *natural_baseline)
{
  GtkWindow *window = GTK_WINDOW (widget);
  GtkWindowPrivate *priv = window->priv;
  GtkWidget *child = gtk_bin_get_child (GTK_BIN (widget));
  gboolean has_size_request = gtk_widget_has_size_request (widget);
  int title_min_size = 0;
  int title_nat_size = 0;
  int child_min_size = 0;
  int child_nat_size = 0;
  GtkBorder window_border = { 0 };


  if (priv->decorated && !priv->fullscreen)
    {
      get_shadow_width (window, &window_border);

      if (orientation == GTK_ORIENTATION_HORIZONTAL)
        for_size -= window_border.left + window_border.right;
      else
        for_size -= window_border.top + window_border.bottom;

      if (priv->title_box != NULL &&
          gtk_widget_get_visible (priv->title_box) &&
          gtk_widget_get_child_visible (priv->title_box))
        {
          int size = for_size;
          if (orientation == GTK_ORIENTATION_HORIZONTAL && for_size >= 0)
            gtk_widget_measure (priv->title_box,
683
                                GTK_ORIENTATION_VERTICAL,
684 685 686 687 688 689
                                -1,
                                NULL, &size,
                                NULL, NULL);

          gtk_widget_measure (priv->title_box,
                              orientation,
690
                              MAX (size, -1),
691 692 693 694 695 696 697 698 699
                              &title_min_size, &title_nat_size,
                              NULL, NULL);
        }
    }

  if (child != NULL && gtk_widget_get_visible (child))
    {
      gtk_widget_measure (child,
                          orientation,
700
                          MAX (for_size, -1),
701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
                          &child_min_size, &child_nat_size,
                          NULL, NULL);

      if (child_nat_size == 0 && !has_size_request)
        child_nat_size = NO_CONTENT_CHILD_NAT;
    }
  else if (!has_size_request)
    {
      child_nat_size = NO_CONTENT_CHILD_NAT;
    }

  if (orientation == GTK_ORIENTATION_HORIZONTAL)
    {
      title_min_size += window_border.left + window_border.right;
      title_nat_size += window_border.left + window_border.right;
      child_min_size += window_border.left + window_border.right;
      child_nat_size += window_border.left + window_border.right;
      *minimum = MAX (title_min_size, child_min_size);
      *natural = MAX (title_nat_size, child_nat_size);
    }
  else
    {
      *minimum = title_min_size + child_min_size + window_border.top + window_border.bottom;
      *natural = title_nat_size + child_nat_size + window_border.top + window_border.bottom;
    }
}

728 729 730 731 732 733 734 735 736 737 738
static void
gtk_window_add (GtkContainer *container,
                GtkWidget    *child)
{
  /* Insert the child's css node now at the end so the order wrt. decoration_node is correct */
  gtk_css_node_insert_before (gtk_widget_get_css_node (GTK_WIDGET (container)),
                              gtk_widget_get_css_node (child),
                              NULL);

  GTK_CONTAINER_CLASS (gtk_window_parent_class)->add (container, child);
}
739

740 741 742 743 744 745 746
static void popover_get_rect (GtkWindowPopover      *popover,
                              GtkWindow             *window,
                              cairo_rectangle_int_t *rect);

static GtkWidget *
gtk_window_pick (GtkWidget *widget,
                 gdouble    x,
747
                 gdouble    y)
748 749
{
  GtkWindow *window = GTK_WINDOW (widget);
750
  GList *popovers;
751

752
  for (popovers = window->priv->popovers.tail; popovers; popovers = popovers->prev)
753 754
    {
      GtkWindowPopover *popover = popovers->data;
755 756
      int dest_x, dest_y;
      GtkWidget *picked;
757

758 759 760
      gtk_widget_translate_coordinates (widget, popover->widget,
                                        x, y,
                                        &dest_x, &dest_y);
761

762 763 764
      picked = gtk_widget_pick (popover->widget, dest_x, dest_y);
      if (picked)
        return picked;
765 766
    }

767
  return GTK_WIDGET_CLASS (gtk_window_parent_class)->pick (widget, x, y);
768 769
}

Elliot Lee's avatar
Elliot Lee committed
770 771 772
static void
gtk_window_class_init (GtkWindowClass *klass)
{
773
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
Elliot Lee's avatar
Elliot Lee committed
774 775
  GtkWidgetClass *widget_class;
  GtkContainerClass *container_class;
776
  GtkBindingSet *binding_set;
777

Elliot Lee's avatar
Elliot Lee committed
778 779
  widget_class = (GtkWidgetClass*) klass;
  container_class = (GtkContainerClass*) klass;
780
  
781 782
  quark_gtk_window_key_hash = g_quark_from_static_string ("gtk-window-key-hash");
  quark_gtk_window_icon_info = g_quark_from_static_string ("gtk-window-icon-info");
783
  quark_gtk_buildable_accels = g_quark_from_static_string ("gtk-window-buildable-accels");
784

785
  gobject_class->constructed = gtk_window_constructed;
Tim Janik's avatar
Tim Janik committed
786
  gobject_class->dispose = gtk_window_dispose;
787 788
  gobject_class->finalize = gtk_window_finalize;

789 790
  gobject_class->set_property = gtk_window_set_property;
  gobject_class->get_property = gtk_window_get_property;
Elliot Lee's avatar
Elliot Lee committed
791

792
  widget_class->destroy = gtk_window_destroy;
Elliot Lee's avatar
Elliot Lee committed
793 794 795
  widget_class->show = gtk_window_show;
  widget_class->hide = gtk_window_hide;
  widget_class->map = gtk_window_map;
796
  widget_class->map_event = gtk_window_map_event;
Elliot Lee's avatar
Elliot Lee committed
797 798
  widget_class->unmap = gtk_window_unmap;
  widget_class->realize = gtk_window_realize;
799
  widget_class->unrealize = gtk_window_unrealize;
800
  widget_class->size_allocate = gtk_window_size_allocate;
Elliot Lee's avatar
Elliot Lee committed
801
  widget_class->configure_event = gtk_window_configure_event;
802
  widget_class->event = gtk_window_event;
Elliot Lee's avatar
Elliot Lee committed
803 804 805 806
  widget_class->key_press_event = gtk_window_key_press_event;
  widget_class->key_release_event = gtk_window_key_release_event;
  widget_class->focus_in_event = gtk_window_focus_in_event;
  widget_class->focus_out_event = gtk_window_focus_out_event;
807
  widget_class->focus = gtk_window_focus;
808
  widget_class->move_focus = gtk_window_move_focus;
809
  widget_class->window_state_event = gtk_window_state_event;
810
  widget_class->measure = gtk_window_measure;
811
  widget_class->state_flags_changed = gtk_window_state_flags_changed;
812
  widget_class->style_updated = gtk_window_style_updated;
Benjamin Otte's avatar
Benjamin Otte committed
813
  widget_class->snapshot = gtk_window_snapshot;
814
  widget_class->pick = gtk_window_pick;
815

816
  container_class->add = gtk_window_add;
817
  container_class->remove = gtk_window_remove;
818
  container_class->check_resize = gtk_window_check_resize;
819
  container_class->forall = gtk_window_forall;
Elliot Lee's avatar
Elliot Lee committed
820

821
  klass->set_focus = gtk_window_real_set_focus;
822

823 824
  klass->activate_default = gtk_window_real_activate_default;
  klass->activate_focus = gtk_window_real_activate_focus;
825
  klass->keys_changed = gtk_window_keys_changed;
826
  klass->enable_debugging = gtk_window_enable_debugging;
827

828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848
  window_props[PROP_TYPE] =
      g_param_spec_enum ("type",
                         P_("Window Type"),
                         P_("The type of the window"),
                         GTK_TYPE_WINDOW_TYPE,
                         GTK_WINDOW_TOPLEVEL,
                         GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);

  window_props[PROP_TITLE] =
      g_param_spec_string ("title",
                           P_("Window Title"),
                           P_("The title of the window"),
                           NULL,
                           GTK_PARAM_READWRITE);

  window_props[PROP_ROLE] =
      g_param_spec_string ("role",
                           P_("Window Role"),
                           P_("Unique identifier for the window to be used when restoring a session"),
                           NULL,
                           GTK_PARAM_READWRITE);
849

850 851 852 853 854 855 856 857
  /**
   * GtkWindow:startup-id:
   *
   * The :startup-id is a write-only property for setting window's
   * startup notification identifier. See gtk_window_set_startup_id()
   * for more details.
   *
   * Since: 2.12
858
   */
859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911
  window_props[PROP_STARTUP_ID] =
      g_param_spec_string ("startup-id",
                           P_("Startup ID"),
                           P_("Unique startup identifier for the window used by startup-notification"),
                           NULL,
                           GTK_PARAM_WRITABLE);

  window_props[PROP_RESIZABLE] =
      g_param_spec_boolean ("resizable",
                            P_("Resizable"),
                            P_("If TRUE, users can resize the window"),
                            TRUE,
                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);

  window_props[PROP_MODAL] =
      g_param_spec_boolean ("modal",
                            P_("Modal"),
                            P_("If TRUE, the window is modal (other windows are not usable while this one is up)"),
                            FALSE,
                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);

  window_props[PROP_WIN_POS] =
      g_param_spec_enum ("window-position",
                         P_("Window Position"),
                         P_("The initial position of the window"),
                         GTK_TYPE_WINDOW_POSITION,
                         GTK_WIN_POS_NONE,
                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);

  window_props[PROP_DEFAULT_WIDTH] =
      g_param_spec_int ("default-width",
                        P_("Default Width"),
                        P_("The default width of the window, used when initially showing the window"),
                        -1, G_MAXINT,
                        -1,
                        GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);

  window_props[PROP_DEFAULT_HEIGHT] =
      g_param_spec_int ("default-height",
                        P_("Default Height"),
                        P_("The default height of the window, used when initially showing the window"),
                        -1, G_MAXINT,
                        -1,
                        GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);

  window_props[PROP_DESTROY_WITH_PARENT] =
      g_param_spec_boolean ("destroy-with-parent",
                            P_("Destroy with Parent"),
                            P_("If this window should be destroyed when the parent is destroyed"),
                            FALSE,
                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);

  window_props[PROP_ICON] =
Benjamin Otte's avatar
Benjamin Otte committed
912 913 914 915 916
      g_param_spec_object ("icon",
                           P_("Icon"),
                           P_("Icon for this window"),
			   GDK_TYPE_TEXTURE,
                           GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
917 918 919 920 921 922

  /**
   * GtkWindow:mnemonics-visible:
   *
   * Whether mnemonics are currently visible in this window.
   *
923
   * This property is maintained by GTK+ based on user input,
924 925 926 927
   * and should not be set by applications.
   *
   * Since: 2.20
   */
928 929 930 931 932 933
  window_props[PROP_MNEMONICS_VISIBLE] =
      g_param_spec_boolean ("mnemonics-visible",
                            P_("Mnemonics Visible"),
                            P_("Whether mnemonics are currently visible in this window"),
                            TRUE,
                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
934 935 936 937 938 939

  /**
   * GtkWindow:focus-visible:
   *
   * Whether 'focus rectangles' are currently visible in this window.
   *
940
   * This property is maintained by GTK+ based on user input
941 942 943 944
   * and should not be set by applications.
   *
   * Since: 2.20
   */
945 946 947 948 949 950 951
  window_props[PROP_FOCUS_VISIBLE] =
      g_param_spec_boolean ("focus-visible",
                            P_("Focus Visible"),
                            P_("Whether focus rectangles are currently visible in this window"),
                            TRUE,
                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);

952 953 954 955 956 957 958 959
  /**
   * GtkWindow:icon-name:
   *
   * The :icon-name property specifies the name of the themed icon to
   * use as the window icon. See #GtkIconTheme for more details.
   *
   * Since: 2.6
   */
960 961 962 963 964 965 966
  window_props[PROP_ICON_NAME] =
      g_param_spec_string ("icon-name",
                           P_("Icon Name"),
                           P_("Name of the themed icon for this window"),
                           NULL,
                           GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);

967 968 969 970 971
  window_props[PROP_DISPLAY] =
      g_param_spec_object ("display",
                           P_("Display"),
                           P_("The display that will display this window"),
                           GDK_TYPE_DISPLAY,
972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005
                           GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);

  window_props[PROP_IS_ACTIVE] =
      g_param_spec_boolean ("is-active",
                            P_("Is Active"),
                            P_("Whether the toplevel is the current active window"),
                            FALSE,
                            GTK_PARAM_READABLE);

  window_props[PROP_TYPE_HINT] =
      g_param_spec_enum ("type-hint",
                         P_("Type hint"),
                         P_("Hint to help the desktop environment understand what kind of window this is and how to treat it."),
                         GDK_TYPE_WINDOW_TYPE_HINT,
                         GDK_WINDOW_TYPE_HINT_NORMAL,
                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);

  window_props[PROP_SKIP_TASKBAR_HINT] =
      g_param_spec_boolean ("skip-taskbar-hint",
                            P_("Skip taskbar"),
                            P_("TRUE if the window should not be in the task bar."),
                            FALSE,
                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);

  window_props[PROP_SKIP_PAGER_HINT] =
      g_param_spec_boolean ("skip-pager-hint",
                            P_("Skip pager"),
                            P_("TRUE if the window should not be in the pager."),
                            FALSE,
                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);

  window_props[PROP_URGENCY_HINT] =
      g_param_spec_boolean ("urgency-hint",
                            P_("Urgent"),
1006
                            P_("TRUE if the window should be brought to the user’s attention."),
1007 1008
                            FALSE,
                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1009

1010
  /**
Matthias Clasen's avatar
Matthias Clasen committed
1011
   * GtkWindow:accept-focus:
1012 1013 1014 1015 1016
   *
   * Whether the window should receive the input focus.
   *
   * Since: 2.4
   */
1017 1018 1019 1020 1021 1022
  window_props[PROP_ACCEPT_FOCUS] =
      g_param_spec_boolean ("accept-focus",
                            P_("Accept focus"),
                            P_("TRUE if the window should receive the input focus."),
                            TRUE,
                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1023

1024
  /**
Matthias Clasen's avatar
Matthias Clasen committed
1025
   * GtkWindow:focus-on-map:
1026 1027 1028 1029 1030
   *
   * Whether the window should receive the input focus when mapped.
   *
   * Since: 2.6
   */
1031 1032 1033 1034 1035 1036
  window_props[PROP_FOCUS_ON_MAP] =
      g_param_spec_boolean ("focus-on-map",
                            P_("Focus on map"),
                            P_("TRUE if the window should receive the input focus when mapped."),
                            TRUE,