gtkwindow.c 350 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
#include "gtkwindow.h"
Matthias Clasen's avatar
Matthias Clasen committed
28

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

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

71 72
#include "gdk/gdk-private.h"

73 74 75 76
#ifdef GDK_WINDOWING_X11
#include "x11/gdkx.h"
#endif

Manuel Bachmann's avatar
Manuel Bachmann committed
77 78 79 80
#ifdef GDK_WINDOWING_WIN32
#include "win32/gdkwin32.h"
#endif

81 82 83 84
#ifdef GDK_WINDOWING_WAYLAND
#include "wayland/gdkwayland.h"
#endif

85 86 87 88
#ifdef GDK_WINDOWING_BROADWAY
#include "broadway/gdkbroadway.h"
#endif

William Hua's avatar
William Hua committed
89 90 91 92
#ifdef GDK_WINDOWING_MIR
#include "mir/gdkmir.h"
#endif

93 94 95 96 97
/**
 * SECTION:gtkwindow
 * @title: GtkWindow
 * @short_description: Toplevel which can contain other widgets
 *
98 99 100 101 102
 * 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,...).
 *
103
 * # GtkWindow as GtkBuildable
Matthias Clasen's avatar
Matthias Clasen committed
104
 *
105
 * The GtkWindow implementation of the GtkBuildable interface supports a
106 107 108
 * 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
109
 *
110
 * It also supports the <initial-focus> element, whose name property names
111
 * the widget to receive the focus when the window is mapped.
112
 *
Matthias Clasen's avatar
Matthias Clasen committed
113
 * An example of a UI definition fragment with accel groups:
114
 * |[
115 116 117 118
 * <object class="GtkWindow">
 *   <accel-groups>
 *     <group name="accelgroup1"/>
 *   </accel-groups>
119
 *   <initial-focus name="thunderclap"/>
120
 * </object>
Matthias Clasen's avatar
Matthias Clasen committed
121
 * 
122
 * ...
Matthias Clasen's avatar
Matthias Clasen committed
123
 * 
124
 * <object class="GtkAccelGroup" id="accelgroup1"/>
125
 * ]|
Matthias Clasen's avatar
Matthias Clasen committed
126
 * 
127 128 129
 * 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.
130 131 132 133 134
 *
 * # CSS nodes
 *
 * |[<!-- language="plain" -->
 * window
135 136
 * ├── decoration
 * ╰── <child>
137 138 139
 * ]|
 *
 * GtkWindow has a main CSS node with name window and style class .background,
140 141 142 143 144 145 146 147 148
 * 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.
149 150 151
 *
 * GtkWindow adds the .titlebar and .default-decoration style classes to the
 * widget that is added as a titlebar child.
152
 */
153

154
#define MNEMONICS_DELAY 300 /* ms */
155 156 157 158 159 160
#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.
 */
161

162 163 164 165 166
typedef struct _GtkWindowPopover GtkWindowPopover;

struct _GtkWindowPopover
{
  GtkWidget *widget;
167
  GtkWidget *parent;
168 169 170
  GdkWindow *window;
  GtkPositionType pos;
  cairo_rectangle_int_t rect;
171
  gulong unmap_id;
172
  guint clamp_allocation : 1;
173
};
174 175 176 177 178

struct _GtkWindowPrivate
{
  GtkMnemonicHash       *mnemonic_hash;

179
  GtkWidget             *attach_widget;
180
  GtkWidget             *default_widget;
181
  GtkWidget             *initial_focus;
182 183 184 185
  GtkWidget             *focus_widget;
  GtkWindow             *transient_parent;
  GtkWindowGeometryInfo *geometry_info;
  GtkWindowGroup        *group;
186
  GdkScreen             *screen;
Matthias Clasen's avatar
Matthias Clasen committed
187
  GdkDisplay            *display;
188
  GtkApplication        *application;
189

190
  GList                 *popovers;
191

192 193 194 195 196 197 198
  GdkModifierType        mnemonic_modifier;

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

