gtkwindow.c 358 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"
26

27
#include "gtkwindow.h"
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

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

67 68
#include "gdk/gdk-private.h"

69 70 71 72
#ifdef GDK_WINDOWING_X11
#include "x11/gdkx.h"
#endif

73 74 75 76
#ifdef GDK_WINDOWING_WIN32
#include "win32/gdkwin32.h"
#endif

77 78 79 80
#ifdef GDK_WINDOWING_WAYLAND
#include "wayland/gdkwayland.h"
#endif

81 82 83 84
#ifdef GDK_WINDOWING_BROADWAY
#include "broadway/gdkbroadway.h"
#endif

William Hua's avatar
William Hua committed
85 86 87 88
#ifdef GDK_WINDOWING_MIR
#include "mir/gdkmir.h"
#endif

89 90 91 92 93
/**
 * SECTION:gtkwindow
 * @title: GtkWindow
 * @short_description: Toplevel which can contain other widgets
 *
94 95 96 97 98
 * 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,...).
 *
99
 * # GtkWindow as GtkBuildable
100
 *
101
 * The GtkWindow implementation of the GtkBuildable interface supports a
102 103 104
 * 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().
105
 *
106
 * It also supports the <initial-focus> element, whose name property names
107
 * the widget to receive the focus when the window is mapped.
108
 *
109
 * An example of a UI definition fragment with accel groups:
110
 * |[
111 112 113 114
 * <object class="GtkWindow">
 *   <accel-groups>
 *     <group name="accelgroup1"/>
 *   </accel-groups>
115
 *   <initial-focus name="thunderclap"/>
116
 * </object>
117
 * 
118
 * ...
119
 * 
120
 * <object class="GtkAccelGroup" id="accelgroup1"/>
121
 * ]|
122
 * 
123 124 125
 * 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.
126
 */
127

128
#define MNEMONICS_DELAY 300 /* ms */
129 130 131 132 133 134
#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.
 */
135

136 137 138 139 140
typedef struct _GtkWindowPopover GtkWindowPopover;

struct _GtkWindowPopover
{
  GtkWidget *widget;
141
  GtkWidget *parent;
142 143 144
  GdkWindow *window;
  GtkPositionType pos;
  cairo_rectangle_int_t rect;
145
  gulong unmap_id;
146
  guint clamp_allocation : 1;
147
};
148 149 150 151 152

struct _GtkWindowPrivate
{
  GtkMnemonicHash       *mnemonic_hash;

153
  GtkWidget             *attach_widget;
154
  GtkWidget             *default_widget;
155
  GtkWidget             *initial_focus;
156 157 158 159
  GtkWidget             *focus_widget;
  GtkWindow             *transient_parent;
  GtkWindowGeometryInfo *geometry_info;
  GtkWindowGroup        *group;
160 161
  GdkScreen             *screen;
  GtkApplication        *application;
162

163
  GList                 *popovers;
164

165 166 167 168 169 170 171 172 173
  GdkModifierType        mnemonic_modifier;

  gchar   *startup_id;
  gchar   *title;
  gchar   *wmclass_class;
  gchar   *wmclass_name;
  gchar   *wm_role;

  guint    keys_changed_handler;
174
  guint    delete_event_handler;
175

176 177
  guint32  initial_timestamp;

178 179
  guint16  configure_request_count;

180
  guint    mnemonics_display_timeout_id;
181

182 183
  gint     scale;

184
  gint title_height;
185
  GtkWidget *title_box;
186
  GtkWidget *titlebar;
187
  GtkWidget *popup_menu;
188

189
  GdkWindow *border_window[8];
190
  gint       initial_fullscreen_monitor;
191

192 193 194 195 196 197 198
  /* 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;
199
  guint    need_default_size         : 1;
200 201 202 203 204 205 206 207 208 209 210 211 212 213

  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;
214
  guint    hide_titlebar_when_maximized : 1;
215 216 217 218 219
  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;
220
  guint    focus_visible             : 1;
221 222 223 224 225 226 227 228
  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 */
229 230 231 232 233
  guint    type_hint                 : 3; /* GdkWindowTypeHint if the hint is
                                           * one of the original eight. If not,
                                           * then it contains
                                           * GDK_WINDOW_TYPE_HINT_NORMAL
                                           */
234
  guint    urgent                    : 1;
235
  guint    gravity                   : 5; /* GdkGravity */
236
  guint    csd_requested             : 1;
237
  guint    client_decorated          : 1; /* Decorations drawn client-side */
238
  guint    use_client_shadow         : 1; /* Decorations use client-side shadows */
239
  guint    maximized                 : 1;
240
  guint    fullscreen                : 1;
241
  guint    tiled                     : 1;
242

243 244
  guint    use_subsurface            : 1;

245
  GtkGesture *multipress_gesture;
246
  GtkGesture *drag_gesture;
247 248