  guint    keys_changed_handler;
199
  guint    delete_event_handler;
200

201 202
  guint32  initial_timestamp;

203 204
  guint16  configure_request_count;

205
  guint    mnemonics_display_timeout_id;
206

207 208
  gint     scale;

209
  gint title_height;
210
  GtkWidget *title_box;
211
  GtkWidget *titlebar;
212
  GtkWidget *popup_menu;
213

Matthias Clasen's avatar
Matthias Clasen committed
214
  GdkWindow *border_window[8];
215
  gint       initial_fullscreen_monitor;
Matthias Clasen's avatar
Matthias Clasen committed
216

217 218 219 220 221 222 223
  /* 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;
224
  guint    need_default_size         : 1;
225 226 227 228 229 230 231 232 233 234 235 236 237 238

  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_focus                 : 1;
  guint    has_user_ref_count        : 1;
  guint    has_toplevel_focus        : 1;
239
  guint    hide_titlebar_when_maximized : 1;
240 241 242 243 244
  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;
245
  guint    focus_visible             : 1;
246 247 248 249 250 251 252 253 254
  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;
255
  guint    gravity                   : 5; /* GdkGravity */
256
  guint    csd_requested             : 1;
257
  guint    client_decorated          : 1; /* Decorations drawn client-side */
258
  guint    use_client_shadow         : 1; /* Decorations use client-side shadows */
Matthias Clasen's avatar
Matthias Clasen committed
259
  guint    maximized                 : 1;
260
  guint    fullscreen                : 1;
Matthias Clasen's avatar
Matthias Clasen committed
261
  guint    tiled                     : 1;
Matthias Clasen's avatar
Matthias Clasen committed
262

263 264
  guint    use_subsurface            : 1;

265 266
  GdkWindowTypeHint type_hint;

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

  GdkWindow *hardcoded_window;
271 272

  GtkCssNode *decoration_node;
273 274

  GskRenderer *renderer;
275 276
};

277
static const GtkTargetEntry dnd_dest_targets [] = {
278
  { (char *) "application/x-rootwindow-drop", 0, 0 },
279 280
};

Elliot Lee's avatar
Elliot Lee committed
281
enum {
282
  SET_FOCUS,
283
  FRAME_EVENT,
284 285
  ACTIVATE_FOCUS,
  ACTIVATE_DEFAULT,
286
  KEYS_CHANGED,
287
  ENABLE_DEBUGGING,
Elliot Lee's avatar
Elliot Lee committed
288 289
  LAST_SIGNAL
};
290

291
enum {
292 293 294 295 296
  PROP_0,

  /* Construct */
  PROP_TYPE,

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

326 327
  /* Writeonly properties */
  PROP_STARTUP_ID,
328

329
  PROP_MNEMONICS_VISIBLE,
330
  PROP_FOCUS_VISIBLE,
331

332 333
  PROP_IS_MAXIMIZED,

334
  LAST_ARG
335
};
Elliot Lee's avatar
Elliot Lee committed
336

337 338
static GParamSpec *window_props[LAST_ARG] = { NULL, };