  GdkWindow *hardcoded_window;
249 250
};

Elliot Lee's avatar
Elliot Lee committed
251
enum {
252
  SET_FOCUS,
253
  FRAME_EVENT,
254 255
  ACTIVATE_FOCUS,
  ACTIVATE_DEFAULT,
256
  KEYS_CHANGED,
257
  ENABLE_DEBUGGING,
Elliot Lee's avatar
Elliot Lee committed
258 259
  LAST_SIGNAL
};
260

261
enum {
262 263 264 265 266
  PROP_0,

  /* Construct */
  PROP_TYPE,

Havoc Pennington's avatar
Havoc Pennington committed
267
  /* Normal Props */
268
  PROP_TITLE,
269
  PROP_ROLE,
270
  PROP_RESIZABLE,
271 272 273 274 275
  PROP_MODAL,
  PROP_WIN_POS,
  PROP_DEFAULT_WIDTH,
  PROP_DEFAULT_HEIGHT,
  PROP_DESTROY_WITH_PARENT,
276
  PROP_HIDE_TITLEBAR_WHEN_MAXIMIZED,
Havoc Pennington's avatar
Havoc Pennington committed
277
  PROP_ICON,
278
  PROP_ICON_NAME,
279
  PROP_SCREEN,
280 281 282
  PROP_TYPE_HINT,
  PROP_SKIP_TASKBAR_HINT,
  PROP_SKIP_PAGER_HINT,
283
  PROP_URGENCY_HINT,
284
  PROP_ACCEPT_FOCUS,
285
  PROP_FOCUS_ON_MAP,
286
  PROP_DECORATED,
287
  PROP_DELETABLE,
288
  PROP_GRAVITY,
Alexander Larsson's avatar
Alexander Larsson committed
289
  PROP_TRANSIENT_FOR,
290
  PROP_ATTACHED_TO,
291 292
  PROP_HAS_RESIZE_GRIP,
  PROP_RESIZE_GRIP_VISIBLE,
293
  PROP_APPLICATION,
294 295 296
  /* Readonly properties */
  PROP_IS_ACTIVE,
  PROP_HAS_TOPLEVEL_FOCUS,
297

298 299
  /* Writeonly properties */
  PROP_STARTUP_ID,
300

301
  PROP_MNEMONICS_VISIBLE,
302
  PROP_FOCUS_VISIBLE,
303

304 305
  PROP_IS_MAXIMIZED,

306
  LAST_ARG
307
};
Elliot Lee's avatar
Elliot Lee committed
308

309 310
static GParamSpec *window_props[LAST_ARG] = { NULL, };

311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
/* 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
326 327 328
typedef struct
{
  GList     *icon_list;
329
  gchar     *icon_name;
Havoc Pennington's avatar
Havoc Pennington committed
330 331 332
  guint      realized : 1;
  guint      using_default_icon : 1;
  guint      using_parent_icon : 1;
333
  guint      using_themed_icon : 1;
Havoc Pennington's avatar
Havoc Pennington committed
334 335
} GtkWindowIconInfo;

336
typedef struct {
337 338
  GdkGeometry    geometry; /* Last set of geometry hints we set */
  GdkWindowHints flags;
Havoc Pennington's avatar
Havoc Pennington committed
339
  GdkRectangle   configure_request;
340 341
} GtkWindowLastGeometryInfo;