339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
/* 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
354 355 356
typedef struct
{
  GList     *icon_list;
357
  gchar     *icon_name;
Havoc Pennington's avatar
Havoc Pennington committed
358 359 360
  guint      realized : 1;
  guint      using_default_icon : 1;
  guint      using_parent_icon : 1;
361
  guint      using_themed_icon : 1;
Havoc Pennington's avatar
Havoc Pennington committed
362 363
} GtkWindowIconInfo;

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

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

Havoc Pennington's avatar
Havoc Pennington committed
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
  /* 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;
395

396
  GtkWindowLastGeometryInfo last;
397
};
398

399

400
static void gtk_window_constructed        (GObject           *object);
Tim Janik's avatar
Tim Janik committed
401
static void gtk_window_dispose            (GObject           *object);
402
static void gtk_window_finalize           (GObject           *object);
403
static void gtk_window_destroy            (GtkWidget         *widget);
Elliot Lee's avatar
Elliot Lee committed
404 405 406 407 408
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);
409
static void gtk_window_unrealize          (GtkWidget         *widget);
410 411
static void gtk_window_size_allocate      (GtkWidget         *widget,
					   GtkAllocation     *allocation);
412 413
static gboolean gtk_window_map_event      (GtkWidget         *widget,
                                           GdkEventAny       *event);
Elliot Lee's avatar
Elliot Lee committed
414 415
static gint gtk_window_configure_event    (GtkWidget         *widget,
					   GdkEventConfigure *event);
416 417
static gboolean gtk_window_event          (GtkWidget         *widget,
                                           GdkEvent          *event);
Elliot Lee's avatar
Elliot Lee committed
418 419 420 421 422 423 424 425
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);
426 427
static gboolean gtk_window_state_event    (GtkWidget          *widget,
                                           GdkEventWindowState *event);
428 429
static void gtk_window_remove             (GtkContainer      *container,
                                           GtkWidget         *widget);
430
static void gtk_window_check_resize       (GtkContainer      *container);
431 432 433 434
static void gtk_window_forall             (GtkContainer   *container,
					   gboolean	include_internals,
					   GtkCallback     callback,
					   gpointer        callback_data);
435
static gint gtk_window_focus              (GtkWidget        *widget,
436
				           GtkDirectionType  direction);
437 438
static void gtk_window_move_focus         (GtkWidget         *widget,
                                           GtkDirectionType   dir);
439
static void gtk_window_real_set_focus     (GtkWindow         *window,
440
					   GtkWidget         *focus);
441

442 443
static void gtk_window_real_activate_default (GtkWindow         *window);
static void gtk_window_real_activate_focus   (GtkWindow         *window);
444
static void gtk_window_keys_changed          (GtkWindow         *window);
445
static gboolean gtk_window_enable_debugging  (GtkWindow         *window,
446
                                              gboolean           toggle);
447 448
static GskRenderNode *gtk_window_get_render_node (GtkWidget   *widget,
                                                  GskRenderer *renderer);
449 450 451 452 453 454
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);

455 456
static GdkScreen *gtk_window_check_screen (GtkWindow *window);

Havoc Pennington's avatar
Havoc Pennington committed
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
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);
477 478 479 480
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
481 482 483 484 485 486 487 488 489 490 491 492
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,
493
                                                      gint          height);
Elliot Lee's avatar
Elliot Lee committed
494

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

static GtkKeyHash *gtk_window_get_key_hash        (GtkWindow   *window);
static void        gtk_window_free_key_hash       (GtkWindow   *window);
Søren Sandmann's avatar
Søren Sandmann committed
506 507
static void	   gtk_window_on_composited_changed (GdkScreen *screen,
						     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 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532

static void gtk_window_get_preferred_width (GtkWidget *widget,
                                            gint      *minimum_size,
                                            gint      *natural_size);
static void gtk_window_get_preferred_width_for_height (GtkWidget *widget,
                                                       gint       height,
                                                       gint      *minimum_size,
                                                       gint      *natural_size);

static void gtk_window_get_preferred_height (GtkWidget *widget,
                                             gint      *minimum_size,
                                             gint      *natural_size);
static void gtk_window_get_preferred_height_for_width (GtkWidget *widget,
                                                       gint       width,
                                                       gint      *minimum_size,
                                                       gint      *natural_size);
533
static void gtk_window_style_updated (GtkWidget     *widget);
534 535
static void gtk_window_state_flags_changed (GtkWidget     *widget,
                                            GtkStateFlags  previous_state);
536

537 538
static GSList      *toplevel_list = NULL;
static guint        window_signals[LAST_SIGNAL] = { 0 };
Havoc Pennington's avatar
Havoc Pennington committed
539
static GList       *default_icon_list = NULL;
540
static gchar       *default_icon_name = NULL;
541
static guint        default_icon_serial = 0;
542
static gboolean     disable_startup_notification = FALSE;
Elliot Lee's avatar
Elliot Lee committed
543

544 545 546
static GQuark       quark_gtk_embedded = 0;
static GQuark       quark_gtk_window_key_hash = 0;
static GQuark       quark_gtk_window_icon_info = 0;
547
static GQuark       quark_gtk_buildable_accels = 0;
548

Johan Dahlin's avatar
Johan Dahlin committed
549 550
static GtkBuildableIface *parent_buildable_iface;

551 552 553 554 555 556 557 558
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
559

Johan Dahlin's avatar
Johan Dahlin committed
560 561
/* GtkBuildable */
static void gtk_window_buildable_interface_init  (GtkBuildableIface *iface);
562 563 564 565
static void gtk_window_buildable_add_child (GtkBuildable *buildable,
                                            GtkBuilder   *builder,
                                            GObject      *child,
                                            const gchar  *type);
566 567 568 569
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
570 571
static void gtk_window_buildable_parser_finished (GtkBuildable     *buildable,
						  GtkBuilder       *builder);