342 343
struct _GtkWindowGeometryInfo
{
344 345 346 347 348
  /* Properties that the app has set on the window
   */
  GdkGeometry    geometry;	/* Geometry hints */
  GdkWindowHints mask;
  GtkWidget     *widget;	/* subwidget to which hints apply */
Havoc Pennington's avatar
Havoc Pennington committed
349 350 351 352 353
  /* from last gtk_window_resize () - if > 0, indicates that
   * we should resize to this size.
   */
  gint           resize_width;  
  gint           resize_height;
354

Havoc Pennington's avatar
Havoc Pennington committed
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
  /* 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;
372

373 374
  /* if true, default_width, height should be multiplied by the
   * increments and affect the geometry widget only
375 376
   */
  guint          default_is_geometry : 1;
377 378 379 380 381

  /* if true, resize_width, height should be multiplied by the
   * increments and affect the geometry widget only
   */
  guint          resize_is_geometry : 1;
Havoc Pennington's avatar
Havoc Pennington committed
382
  
383
  GtkWindowLastGeometryInfo last;
384
};
385

386

387
static void gtk_window_constructed        (GObject           *object);
Tim Janik's avatar
Tim Janik committed
388
static void gtk_window_dispose            (GObject           *object);
389
static void gtk_window_finalize           (GObject           *object);
390
static void gtk_window_destroy            (GtkWidget         *widget);
Elliot Lee's avatar
Elliot Lee committed
391 392 393 394 395
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);
396
static void gtk_window_unrealize          (GtkWidget         *widget);
397 398
static void gtk_window_size_allocate      (GtkWidget         *widget,
					   GtkAllocation     *allocation);
399 400
static gboolean gtk_window_map_event      (GtkWidget         *widget,
                                           GdkEventAny       *event);
Elliot Lee's avatar
Elliot Lee committed
401 402
static gint gtk_window_configure_event    (GtkWidget         *widget,
					   GdkEventConfigure *event);
403 404
static gboolean gtk_window_event          (GtkWidget         *widget,
                                           GdkEvent          *event);
Elliot Lee's avatar
Elliot Lee committed
405 406 407 408 409 410 411 412
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);
413 414
static gboolean gtk_window_state_event    (GtkWidget          *widget,
                                           GdkEventWindowState *event);
415 416
static void gtk_window_remove             (GtkContainer      *container,
                                           GtkWidget         *widget);
417
static void gtk_window_check_resize       (GtkContainer      *container);
418 419 420 421
static void gtk_window_forall             (GtkContainer   *container,
					   gboolean	include_internals,
					   GtkCallback     callback,
					   gpointer        callback_data);
422
static gint gtk_window_focus              (GtkWidget        *widget,
423
				           GtkDirectionType  direction);
424 425
static void gtk_window_move_focus         (GtkWidget         *widget,
                                           GtkDirectionType   dir);
426
static void gtk_window_real_set_focus     (GtkWindow         *window,
427
					   GtkWidget         *focus);
428

429 430
static void gtk_window_real_activate_default (GtkWindow         *window);
static void gtk_window_real_activate_focus   (GtkWindow         *window);
431
static void gtk_window_keys_changed          (GtkWindow         *window);
432
static gboolean gtk_window_enable_debugging  (GtkWindow         *window,
433
                                              gboolean           toggle);
434 435
static gint gtk_window_draw                  (GtkWidget         *widget,
					      cairo_t           *cr);
436 437 438 439 440 441
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);

442 443
static GdkScreen *gtk_window_check_screen (GtkWindow *window);

Havoc Pennington's avatar
Havoc Pennington committed
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475
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);
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,
476 477
                                                      gint          height,
						      gboolean      is_geometry);
Elliot Lee's avatar
Elliot Lee committed
478

479 480 481 482
static void     update_themed_icon                    (GtkIconTheme *theme,
				                       GtkWindow    *window);
static GList   *icon_list_from_theme                  (GtkWidget    *widget,
						       const gchar  *name);
Havoc Pennington's avatar
Havoc Pennington committed
483 484
static void     gtk_window_realize_icon               (GtkWindow    *window);
static void     gtk_window_unrealize_icon             (GtkWindow    *window);
485
static void     update_window_buttons                 (GtkWindow    *window);
486 487
static void     get_shadow_width                      (GtkWidget    *widget,
                                                       GtkBorder    *shadow_width);
488 489 490

static GtkKeyHash *gtk_window_get_key_hash        (GtkWindow   *window);
static void        gtk_window_free_key_hash       (GtkWindow   *window);
491 492
static void	   gtk_window_on_composited_changed (GdkScreen *screen,
						     GtkWindow *window);