572 573 574 575 576 577 578 579 580 581 582
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
583

584
static void ensure_state_flag_backdrop (GtkWidget *widget);
585
static void unset_titlebar (GtkWindow *window);
Matthias Clasen's avatar
Matthias Clasen committed
586 587 588
static void on_titlebar_title_notify (GtkHeaderBar *titlebar,
                                      GParamSpec   *pspec,
                                      GtkWindow    *self);
589 590 591 592 593
static GtkWindowRegion get_active_region_type (GtkWindow   *window,
                                               GdkEventAny *event,
                                               gint         x,
                                               gint         y);

594
static void gtk_window_update_debugging (void);
595

Johan Dahlin's avatar
Johan Dahlin committed
596
G_DEFINE_TYPE_WITH_CODE (GtkWindow, gtk_window, GTK_TYPE_BIN,
597
                         G_ADD_PRIVATE (GtkWindow)
Johan Dahlin's avatar
Johan Dahlin committed
598
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
599
						gtk_window_buildable_interface_init))
Elliot Lee's avatar
Elliot Lee committed
600

601 602 603 604 605
static void
add_tab_bindings (GtkBindingSet    *binding_set,
		  GdkModifierType   modifiers,
		  GtkDirectionType  direction)
{
606
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, modifiers,
607
                                "move-focus", 1,
608
                                GTK_TYPE_DIRECTION_TYPE, direction);
609
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, modifiers,
610
                                "move-focus", 1,
611 612 613
                                GTK_TYPE_DIRECTION_TYPE, direction);
}

614 615 616 617 618
static void
add_arrow_bindings (GtkBindingSet    *binding_set,
		    guint             keysym,
		    GtkDirectionType  direction)
{
619
  guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
620 621
  
  gtk_binding_entry_add_signal (binding_set, keysym, 0,
622
                                "move-focus", 1,
623 624
                                GTK_TYPE_DIRECTION_TYPE, direction);
  gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
625
                                "move-focus", 1,
626 627
                                GTK_TYPE_DIRECTION_TYPE, direction);
  gtk_binding_entry_add_signal (binding_set, keypad_keysym, 0,
628
                                "move-focus", 1,
629 630
                                GTK_TYPE_DIRECTION_TYPE, direction);
  gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
631
                                "move-focus", 1,
632 633 634
                                GTK_TYPE_DIRECTION_TYPE, direction);
}

635 636 637 638 639 640 641 642 643 644 645 646 647
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;
648

649
      end = NULL;
650
      errno = 0;
651 652
      timestamp = g_ascii_strtoull (timestr, &end, 0);
      if (errno == 0 && end != timestr)
653 654 655 656 657 658 659 660 661 662 663
        retval = timestamp;
    }

  return retval;
}

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