493
#ifdef GDK_WINDOWING_X11
494 495 496
static void        gtk_window_on_theme_variant_changed (GtkSettings *settings,
                                                        GParamSpec  *pspec,
                                                        GtkWindow   *window);
497
#endif
498
static void        gtk_window_set_theme_variant         (GtkWindow  *window);
499

500 501
static void        gtk_window_do_popup         (GtkWindow      *window,
                                                GdkEventButton *event);
502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518

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);

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

527 528 529
static GQuark       quark_gtk_embedded = 0;
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

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

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);
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);
566

567
static void ensure_state_flag_backdrop (GtkWidget *widget);
568
static void unset_titlebar (GtkWindow *window);
569 570 571
static void on_titlebar_title_notify (GtkHeaderBar *titlebar,
                                      GParamSpec   *pspec,
                                      GtkWindow    *self);
572 573 574 575 576
static GtkWindowRegion get_active_region_type (GtkWindow   *window,
                                               GdkEventAny *event,
                                               gint         x,
                                               gint         y);

577
static void gtk_window_update_debugging (void);
578

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

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

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

618 619 620 621 622 623 624 625 626 627 628 629 630
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;
631

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

  return retval;
}

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

Elliot Lee's avatar
Elliot Lee committed
648 649 650
static void
gtk_window_class_init (GtkWindowClass *klass)
{
651
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
Elliot Lee's avatar
Elliot Lee committed
652 653
  GtkWidgetClass *widget_class;
  GtkContainerClass *container_class;
654
  GtkBindingSet *binding_set;
655

Elliot Lee's avatar
Elliot Lee committed
656 657
  widget_class = (GtkWidgetClass*) klass;
  container_class = (GtkContainerClass*) klass;
658
  
659 660 661
  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");
662
  quark_gtk_buildable_accels = g_quark_from_static_string ("gtk-window-buildable-accels");
663

664
  gobject_class->constructed = gtk_window_constructed;
Tim Janik's avatar
Tim Janik committed
665
  gobject_class->dispose = gtk_window_dispose;
666 667
  gobject_class->finalize = gtk_window_finalize;

668 669
  gobject_class->set_property = gtk_window_set_property;
  gobject_class->get_property = gtk_window_get_property;
Elliot Lee's avatar
Elliot Lee committed
670

671
  widget_class->destroy = gtk_window_destroy;
Elliot Lee's avatar
Elliot Lee committed
672 673 674
  widget_class->show = gtk_window_show;
  widget_class->hide = gtk_window_hide;
  widget_class->map = gtk_window_map;
675
  widget_class->map_event = gtk_window_map_event;
Elliot Lee's avatar
Elliot Lee committed
676 677
  widget_class->unmap = gtk_window_unmap;
  widget_class->realize = gtk_window_realize;
678
  widget_class->unrealize = gtk_window_unrealize;
679
  widget_class->size_allocate = gtk_window_size_allocate;
Elliot Lee's avatar
Elliot Lee committed
680
  widget_class->configure_event = gtk_window_configure_event;
681
  widget_class->event = gtk_window_event;
Elliot Lee's avatar
Elliot Lee committed
682 683 684 685
  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;
686
  widget_class->focus = gtk_window_focus;
687
  widget_class->move_focus = gtk_window_move_focus;
688
  widget_class->draw = gtk_window_draw;
689
  widget_class->window_state_event = gtk_window_state_event;
690 691 692 693
  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;
694

695
  container_class->remove = gtk_window_remove;
696
  container_class->check_resize = gtk_window_check_resize;
697
  container_class->forall = gtk_window_forall;
Elliot Lee's avatar
Elliot Lee committed
698

699
  klass->set_focus = gtk_window_real_set_focus;
700

701 702
  klass->activate_default = gtk_window_real_activate_default;
  klass->activate_focus = gtk_window_real_activate_focus;
703
  klass->keys_changed = gtk_window_keys_changed;
704
  klass->enable_debugging = gtk_window_enable_debugging;
705

706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726
  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);
727

728 729 730 731 732 733 734 735
  /**
   * 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
736
   */
737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 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
  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);
788

789 790 791 792 793 794 795
  /**
   * GtkWindow:hide-titlebar-when-maximized:
   *
   * Whether the titlebar should be hidden during maximization.
   *
   * Since: 3.4
   */
796 797 798 799 800 801 802 803 804 805 806 807 808
  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);
809 810 811 812 813 814

  /**
   * GtkWindow:mnemonics-visible:
   *
   * Whether mnemonics are currently visible in this window.
   *
815
   * This property is maintained by GTK+ based on user input,
816 817 818 819
   * and should not be set by applications.
   *
   * Since: 2.20
   */
820 821 822 823 824 825
  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);
826 827 828 829 830 831

  /**
   * GtkWindow:focus-visible:
   *
   * Whether 'focus rectangles' are currently visible in this window.
   *
832
   * This property is maintained by GTK+ based on user input
833 834 835 836
   * and should not be set by applications.
   *
   * Since: 2.20
   */
837 838 839 840 841 842 843
  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);

844 845 846 847 848 849 850 851
  /**
   * 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
   */
852 853 854 855 856 857 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
  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);
908

909
  /**
Matthias Clasen's avatar
Matthias Clasen committed
910
   * GtkWindow:accept-focus:
911 912 913 914 915
   *
   * Whether the window should receive the input focus.
   *
   * Since: 2.4
   */
916 917 918 919 920 921
  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);
922

923
  /**
Matthias Clasen's avatar
Matthias Clasen committed
924
   * GtkWindow:focus-on-map:
925 926 927 928 929
   *
   * Whether the window should receive the input focus when mapped.
   *
   * Since: 2.6
   */
930 931 932 933 934 935
  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);
936

937 938 939 940 941 942 943
  /**
   * GtkWindow:decorated:
   *
   * Whether the window should be decorated by the window manager.
   *
   * Since: 2.4
   */
944 945 946 947 948 949
  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);
950

951 952 953 954 955 956 957
  /**
   * GtkWindow:deletable:
   *
   * Whether the window frame should have a close button.
   *
   * Since: 2.10
   */
958 959 960 961 962 963
  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);
964

965
  /**
966
   * GtkWindow:has-resize-grip:
967 968 969 970 971 972 973 974
   *
   * Whether the window has a corner resize grip.
   *
   * Note that the resize grip is only shown if the window is
   * actually resizable and not maximized. Use
   * #GtkWindow:resize-grip-visible to find out if the resize
   * grip is currently shown.
   *
975 976
   * Deprecated: 3.14: Resize grips have been removed.
   *
977 978
   * Since: 3.0
   */
979 980 981 982 983 984
  window_props[PROP_HAS_RESIZE_GRIP] =
      g_param_spec_boolean ("has-resize-grip",
                            P_("Resize grip"),
                            P_("Specifies whether the window should have a resize grip"),
                            FALSE,
                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_DEPRECATED);
985 986

  /**
Matthias Clasen's avatar
Matthias Clasen committed
987
   * GtkWindow:resize-grip-visible:
988 989 990
   *
   * Whether a corner resize grip is currently shown.
   *
991 992
   * Deprecated: 3.14: Resize grips have been removed.
   *
993 994
   * Since: 3.0
   */
995 996 997 998 999 1000
  window_props[PROP_RESIZE_GRIP_VISIBLE] =
      g_param_spec_boolean ("resize-grip-visible",
                            P_("Resize grip is visible"),
                            P_("Specifies whether the window's resize grip is visible."),
                            FALSE,
                            GTK_PARAM_READABLE|G_PARAM_DEPRECATED);
1001

1002 1003 1004 1005 1006 1007 1008 1009
  /**
   * GtkWindow:gravity:
   *
   * The window gravity of the window. See gtk_window_move() and #GdkGravity for
   * more details about window gravity.
   *
   * Since: 2.4
   */
1010 1011 1012 1013 1014 1015 1016
  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
1017 1018 1019 1020 1021 1022 1023 1024 1025

  /**
   * GtkWindow:transient-for:
   *
   * The transient parent of the window. See gtk_window_set_transient_for() for
   * more details about transient windows.
   *
   * Since: 2.10
   */
1026 1027 1028 1029 1030 1031
  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
1032

1033 1034 1035
  /**
   * GtkWindow:attached-to:
   *
1036 1037 1038 1039 1040 1041 1042
   * 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.
1043 1044 1045
   *
   * Since: 3.4
   */
1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058
  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);
1059