Elliot Lee's avatar
Elliot Lee committed
665 666 667
static void
gtk_window_class_init (GtkWindowClass *klass)
{
668
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
Elliot Lee's avatar
Elliot Lee committed
669 670
  GtkWidgetClass *widget_class;
  GtkContainerClass *container_class;
671
  GtkBindingSet *binding_set;
672

Elliot Lee's avatar
Elliot Lee committed
673 674
  widget_class = (GtkWidgetClass*) klass;
  container_class = (GtkContainerClass*) klass;
675
  
676 677 678
  quark_gtk_embedded = g_quark_from_static_string ("gtk-embedded");
  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");
679
  quark_gtk_buildable_accels = g_quark_from_static_string ("gtk-window-buildable-accels");
680

681
  gobject_class->constructed = gtk_window_constructed;
Tim Janik's avatar
Tim Janik committed
682
  gobject_class->dispose = gtk_window_dispose;
683 684
  gobject_class->finalize = gtk_window_finalize;

685 686
  gobject_class->set_property = gtk_window_set_property;
  gobject_class->get_property = gtk_window_get_property;
Elliot Lee's avatar
Elliot Lee committed
687

688
  widget_class->destroy = gtk_window_destroy;
Elliot Lee's avatar
Elliot Lee committed
689 690 691
  widget_class->show = gtk_window_show;
  widget_class->hide = gtk_window_hide;
  widget_class->map = gtk_window_map;
692
  widget_class->map_event = gtk_window_map_event;
Elliot Lee's avatar
Elliot Lee committed
693 694
  widget_class->unmap = gtk_window_unmap;
  widget_class->realize = gtk_window_realize;
695
  widget_class->unrealize = gtk_window_unrealize;
696
  widget_class->size_allocate = gtk_window_size_allocate;
Elliot Lee's avatar
Elliot Lee committed
697
  widget_class->configure_event = gtk_window_configure_event;
698
  widget_class->event = gtk_window_event;
Elliot Lee's avatar
Elliot Lee committed
699 700 701 702
  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;
703
  widget_class->focus = gtk_window_focus;
704
  widget_class->move_focus = gtk_window_move_focus;
705
  widget_class->window_state_event = gtk_window_state_event;
706 707 708 709
  widget_class->get_preferred_width = gtk_window_get_preferred_width;
  widget_class->get_preferred_width_for_height = gtk_window_get_preferred_width_for_height;
  widget_class->get_preferred_height = gtk_window_get_preferred_height;
  widget_class->get_preferred_height_for_width = gtk_window_get_preferred_height_for_width;
710
  widget_class->state_flags_changed = gtk_window_state_flags_changed;
711
  widget_class->style_updated = gtk_window_style_updated;
712
  widget_class->get_render_node = gtk_window_get_render_node;
713

714
  container_class->remove = gtk_window_remove;
715
  container_class->check_resize = gtk_window_check_resize;
716
  container_class->forall = gtk_window_forall;
Elliot Lee's avatar
Elliot Lee committed
717

718
  klass->set_focus = gtk_window_real_set_focus;
719

720 721
  klass->activate_default = gtk_window_real_activate_default;
  klass->activate_focus = gtk_window_real_activate_focus;
722
  klass->keys_changed = gtk_window_keys_changed;
723
  klass->enable_debugging = gtk_window_enable_debugging;
724

725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745
  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);
746

747 748 749 750 751 752 753 754
  /**
   * 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
755
   */
756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806
  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);
807

808 809 810 811 812 813 814
  /**
   * GtkWindow:hide-titlebar-when-maximized:
   *
   * Whether the titlebar should be hidden during maximization.
   *
   * Since: 3.4
   */
815 816 817 818 819 820 821 822 823 824 825 826 827
  window_props[PROP_HIDE_TITLEBAR_WHEN_MAXIMIZED] =
      g_param_spec_boolean ("hide-titlebar-when-maximized",
                            P_("Hide the titlebar during maximization"),
                            P_("If this window's titlebar should be hidden when the window is maximized"),
                            FALSE,
                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);

  window_props[PROP_ICON] =
      g_param_spec_object ("icon",
                           P_("Icon"),
                           P_("Icon for this window"),
                           GDK_TYPE_PIXBUF,
                           GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
828 829 830 831 832 833

  /**
   * GtkWindow:mnemonics-visible:
   *
   * Whether mnemonics are currently visible in this window.
   *
834
   * This property is maintained by GTK+ based on user input,
835 836 837 838
   * and should not be set by applications.
   *
   * Since: 2.20
   */
839 840 841 842 843 844
  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);
845 846 847 848 849 850

  /**
   * GtkWindow:focus-visible:
   *
   * Whether 'focus rectangles' are currently visible in this window.
   *
851
   * This property is maintained by GTK+ based on user input
852 853 854 855
   * and should not be set by applications.
   *
   * Since: 2.20
   */
856 857 858 859 860 861 862
  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);

863 864 865 866 867 868 869 870
  /**
   * 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
   */
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 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926
  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);

  window_props[PROP_SCREEN] =
      g_param_spec_object ("screen",
                           P_("Screen"),
                           P_("The screen where this window will be displayed"),
                           GDK_TYPE_SCREEN,
                           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_HAS_TOPLEVEL_FOCUS] =
      g_param_spec_boolean ("has-toplevel-focus",
                            P_("Focus in Toplevel"),
                            P_("Whether the input focus is within this GtkWindow"),
                            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"),
                            P_("TRUE if the window should be brought to the user's attention."),
                            FALSE,
                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
927

928
  /**
Matthias Clasen's avatar
Matthias Clasen committed
929
   * GtkWindow:accept-focus:
930 931 932 933 934
   *
   * Whether the window should receive the input focus.
   *
   * Since: 2.4
   */
935 936 937 938 939 940
  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);
941

942
  /**
Matthias Clasen's avatar
Matthias Clasen committed
943
   * GtkWindow:focus-on-map:
944 945 946 947 948
   *
   * Whether the window should receive the input focus when mapped.
   *
   * Since: 2.6
   */
949 950 951 952 953 954
  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,
                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
955

956 957 958 959 960 961 962
  /**
   * GtkWindow:decorated:
   *
   * Whether the window should be decorated by the window manager.
   *
   * Since: 2.4
   */
963 964 965 966 967 968
  window_props[PROP_DECORATED] =
      g_param_spec_boolean ("decorated",
                            P_("Decorated"),
                            P_("Whether the window should be decorated by the window manager"),
                            TRUE,
                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
969

970 971 972 973 974 975 976
  /**
   * GtkWindow:deletable:
   *
   * Whether the window frame should have a close button.
   *
   * Since: 2.10
   */
977 978 979 980 981 982
  window_props[PROP_DELETABLE] =
      g_param_spec_boolean ("deletable",
                            P_("Deletable"),
                            P_("Whether the window frame should have a close button"),
                            TRUE,
                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
983

984 985 986 987 988 989 990 991
  /**
   * GtkWindow:gravity:
   *
   * The window gravity of the window. See gtk_window_move() and #GdkGravity for
   * more details about window gravity.
   *
   * Since: 2.4
   */
992 993 994 995 996 997 998
  window_props[PROP_GRAVITY] =
      g_param_spec_enum ("gravity",
                         P_("Gravity"),
                         P_("The window gravity of the window"),
                         GDK_TYPE_GRAVITY,
                         GDK_GRAVITY_NORTH_WEST,
                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
Alexander Larsson's avatar
Alexander Larsson committed
999 1000 1001 1002 1003 1004 1005 1006 1007

  /**
   * GtkWindow:transient-for:
   *
   * The transient parent of the window. See gtk_window_set_transient_for() for
   * more details about transient windows.
   *
   * Since: 2.10
   */
1008 1009 1010 1011 1012 1013
  window_props[PROP_TRANSIENT_FOR] =
      g_param_spec_object ("transient-for",
                           P_("Transient for Window"),
                           P_("The transient parent of the dialog"),
                           GTK_TYPE_WINDOW,
                           GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY);
Matthias Clasen's avatar
Matthias Clasen committed
1014

1015 1016 1017
  /**
   * GtkWindow:attached-to:
   *
1018 1019 1020 1021 1022 1023 1024
   * The widget to which this window is attached.
   * See gtk_window_set_attached_to().
   *
   * Examples of places where specifying this relation is useful are
   * for instance a #GtkMenu created by a #GtkComboBox, a completion
   * popup window created by #GtkEntry or a typeahead search entry
   * created by #GtkTreeView.
1025 1026 1027
   *
   * Since: 3.4
   */
1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040
  window_props[PROP_ATTACHED_TO] =
      g_param_spec_object ("attached-to",
                           P_("Attached to Widget"),
                           P_("The widget where the window is attached"),
                           GTK_TYPE_WIDGET,
                           GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY);

  window_props[PROP_IS_MAXIMIZED] =
      g_param_spec_boolean ("is-maximized",
                            P_("Is maximized"),
                            P_("Whether the window is maximized"),
                            FALSE,
                            GTK_PARAM_READABLE);
1041

Allison Karlitskaya's avatar
Allison Karlitskaya committed
1042 1043 1044 1045 1046
  /**
   * GtkWindow:application:
   *
   * The #GtkApplication associated with the window.
   *
1047 1048 1049 1050 1051 1052
   * The application will be kept alive for at least as long as it
   * has any windows associated with it (see g_application_hold()
   * for a way to keep it alive without windows).
   *
   * Normally, the connection between the application and the window
   * will remain until the window is destroyed, but you can explicitly
1053
   * remove it by setting the :application property to %NULL.
Allison Karlitskaya's avatar
Allison Karlitskaya committed
1054 1055 1056
   *
   * Since: 3.0
   */
1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080
  window_props[PROP_APPLICATION] =
      g_param_spec_object ("application",
                           P_("GtkApplication"),
                           P_("The GtkApplication for the window"),
                           GTK_TYPE_APPLICATION,
                           GTK_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);

  g_object_class_install_properties (gobject_class,<