1060 1061 1062 1063 1064
  /**
   * GtkWindow:application:
   *
   * The #GtkApplication associated with the window.
   *
1065 1066 1067 1068 1069 1070 1071
   * 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
   * remove it by setting the ::application property to %NULL.
1072 1073 1074
   *
   * Since: 3.0
   */
1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098
  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, LAST_ARG, window_props);

  /* Style properties.
   */
  gtk_widget_class_install_style_property (widget_class,
                                           g_param_spec_string ("decoration-button-layout",
                                                                P_("Decorated button layout"),
                                                                P_("Decorated button layout"),
                                                                "menu:close",
                                                                GTK_PARAM_READABLE|G_PARAM_DEPRECATED));

  gtk_widget_class_install_style_property (widget_class,
                                           g_param_spec_int ("decoration-resize-handle",
                                                             P_("Decoration resize handle size"),
                                                             P_("Decoration resize handle size"),
                                                             0, G_MAXINT,
                                                             20, GTK_PARAM_READWRITE));
1099

1100 1101 1102 1103 1104 1105 1106 1107 1108 1109
  /**
   * GtkWindow:set-focus:
   * @window: the window which received the signal
   * @widget: the newly focused widget (or %NULL for no focus)
   *
   * This signal is emitted whenever the currently focused widget in
   * this window changes.
   *
   * Since: 2.24
   */
1110
  window_signals[SET_FOCUS] =
1111
    g_signal_new (I_("set-focus"),
Manish Singh's avatar
Manish Singh committed
1112
                  G_TYPE_FROM_CLASS (gobject_class),
1113 1114 1115
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkWindowClass, set_focus),
                  NULL, NULL,
1116
                  _gtk_marshal_VOID__OBJECT,
1117 1118
                  G_TYPE_NONE, 1,
                  GTK_TYPE_WIDGET);
1119

Matthias Clasen's avatar
Matthias Clasen committed
1120 1121 1122 1123
  /**
   * GtkWindow::activate-focus:
   * @window: the window which received the signal
   *
1124
   * The ::activate-focus signal is a
1125
   * [keybinding signal][GtkBindingSignal]
Matthias Clasen's avatar
Matthias Clasen committed
1126 1127 1128
   * which gets emitted when the user activates the currently
   * focused widget of @window.
   */
1129
  window_signals[ACTIVATE_FOCUS] =
1130
    g_signal_new (I_("activate-focus"),
Manish Singh's avatar
Manish Singh committed
1131
                  G_TYPE_FROM_CLASS (gobject_class),
1132
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
Manish Singh's avatar
Manish Singh committed
1133
                  G_STRUCT_OFFSET (GtkWindowClass, activate_focus),
1134
                  NULL, NULL,
1135
                  _gtk_marshal_VOID__VOID,
1136 1137
                  G_TYPE_NONE,
                  0);
1138

Matthias Clasen's avatar
Matthias Clasen committed
1139 1140 1141 1142 1143
  /**
   * GtkWindow::activate-default:
   * @window: the window which received the signal
   *
   * The ::activate-default signal is a
1144
   * [keybinding signal][GtkBindingSignal]
Matthias Clasen's avatar
Matthias Clasen committed
1145 1146 1147
   * which gets emitted when the user activates the default widget
   * of @window.
   */
1148
  window_signals[ACTIVATE_DEFAULT] =
1149
    g_signal_new (I_("activate-default"),
Manish Singh's avatar
Manish Singh committed
1150
                  G_TYPE_FROM_CLASS (gobject_class),
1151
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
Manish Singh's avatar
Manish Singh committed
1152
                  G_STRUCT_OFFSET (GtkWindowClass, activate_default),
1153
                  NULL, NULL,
1154
                  _gtk_marshal_VOID__VOID,
1155 1156
                  G_TYPE_NONE,
                  0);
1157

Matthias Clasen's avatar
Matthias Clasen committed
1158 1159 1160 1161 1162 1163 1164
  /**
   * GtkWindow::keys-changed:
   * @window: the window which received the signal
   *
   * The ::keys-changed signal gets emitted when the set of accelerators
   * or mnemonics that are associated with @window changes.
   */
1165
  window_signals[KEYS_CHANGED] =
1166
    g_signal_new (I_("keys-changed"),
Manish Singh's avatar
Manish Singh committed
1167
                  G_TYPE_FROM_CLASS (gobject_class),
1168
                  G_SIGNAL_RUN_FIRST,
Manish Singh's avatar
Manish Singh committed
1169
                  G_STRUCT_OFFSET (GtkWindowClass, keys_changed),
1170
                  NULL, NULL,
Manish Singh's avatar
Manish Singh committed
1171
                  _gtk_marshal_VOID__VOID,
1172 1173
                  G_TYPE_NONE,
                  0);
1174

1175
  /**
1176
   * GtkWindow::enable-debugging:
1177
   * @window: the window on which the signal is emitted
1178
   * @toggle: toggle the debugger
1179
   *
1180 1181 1182 1183 1184
   * The ::enable-debugging signal is a [keybinding signal][GtkBindingSignal]
   * which gets emitted when the user enables or disables interactive
   * debugging. When @toggle is %TRUE, interactive debugging is toggled
   * on or off, when it is %FALSE, the debugger will be pointed at the
   * widget under the pointer.
1185
   *
1186 1187
   * The default bindings for this signal are Ctrl-Shift-I
   * and Ctrl-Shift-D.
1188 1189
   *
   * Return: %TRUE if the key binding was handled
1190
   */
1191 1192
  window_signals[ENABLE_DEBUGGING] =
    g_signal_new (I_("enable-debugging"),
1193 1194
                  G_TYPE_FROM_CLASS (gobject_class),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1195
                  G_STRUCT_OFFSET (GtkWindowClass, enable_debugging),
1196
                  NULL, NULL,
1197 1198
                  _gtk_marshal_BOOLEAN__BOOLEAN,
                  G_TYPE_BOOLEAN,
1199
                  1, G_TYPE_BOOLEAN);
1200

1201 1202 1203 1204 1205 1206
  /*
   * Key bindings
   */

  binding_set = gtk_binding_set_by_class (klass);

1207
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0,
1208
                                "activate-focus", 0);
1209
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0,
1210
                                "activate-focus", 0);
1211
  
1212
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0,
1213
                                "activate-default", 0);
1214
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0,
1215
                                "activate-default", 0);
1216
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0,
1217
                                "activate-default", 0);
1218

1219
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_I, GDK_CONTROL_MASK|GDK_SHIFT_MASK,
1220 1221
                                "enable-debugging", 1,
                                G_TYPE_BOOLEAN, FALSE);
1222
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_D, GDK_CONTROL_MASK|GDK_SHIFT_MASK,
1223 1224
                                "enable-debugging", 1,
                                G_TYPE_BOOLEAN, TRUE);
1225

1226 1227 1228 1229
  add_arrow_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP);
  add_arrow_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN);
  add_arrow_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT);
  add_arrow_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT);
1230

1231 1232 1233 1234
  add_tab_bindings (binding_set, 0, GTK_DIR_TAB_FORWARD);
  add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
  add_tab_bindings (binding_set, GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
  add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1235 1236

  gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_WINDOW_ACCESSIBLE);
Elliot Lee's avatar
Elliot Lee committed
1237 1238
}

1239 1240 1241 1242 1243 1244 1245 1246
/**
 * gtk_window_is_maximized:
 * @window: a #GtkWindow
 *
 * Retrieves the current maximized state of @window.
 *
 * Note that since maximization is ultimately handled by the window
 * manager and happens asynchronously to an application request, you
1247
 * shouldn’t assume the return value of this function changing
1248 1249 1250 1251 1252 1253 1254
 * immediately (or at all), as an effect of calling
 * gtk_window_maximize() or gtk_window_unmaximize().
 *
 * Returns: whether the window has a maximized state.
 *
 * Since: 3.12
 */
1255
gboolean
1256
gtk_window_is_maximized (GtkWindow *window)
1257 1258 1259
{
  GtkWindowPrivate *priv = window->priv;

1260 1261
  g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);

1262 1263 1264 1265 1266
  return priv->maximized;
}

void
_gtk_window_toggle_maximized (GtkWindow *window)
1267
{
1268
  GtkWindowPrivate *priv = window->priv;
1269

1270
  if (priv->maximized)
1271 1272 1273 1274 1275 1276 1277 1278
    gtk_window_unmaximize (window);
  else
    gtk_window_maximize (window);
}

static gboolean
send_delete_event (gpointer data)
{
1279
  GtkWidget *window = data;
1280 1281
  GtkWindowPrivate *priv = GTK_WINDOW (window)->priv;

1282 1283 1284 1285 1286 1287
  GdkEvent *event;

  event = gdk_event_new (GDK_DELETE);

  event->any.window = g_object_ref (gtk_widget_get_window (window));
  event->any.send_event = TRUE;
1288
  priv->delete_event_handler = 0;
1289 1290 1291 1292 1293 1294 1295

  gtk_main_do_event (event);
  gdk_event_free (event);

  return G_SOURCE_REMOVE;
}

1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309
/**
 * gtk_window_close:
 * @window: a #GtkWindow
 *
 * Requests that the window is closed, similar to what happens
 * when a window manager close button is clicked.
 *
 * This function can be used with close buttons in custom
 * titlebars.
 *
 * Since: 3.10
 */
void
gtk_window_close (GtkWindow *window)
1310
{
1311
  if (!_gtk_widget_get_realized (GTK_WIDGET (window)))
1312 1313
    return;

1314
  window->priv->delete_event_handler = gdk_threads_add_idle (send_delete_event, window);
1315
  g_source_set_name_by_id (window->priv->delete_event_handler, "[gtk+] send_delete_event");
1316 1317
}

1318 1319 1320
static void
popover_destroy (GtkWindowPopover *popover)
{
1321 1322 1323 1324 1325 1326
  if (popover->unmap_id)
    {
      g_signal_handler_disconnect (popover->widget, popover->unmap_id);
      popover->unmap_id = 0;
    }

1327
  if (popover->widget && _gtk_widget_get_parent (popover->widget))
1328
    gtk_widget_unparent (popover->widget);
1329 1330 1331 1332 1333 1334 1335

  if (popover->window)
    gdk_window_destroy (popover->window);

  g_free (popover);
}

1336 1337 1338 1339 1340 1341
static gboolean
gtk_window_titlebar_action (GtkWindow      *window,
                            const GdkEvent *event,
                            guint           button,
                            gint            n_press)
{
1342 1343 1344 1345 1346
  GtkSettings *settings;
  gchar *action = NULL;
  gboolean retval = TRUE;

  settings = gtk_widget_get_settings (GTK_WIDGET (window));
1347 1348 1349 1350
  switch (button)
    {
    case GDK_BUTTON_PRIMARY:
      if (n_press == 2)
1351 1352
        g_object_get (settings, "gtk-titlebar-double-click", &action, NULL);
      break;
1353
    case GDK_BUTTON_MIDDLE:
1354 1355
      g_object_get (settings, "gtk-titlebar-middle-click", &action, NULL);
      break;
1356
    case GDK_BUTTON_SECONDARY:
1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377
      g_object_get (settings, "gtk-titlebar-right-click", &action, NULL);
      break;
    }

  if (action == NULL)
    retval = FALSE;
  else if (g_str_equal (action, "none"))
    retval = FALSE;
    /* treat all maximization variants the same */
  else if (g_str_has_prefix (action, "toggle-maximize"))
    _gtk_window_toggle_maximized (window);
  else if (g_str_equal (action, "lower"))
    gdk_window_lower (gtk_widget_get_window (GTK_WIDGET (window)));
  else if (g_str_equal (action, "minimize"))
    gdk_window_iconify (gtk_widget_get_window (GTK_WIDGET (window)));
  else if (g_str_equal (action, "menu"))
    gtk_window_do_popup (window, (GdkEventButton*) event);
  else
    {
      g_warning ("Unsupported titlebar action %s\n", action);
      retval = FALSE;
1378
    }
1379 1380 1381 1382

  g_free (action);

  return retval;
1383 1384
}

1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405
static void
multipress_gesture_pressed_cb (GtkGestureMultiPress *gesture,
                               gint                  n_press,
                               gdouble               x,
                               gdouble               y,
                               GtkWindow            *window)
{
  GtkWidget *event_widget, *widget;
  gboolean window_drag = FALSE;
  GdkEventSequence *sequence;
  GtkWindowRegion region;
  GtkWindowPrivate *priv;
  const GdkEvent *event;
  guint button;

  widget = GTK_WIDGET (window);
  priv = gtk_window_get_instance_private (window);
  sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
  button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
  event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);