]> Pileus Git - ~andy/gtk/blob - gtk/gtkwindow.c
a2f9b18e0da5dcbcafb09e486b713087ea99a26f
[~andy/gtk] / gtk / gtkwindow.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 /*
19  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
20  * file for a list of people on the GTK+ Team.  See the ChangeLog
21  * files for a list of changes.  These files are distributed with
22  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
23  */
24
25 #include "config.h"
26
27 #include "gtkwindow.h"
28
29 #include <string.h>
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <limits.h>
33
34 #include "gtkprivate.h"
35 #include "gtkwindowprivate.h"
36 #include "gtkaccelgroupprivate.h"
37 #include "gtkbindings.h"
38 #include "gtkkeyhash.h"
39 #include "gtkmain.h"
40 #include "gtkmnemonichash.h"
41 #include "gtkmenubar.h"
42 #include "gtkiconfactory.h"
43 #include "gtkicontheme.h"
44 #include "gtkmarshalers.h"
45 #include "gtkplug.h"
46 #include "gtkbuildable.h"
47 #include "gtkwidgetprivate.h"
48 #include "gtkcontainerprivate.h"
49 #include "gtkintl.h"
50 #include "gtkstylecontextprivate.h"
51 #include "gtktypebuiltins.h"
52 #include "a11y/gtkwindowaccessible.h"
53
54 #include "deprecated/gtkstyle.h"
55
56 #ifdef GDK_WINDOWING_X11
57 #include "x11/gdkx.h"
58 #endif
59
60 /**
61  * SECTION:gtkwindow
62  * @title: GtkWindow
63  * @short_description: Toplevel which can contain other widgets
64  *
65  * A GtkWindow is a toplevel window which can contain other widgets.
66  * Windows normally have decorations that are under the control
67  * of the windowing system and allow the user to manipulate the window
68  * (resize it, move it, close it,...).
69  *
70  * GTK+ also allows windows to have a resize grip (a small area in the lower
71  * right or left corner) which can be clicked to reszie the window. To
72  * control whether a window has a resize grip, use
73  * gtk_window_set_has_resize_grip().
74  *
75  * <refsect2 id="GtkWindow-BUILDER-UI">
76  * <title>GtkWindow as GtkBuildable</title>
77  * <para>
78  * The GtkWindow implementation of the GtkBuildable interface supports a
79  * custom <tag class="starttag">accel-groups</tag> element, which supports
80  * any number of <tag class="starttag">group</tag> elements representing the
81  * #GtkAccelGroup objects you want to add to your window (synonymous with
82  * gtk_window_add_accel_group().
83  * </para>
84  * <example>
85  * <title>A UI definition fragment with accel groups</title>
86  * <programlisting><![CDATA[
87  * <object class="GtkWindow">
88  *   <accel-groups>
89  *     <group name="accelgroup1"/>
90  *   </accel-groups>
91  * </object>
92  * <!-- -->
93  * ...
94  * <!-- -->
95  * <object class="GtkAccelGroup" id="accelgroup1"/>
96  * ]]></programlisting>
97  * </example>
98  * </refsect2>
99  */
100
101 #define AUTO_MNEMONICS_DELAY 300 /* ms */
102
103 typedef struct _GtkDeviceGrabInfo GtkDeviceGrabInfo;
104
105 struct _GtkWindowPrivate
106 {
107   GtkMnemonicHash       *mnemonic_hash;
108
109   GtkWidget             *attach_widget;
110   GtkWidget             *default_widget;
111   GtkWidget             *focus_widget;
112   GtkWindow             *transient_parent;
113   GtkWindowGeometryInfo *geometry_info;
114   GtkWindowGroup        *group;
115   GdkScreen             *screen;
116   GtkApplication        *application;
117
118   GdkModifierType        mnemonic_modifier;
119   GdkWindowTypeHint      gdk_type_hint;
120
121   GdkWindow *grip_window;
122
123   gchar   *startup_id;
124   gchar   *title;
125   gchar   *wmclass_class;
126   gchar   *wmclass_name;
127   gchar   *wm_role;
128
129   guint    keys_changed_handler;
130
131   guint32  initial_timestamp;
132
133   guint16  configure_request_count;
134
135   guint    auto_mnemonics_timeout_id;
136
137   /* The following flags are initially TRUE (before a window is mapped).
138    * They cause us to compute a configure request that involves
139    * default-only parameters. Once mapped, we set them to FALSE.
140    * Then we set them to TRUE again on unmap (for position)
141    * and on unrealize (for size).
142    */
143   guint    need_default_position     : 1;
144   guint    need_default_size         : 1;
145
146   guint    above_initially           : 1;
147   guint    accept_focus              : 1;
148   guint    below_initially           : 1;
149   guint    builder_visible           : 1;
150   guint    configure_notify_received : 1;
151   guint    decorated                 : 1;
152   guint    deletable                 : 1;
153   guint    destroy_with_parent       : 1;
154   guint    focus_on_map              : 1;
155   guint    fullscreen_initially      : 1;
156   guint    has_focus                 : 1;
157   guint    has_user_ref_count        : 1;
158   guint    has_toplevel_focus        : 1;
159   guint    hide_titlebar_when_maximized : 1;
160   guint    iconify_initially         : 1; /* gtk_window_iconify() called before realization */
161   guint    is_active                 : 1;
162   guint    maximize_initially        : 1;
163   guint    mnemonics_visible         : 1;
164   guint    mnemonics_visible_set     : 1;
165   guint    focus_visible             : 1;
166   guint    modal                     : 1;
167   guint    position                  : 3;
168   guint    reset_type_hint           : 1;
169   guint    resizable                 : 1;
170   guint    skips_pager               : 1;
171   guint    skips_taskbar             : 1;
172   guint    stick_initially           : 1;
173   guint    transient_parent_group    : 1;
174   guint    type                      : 4; /* GtkWindowType */
175   guint    type_hint                 : 3; /* GdkWindowTypeHint if the hint is
176                                            * one of the original eight. If not,
177                                            * then it contains
178                                            * GDK_WINDOW_TYPE_HINT_NORMAL
179                                            */
180   guint    urgent                    : 1;
181   guint    has_resize_grip           : 1;
182   guint    resize_grip_visible       : 1;  /* don't use, just for "resize-
183                                             * grip-visible" notification
184                                             */
185   guint    gravity                   : 5; /* GdkGravity */
186
187 };
188
189 enum {
190   SET_FOCUS,
191   FRAME_EVENT,
192   ACTIVATE_FOCUS,
193   ACTIVATE_DEFAULT,
194   KEYS_CHANGED,
195   LAST_SIGNAL
196 };
197
198 enum {
199   PROP_0,
200
201   /* Construct */
202   PROP_TYPE,
203
204   /* Normal Props */
205   PROP_TITLE,
206   PROP_ROLE,
207   PROP_RESIZABLE,
208   PROP_MODAL,
209   PROP_WIN_POS,
210   PROP_DEFAULT_WIDTH,
211   PROP_DEFAULT_HEIGHT,
212   PROP_DESTROY_WITH_PARENT,
213   PROP_HIDE_TITLEBAR_WHEN_MAXIMIZED,
214   PROP_ICON,
215   PROP_ICON_NAME,
216   PROP_SCREEN,
217   PROP_TYPE_HINT,
218   PROP_SKIP_TASKBAR_HINT,
219   PROP_SKIP_PAGER_HINT,
220   PROP_URGENCY_HINT,
221   PROP_ACCEPT_FOCUS,
222   PROP_FOCUS_ON_MAP,
223   PROP_DECORATED,
224   PROP_DELETABLE,
225   PROP_GRAVITY,
226   PROP_TRANSIENT_FOR,
227   PROP_ATTACHED_TO,
228   PROP_HAS_RESIZE_GRIP,
229   PROP_RESIZE_GRIP_VISIBLE,
230   PROP_APPLICATION,
231   /* Readonly properties */
232   PROP_IS_ACTIVE,
233   PROP_HAS_TOPLEVEL_FOCUS,
234
235   /* Writeonly properties */
236   PROP_STARTUP_ID,
237
238   PROP_MNEMONICS_VISIBLE,
239   PROP_FOCUS_VISIBLE,
240
241   LAST_ARG
242 };
243
244 typedef struct
245 {
246   GList     *icon_list;
247   gchar     *icon_name;
248   guint      realized : 1;
249   guint      using_default_icon : 1;
250   guint      using_parent_icon : 1;
251   guint      using_themed_icon : 1;
252 } GtkWindowIconInfo;
253
254 typedef struct {
255   GdkGeometry    geometry; /* Last set of geometry hints we set */
256   GdkWindowHints flags;
257   GdkRectangle   configure_request;
258 } GtkWindowLastGeometryInfo;
259
260 struct _GtkWindowGeometryInfo
261 {
262   /* Properties that the app has set on the window
263    */
264   GdkGeometry    geometry;      /* Geometry hints */
265   GdkWindowHints mask;
266   GtkWidget     *widget;        /* subwidget to which hints apply */
267   /* from last gtk_window_resize () - if > 0, indicates that
268    * we should resize to this size.
269    */
270   gint           resize_width;  
271   gint           resize_height;
272
273   /* From last gtk_window_move () prior to mapping -
274    * only used if initial_pos_set
275    */
276   gint           initial_x;
277   gint           initial_y;
278   
279   /* Default size - used only the FIRST time we map a window,
280    * only if > 0.
281    */
282   gint           default_width; 
283   gint           default_height;
284   /* whether to use initial_x, initial_y */
285   guint          initial_pos_set : 1;
286   /* CENTER_ALWAYS or other position constraint changed since
287    * we sent the last configure request.
288    */
289   guint          position_constraints_changed : 1;
290
291   /* if true, default_width, height should be multiplied by the
292    * increments and affect the geometry widget only
293    */
294   guint          default_is_geometry : 1;
295
296   /* if true, resize_width, height should be multiplied by the
297    * increments and affect the geometry widget only
298    */
299   guint          resize_is_geometry : 1;
300   
301   GtkWindowLastGeometryInfo last;
302 };
303
304
305 struct _GtkDeviceGrabInfo
306 {
307   GtkWidget *widget;
308   GdkDevice *device;
309   guint block_others : 1;
310 };
311
312 struct _GtkWindowGroupPrivate
313 {
314   GSList *grabs;
315   GSList *device_grabs;
316 };
317
318 static void gtk_window_dispose            (GObject           *object);
319 static void gtk_window_finalize           (GObject           *object);
320 static void gtk_window_destroy            (GtkWidget         *widget);
321 static void gtk_window_show               (GtkWidget         *widget);
322 static void gtk_window_hide               (GtkWidget         *widget);
323 static void gtk_window_map                (GtkWidget         *widget);
324 static void gtk_window_unmap              (GtkWidget         *widget);
325 static void gtk_window_realize            (GtkWidget         *widget);
326 static void gtk_window_unrealize          (GtkWidget         *widget);
327 static void gtk_window_size_allocate      (GtkWidget         *widget,
328                                            GtkAllocation     *allocation);
329 static gboolean gtk_window_map_event      (GtkWidget         *widget,
330                                            GdkEventAny       *event);
331 static gint gtk_window_configure_event    (GtkWidget         *widget,
332                                            GdkEventConfigure *event);
333 static gint gtk_window_key_press_event    (GtkWidget         *widget,
334                                            GdkEventKey       *event);
335 static gint gtk_window_key_release_event  (GtkWidget         *widget,
336                                            GdkEventKey       *event);
337 static gint gtk_window_button_press_event (GtkWidget         *widget,
338                                            GdkEventButton    *event);
339 static gint gtk_window_enter_notify_event (GtkWidget         *widget,
340                                            GdkEventCrossing  *event);
341 static gint gtk_window_leave_notify_event (GtkWidget         *widget,
342                                            GdkEventCrossing  *event);
343 static gint gtk_window_focus_in_event     (GtkWidget         *widget,
344                                            GdkEventFocus     *event);
345 static gint gtk_window_focus_out_event    (GtkWidget         *widget,
346                                            GdkEventFocus     *event);
347 static void gtk_window_style_updated      (GtkWidget         *widget);
348 static gboolean gtk_window_state_event    (GtkWidget          *widget,
349                                            GdkEventWindowState *event);
350 static void gtk_window_check_resize       (GtkContainer      *container);
351 static gint gtk_window_focus              (GtkWidget        *widget,
352                                            GtkDirectionType  direction);
353 static void gtk_window_move_focus         (GtkWidget         *widget,
354                                            GtkDirectionType   dir);
355 static void gtk_window_real_set_focus     (GtkWindow         *window,
356                                            GtkWidget         *focus);
357 static void gtk_window_direction_changed  (GtkWidget         *widget,
358                                            GtkTextDirection   prev_dir);
359 static void gtk_window_state_changed      (GtkWidget         *widget,
360                                            GtkStateType       previous_state);
361
362 static void gtk_window_real_activate_default (GtkWindow         *window);
363 static void gtk_window_real_activate_focus   (GtkWindow         *window);
364 static void gtk_window_keys_changed          (GtkWindow         *window);
365 static gint gtk_window_draw                  (GtkWidget         *widget,
366                                               cairo_t           *cr);
367 static void gtk_window_unset_transient_for         (GtkWindow  *window);
368 static void gtk_window_transient_parent_realized   (GtkWidget  *parent,
369                                                     GtkWidget  *window);
370 static void gtk_window_transient_parent_unrealized (GtkWidget  *parent,
371                                                     GtkWidget  *window);
372
373 static GdkScreen *gtk_window_check_screen (GtkWindow *window);
374
375 static GtkWindowGeometryInfo* gtk_window_get_geometry_info         (GtkWindow    *window,
376                                                                     gboolean      create);
377
378 static void     gtk_window_move_resize               (GtkWindow    *window);
379 static gboolean gtk_window_compare_hints             (GdkGeometry  *geometry_a,
380                                                       guint         flags_a,
381                                                       GdkGeometry  *geometry_b,
382                                                       guint         flags_b);
383 static void     gtk_window_constrain_size            (GtkWindow    *window,
384                                                       GdkGeometry  *geometry,
385                                                       guint         flags,
386                                                       gint          width,
387                                                       gint          height,
388                                                       gint         *new_width,
389                                                       gint         *new_height);
390 static void     gtk_window_constrain_position        (GtkWindow    *window,
391                                                       gint          new_width,
392                                                       gint          new_height,
393                                                       gint         *x,
394                                                       gint         *y);
395 static void     gtk_window_compute_hints             (GtkWindow    *window,
396                                                       GdkGeometry  *new_geometry,
397                                                       guint        *new_flags);
398 static void     gtk_window_compute_configure_request (GtkWindow    *window,
399                                                       GdkRectangle *request,
400                                                       GdkGeometry  *geometry,
401                                                       guint        *flags);
402
403 static void     gtk_window_set_default_size_internal (GtkWindow    *window,
404                                                       gboolean      change_width,
405                                                       gint          width,
406                                                       gboolean      change_height,
407                                                       gint          height,
408                                                       gboolean      is_geometry);
409
410 static void     update_themed_icon                    (GtkIconTheme *theme,
411                                                        GtkWindow    *window);
412 static GList   *icon_list_from_theme                  (GtkWidget    *widget,
413                                                        const gchar  *name);
414 static void     gtk_window_realize_icon               (GtkWindow    *window);
415 static void     gtk_window_unrealize_icon             (GtkWindow    *window);
416 static void     resize_grip_create_window             (GtkWindow    *window);
417 static void     resize_grip_destroy_window            (GtkWindow    *window);
418 static void     update_grip_visibility                (GtkWindow    *window);
419
420 static void        gtk_window_notify_keys_changed (GtkWindow   *window);
421 static GtkKeyHash *gtk_window_get_key_hash        (GtkWindow   *window);
422 static void        gtk_window_free_key_hash       (GtkWindow   *window);
423 static void        gtk_window_on_composited_changed (GdkScreen *screen,
424                                                      GtkWindow *window);
425 static void        gtk_window_on_theme_variant_changed (GtkSettings *settings,
426                                                         GParamSpec  *pspec,
427                                                         GtkWindow   *window);
428 static void        gtk_window_set_theme_variant         (GtkWindow  *window);
429
430 static GSList      *toplevel_list = NULL;
431 static guint        window_signals[LAST_SIGNAL] = { 0 };
432 static GList       *default_icon_list = NULL;
433 static gchar       *default_icon_name = NULL;
434 static guint        default_icon_serial = 0;
435 static gboolean     disable_startup_notification = FALSE;
436 static gboolean     sent_startup_notification = FALSE;
437
438 static GQuark       quark_gtk_embedded = 0;
439 static GQuark       quark_gtk_window_key_hash = 0;
440 static GQuark       quark_gtk_window_icon_info = 0;
441 static GQuark       quark_gtk_buildable_accels = 0;
442
443 static GtkBuildableIface *parent_buildable_iface;
444
445 static void gtk_window_set_property (GObject         *object,
446                                      guint            prop_id,
447                                      const GValue    *value,
448                                      GParamSpec      *pspec);
449 static void gtk_window_get_property (GObject         *object,
450                                      guint            prop_id,
451                                      GValue          *value,
452                                      GParamSpec      *pspec);
453
454 /* GtkBuildable */
455 static void gtk_window_buildable_interface_init  (GtkBuildableIface *iface);
456 static void gtk_window_buildable_set_buildable_property (GtkBuildable        *buildable,
457                                                          GtkBuilder          *builder,
458                                                          const gchar         *name,
459                                                          const GValue        *value);
460 static void gtk_window_buildable_parser_finished (GtkBuildable     *buildable,
461                                                   GtkBuilder       *builder);
462 static gboolean gtk_window_buildable_custom_tag_start (GtkBuildable  *buildable,
463                                                        GtkBuilder    *builder,
464                                                        GObject       *child,
465                                                        const gchar   *tagname,
466                                                        GMarkupParser *parser,
467                                                        gpointer      *data);
468 static void gtk_window_buildable_custom_finished (GtkBuildable  *buildable,
469                                                       GtkBuilder    *builder,
470                                                       GObject       *child,
471                                                       const gchar   *tagname,
472                                                       gpointer       user_data);
473
474 static void ensure_state_flag_backdrop (GtkWidget *widget);
475
476 G_DEFINE_TYPE_WITH_CODE (GtkWindow, gtk_window, GTK_TYPE_BIN,
477                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
478                                                 gtk_window_buildable_interface_init))
479
480 static void
481 add_tab_bindings (GtkBindingSet    *binding_set,
482                   GdkModifierType   modifiers,
483                   GtkDirectionType  direction)
484 {
485   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, modifiers,
486                                 "move-focus", 1,
487                                 GTK_TYPE_DIRECTION_TYPE, direction);
488   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, modifiers,
489                                 "move-focus", 1,
490                                 GTK_TYPE_DIRECTION_TYPE, direction);
491 }
492
493 static void
494 add_arrow_bindings (GtkBindingSet    *binding_set,
495                     guint             keysym,
496                     GtkDirectionType  direction)
497 {
498   guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
499   
500   gtk_binding_entry_add_signal (binding_set, keysym, 0,
501                                 "move-focus", 1,
502                                 GTK_TYPE_DIRECTION_TYPE, direction);
503   gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
504                                 "move-focus", 1,
505                                 GTK_TYPE_DIRECTION_TYPE, direction);
506   gtk_binding_entry_add_signal (binding_set, keypad_keysym, 0,
507                                 "move-focus", 1,
508                                 GTK_TYPE_DIRECTION_TYPE, direction);
509   gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
510                                 "move-focus", 1,
511                                 GTK_TYPE_DIRECTION_TYPE, direction);
512 }
513
514 static guint32
515 extract_time_from_startup_id (const gchar* startup_id)
516 {
517   gchar *timestr = g_strrstr (startup_id, "_TIME");
518   guint32 retval = GDK_CURRENT_TIME;
519
520   if (timestr)
521     {
522       gchar *end;
523       guint32 timestamp; 
524     
525       /* Skip past the "_TIME" part */
526       timestr += 5;
527
528       end = NULL;
529       errno = 0;
530       timestamp = g_ascii_strtoull (timestr, &end, 0);
531       if (errno == 0 && end != timestr)
532         retval = timestamp;
533     }
534
535   return retval;
536 }
537
538 static gboolean
539 startup_id_is_fake (const gchar* startup_id)
540 {
541   return strncmp (startup_id, "_TIME", 5) == 0;
542 }
543
544 static void
545 gtk_window_class_init (GtkWindowClass *klass)
546 {
547   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
548   GtkWidgetClass *widget_class;
549   GtkContainerClass *container_class;
550   GtkBindingSet *binding_set;
551
552   widget_class = (GtkWidgetClass*) klass;
553   container_class = (GtkContainerClass*) klass;
554   
555   quark_gtk_embedded = g_quark_from_static_string ("gtk-embedded");
556   quark_gtk_window_key_hash = g_quark_from_static_string ("gtk-window-key-hash");
557   quark_gtk_window_icon_info = g_quark_from_static_string ("gtk-window-icon-info");
558   quark_gtk_buildable_accels = g_quark_from_static_string ("gtk-window-buildable-accels");
559
560   gobject_class->dispose = gtk_window_dispose;
561   gobject_class->finalize = gtk_window_finalize;
562
563   gobject_class->set_property = gtk_window_set_property;
564   gobject_class->get_property = gtk_window_get_property;
565
566   widget_class->destroy = gtk_window_destroy;
567   widget_class->show = gtk_window_show;
568   widget_class->hide = gtk_window_hide;
569   widget_class->map = gtk_window_map;
570   widget_class->map_event = gtk_window_map_event;
571   widget_class->unmap = gtk_window_unmap;
572   widget_class->realize = gtk_window_realize;
573   widget_class->unrealize = gtk_window_unrealize;
574   widget_class->size_allocate = gtk_window_size_allocate;
575   widget_class->configure_event = gtk_window_configure_event;
576   widget_class->key_press_event = gtk_window_key_press_event;
577   widget_class->key_release_event = gtk_window_key_release_event;
578   widget_class->enter_notify_event = gtk_window_enter_notify_event;
579   widget_class->leave_notify_event = gtk_window_leave_notify_event;
580   widget_class->focus_in_event = gtk_window_focus_in_event;
581   widget_class->button_press_event = gtk_window_button_press_event;
582   widget_class->focus_out_event = gtk_window_focus_out_event;
583   widget_class->focus = gtk_window_focus;
584   widget_class->move_focus = gtk_window_move_focus;
585   widget_class->draw = gtk_window_draw;
586   widget_class->window_state_event = gtk_window_state_event;
587   widget_class->direction_changed = gtk_window_direction_changed;
588   widget_class->state_changed = gtk_window_state_changed;
589   widget_class->style_updated = gtk_window_style_updated;
590
591   container_class->check_resize = gtk_window_check_resize;
592
593   klass->set_focus = gtk_window_real_set_focus;
594
595   klass->activate_default = gtk_window_real_activate_default;
596   klass->activate_focus = gtk_window_real_activate_focus;
597   klass->keys_changed = gtk_window_keys_changed;
598
599   g_type_class_add_private (gobject_class, sizeof (GtkWindowPrivate));
600
601   /* Construct */
602   g_object_class_install_property (gobject_class,
603                                    PROP_TYPE,
604                                    g_param_spec_enum ("type",
605                                                       P_("Window Type"),
606                                                       P_("The type of the window"),
607                                                       GTK_TYPE_WINDOW_TYPE,
608                                                       GTK_WINDOW_TOPLEVEL,
609                                                       GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
610   /* Regular Props */
611   g_object_class_install_property (gobject_class,
612                                    PROP_TITLE,
613                                    g_param_spec_string ("title",
614                                                         P_("Window Title"),
615                                                         P_("The title of the window"),
616                                                         NULL,
617                                                         GTK_PARAM_READWRITE));
618
619   g_object_class_install_property (gobject_class,
620                                    PROP_ROLE,
621                                    g_param_spec_string ("role",
622                                                         P_("Window Role"),
623                                                         P_("Unique identifier for the window to be used when restoring a session"),
624                                                         NULL,
625                                                         GTK_PARAM_READWRITE));
626
627   /**
628    * GtkWindow:startup-id:
629    *
630    * The :startup-id is a write-only property for setting window's
631    * startup notification identifier. See gtk_window_set_startup_id()
632    * for more details.
633    *
634    * Since: 2.12
635    */
636   g_object_class_install_property (gobject_class,
637                                    PROP_STARTUP_ID,
638                                    g_param_spec_string ("startup-id",
639                                                         P_("Startup ID"),
640                                                         P_("Unique startup identifier for the window used by startup-notification"),
641                                                         NULL,
642                                                         GTK_PARAM_WRITABLE));
643
644   g_object_class_install_property (gobject_class,
645                                    PROP_RESIZABLE,
646                                    g_param_spec_boolean ("resizable",
647                                                          P_("Resizable"),
648                                                          P_("If TRUE, users can resize the window"),
649                                                          TRUE,
650                                                          GTK_PARAM_READWRITE));
651   
652   g_object_class_install_property (gobject_class,
653                                    PROP_MODAL,
654                                    g_param_spec_boolean ("modal",
655                                                          P_("Modal"),
656                                                          P_("If TRUE, the window is modal (other windows are not usable while this one is up)"),
657                                                          FALSE,
658                                                          GTK_PARAM_READWRITE));
659
660   g_object_class_install_property (gobject_class,
661                                    PROP_WIN_POS,
662                                    g_param_spec_enum ("window-position",
663                                                       P_("Window Position"),
664                                                       P_("The initial position of the window"),
665                                                       GTK_TYPE_WINDOW_POSITION,
666                                                       GTK_WIN_POS_NONE,
667                                                       GTK_PARAM_READWRITE));
668  
669   g_object_class_install_property (gobject_class,
670                                    PROP_DEFAULT_WIDTH,
671                                    g_param_spec_int ("default-width",
672                                                      P_("Default Width"),
673                                                      P_("The default width of the window, used when initially showing the window"),
674                                                      -1,
675                                                      G_MAXINT,
676                                                      -1,
677                                                      GTK_PARAM_READWRITE));
678   
679   g_object_class_install_property (gobject_class,
680                                    PROP_DEFAULT_HEIGHT,
681                                    g_param_spec_int ("default-height",
682                                                      P_("Default Height"),
683                                                      P_("The default height of the window, used when initially showing the window"),
684                                                      -1,
685                                                      G_MAXINT,
686                                                      -1,
687                                                      GTK_PARAM_READWRITE));
688   
689   g_object_class_install_property (gobject_class,
690                                    PROP_DESTROY_WITH_PARENT,
691                                    g_param_spec_boolean ("destroy-with-parent",
692                                                          P_("Destroy with Parent"),
693                                                          P_("If this window should be destroyed when the parent is destroyed"),
694                                                          FALSE,
695                                                          GTK_PARAM_READWRITE));
696
697   /**
698    * GtkWindow:hide-titlebar-when-maximized:
699    *
700    * Whether the titlebar should be hidden during maximization.
701    *
702    * Since: 3.4
703    */
704   g_object_class_install_property (gobject_class,
705                                    PROP_HIDE_TITLEBAR_WHEN_MAXIMIZED,
706                                    g_param_spec_boolean ("hide-titlebar-when-maximized",
707                                                          P_("Hide the titlebar during maximization"),
708                                                          P_("If this window's titlebar should be hidden when the window is maximized"),
709                                                          FALSE,
710                                                          GTK_PARAM_READWRITE));
711
712   g_object_class_install_property (gobject_class,
713                                    PROP_ICON,
714                                    g_param_spec_object ("icon",
715                                                         P_("Icon"),
716                                                         P_("Icon for this window"),
717                                                         GDK_TYPE_PIXBUF,
718                                                         GTK_PARAM_READWRITE));
719
720   /**
721    * GtkWindow:mnemonics-visible:
722    *
723    * Whether mnemonics are currently visible in this window.
724    *
725    * This property is maintained by GTK+ based on the
726    * #GtkSettings:gtk-auto-mnemonics setting and user input,
727    * and should not be set by applications.
728    *
729    * Since: 2.20
730    */
731   g_object_class_install_property (gobject_class,
732                                    PROP_MNEMONICS_VISIBLE,
733                                    g_param_spec_boolean ("mnemonics-visible",
734                                                          P_("Mnemonics Visible"),
735                                                          P_("Whether mnemonics are currently visible in this window"),
736                                                          TRUE,
737                                                          GTK_PARAM_READWRITE));
738
739   /**
740    * GtkWindow:focus-visible:
741    *
742    * Whether 'focus rectangles' are currently visible in this window.
743    *
744    * This property is maintained by GTK+ based on the
745    * #GtkSettings:gtk-visible-focus setting and user input
746    * and should not be set by applications.
747    *
748    * Since: 2.20
749    */
750   g_object_class_install_property (gobject_class,
751                                    PROP_FOCUS_VISIBLE,
752                                    g_param_spec_boolean ("focus-visible",
753                                                          P_("Focus Visible"),
754                                                          P_("Whether focus rectangles are currently visible in this window"),
755                                                          TRUE,
756                                                          GTK_PARAM_READWRITE));
757   
758   /**
759    * GtkWindow:icon-name:
760    *
761    * The :icon-name property specifies the name of the themed icon to
762    * use as the window icon. See #GtkIconTheme for more details.
763    *
764    * Since: 2.6
765    */
766   g_object_class_install_property (gobject_class,
767                                    PROP_ICON_NAME,
768                                    g_param_spec_string ("icon-name",
769                                                         P_("Icon Name"),
770                                                         P_("Name of the themed icon for this window"),
771                                                         NULL,
772                                                         GTK_PARAM_READWRITE));
773   
774   g_object_class_install_property (gobject_class,
775                                    PROP_SCREEN,
776                                    g_param_spec_object ("screen",
777                                                         P_("Screen"),
778                                                         P_("The screen where this window will be displayed"),
779                                                         GDK_TYPE_SCREEN,
780                                                         GTK_PARAM_READWRITE));
781
782   g_object_class_install_property (gobject_class,
783                                    PROP_IS_ACTIVE,
784                                    g_param_spec_boolean ("is-active",
785                                                          P_("Is Active"),
786                                                          P_("Whether the toplevel is the current active window"),
787                                                          FALSE,
788                                                          GTK_PARAM_READABLE));
789   
790   g_object_class_install_property (gobject_class,
791                                    PROP_HAS_TOPLEVEL_FOCUS,
792                                    g_param_spec_boolean ("has-toplevel-focus",
793                                                          P_("Focus in Toplevel"),
794                                                          P_("Whether the input focus is within this GtkWindow"),
795                                                          FALSE,
796                                                          GTK_PARAM_READABLE));
797
798   g_object_class_install_property (gobject_class,
799                                    PROP_TYPE_HINT,
800                                    g_param_spec_enum ("type-hint",
801                                                       P_("Type hint"),
802                                                       P_("Hint to help the desktop environment understand what kind of window this is and how to treat it."),
803                                                       GDK_TYPE_WINDOW_TYPE_HINT,
804                                                       GDK_WINDOW_TYPE_HINT_NORMAL,
805                                                       GTK_PARAM_READWRITE));
806
807   g_object_class_install_property (gobject_class,
808                                    PROP_SKIP_TASKBAR_HINT,
809                                    g_param_spec_boolean ("skip-taskbar-hint",
810                                                          P_("Skip taskbar"),
811                                                          P_("TRUE if the window should not be in the task bar."),
812                                                          FALSE,
813                                                          GTK_PARAM_READWRITE));
814
815   g_object_class_install_property (gobject_class,
816                                    PROP_SKIP_PAGER_HINT,
817                                    g_param_spec_boolean ("skip-pager-hint",
818                                                          P_("Skip pager"),
819                                                          P_("TRUE if the window should not be in the pager."),
820                                                          FALSE,
821                                                          GTK_PARAM_READWRITE));  
822
823   g_object_class_install_property (gobject_class,
824                                    PROP_URGENCY_HINT,
825                                    g_param_spec_boolean ("urgency-hint",
826                                                          P_("Urgent"),
827                                                          P_("TRUE if the window should be brought to the user's attention."),
828                                                          FALSE,
829                                                          GTK_PARAM_READWRITE));  
830
831   /**
832    * GtkWindow:accept-focus:
833    *
834    * Whether the window should receive the input focus.
835    *
836    * Since: 2.4
837    */
838   g_object_class_install_property (gobject_class,
839                                    PROP_ACCEPT_FOCUS,
840                                    g_param_spec_boolean ("accept-focus",
841                                                          P_("Accept focus"),
842                                                          P_("TRUE if the window should receive the input focus."),
843                                                          TRUE,
844                                                          GTK_PARAM_READWRITE));  
845
846   /**
847    * GtkWindow:focus-on-map:
848    *
849    * Whether the window should receive the input focus when mapped.
850    *
851    * Since: 2.6
852    */
853   g_object_class_install_property (gobject_class,
854                                    PROP_FOCUS_ON_MAP,
855                                    g_param_spec_boolean ("focus-on-map",
856                                                          P_("Focus on map"),
857                                                          P_("TRUE if the window should receive the input focus when mapped."),
858                                                          TRUE,
859                                                          GTK_PARAM_READWRITE));  
860
861   /**
862    * GtkWindow:decorated:
863    *
864    * Whether the window should be decorated by the window manager.
865    *
866    * Since: 2.4
867    */
868   g_object_class_install_property (gobject_class,
869                                    PROP_DECORATED,
870                                    g_param_spec_boolean ("decorated",
871                                                          P_("Decorated"),
872                                                          P_("Whether the window should be decorated by the window manager"),
873                                                          TRUE,
874                                                          GTK_PARAM_READWRITE));
875
876   /**
877    * GtkWindow:deletable:
878    *
879    * Whether the window frame should have a close button.
880    *
881    * Since: 2.10
882    */
883   g_object_class_install_property (gobject_class,
884                                    PROP_DELETABLE,
885                                    g_param_spec_boolean ("deletable",
886                                                          P_("Deletable"),
887                                                          P_("Whether the window frame should have a close button"),
888                                                          TRUE,
889                                                          GTK_PARAM_READWRITE));
890
891   /**
892    * GtkWindow:has-resize-grip:
893    *
894    * Whether the window has a corner resize grip.
895    *
896    * Note that the resize grip is only shown if the window is
897    * actually resizable and not maximized. Use
898    * #GtkWindow:resize-grip-visible to find out if the resize
899    * grip is currently shown.
900    *
901    * Since: 3.0
902    */
903   g_object_class_install_property (gobject_class,
904                                    PROP_HAS_RESIZE_GRIP,
905                                    g_param_spec_boolean ("has-resize-grip",
906                                                          P_("Resize grip"),
907                                                          P_("Specifies whether the window should have a resize grip"),
908                                                          TRUE,
909                                                          GTK_PARAM_READWRITE));
910
911   /**
912    * GtkWindow:resize-grip-visible:
913    *
914    * Whether a corner resize grip is currently shown.
915    *
916    * Since: 3.0
917    */
918   g_object_class_install_property (gobject_class,
919                                    PROP_RESIZE_GRIP_VISIBLE,
920                                    g_param_spec_boolean ("resize-grip-visible",
921                                                          P_("Resize grip is visible"),
922                                                          P_("Specifies whether the window's resize grip is visible."),
923                                                          FALSE,
924                                                          GTK_PARAM_READABLE));
925
926
927   /**
928    * GtkWindow:gravity:
929    *
930    * The window gravity of the window. See gtk_window_move() and #GdkGravity for
931    * more details about window gravity.
932    *
933    * Since: 2.4
934    */
935   g_object_class_install_property (gobject_class,
936                                    PROP_GRAVITY,
937                                    g_param_spec_enum ("gravity",
938                                                       P_("Gravity"),
939                                                       P_("The window gravity of the window"),
940                                                       GDK_TYPE_GRAVITY,
941                                                       GDK_GRAVITY_NORTH_WEST,
942                                                       GTK_PARAM_READWRITE));
943
944
945   /**
946    * GtkWindow:transient-for:
947    *
948    * The transient parent of the window. See gtk_window_set_transient_for() for
949    * more details about transient windows.
950    *
951    * Since: 2.10
952    */
953   g_object_class_install_property (gobject_class,
954                                    PROP_TRANSIENT_FOR,
955                                    g_param_spec_object ("transient-for",
956                                                         P_("Transient for Window"),
957                                                         P_("The transient parent of the dialog"),
958                                                         GTK_TYPE_WINDOW,
959                                                         GTK_PARAM_READWRITE| G_PARAM_CONSTRUCT));
960
961   /**
962    * GtkWindow:attached-to:
963    *
964    * The widget to which this window is attached.
965    * See gtk_window_set_attached_to().
966    *
967    * Examples of places where specifying this relation is useful are
968    * for instance a #GtkMenu created by a #GtkComboBox, a completion
969    * popup window created by #GtkEntry or a typeahead search entry
970    * created by #GtkTreeView.
971    *
972    * Since: 3.4
973    */
974   g_object_class_install_property (gobject_class,
975                                    PROP_ATTACHED_TO,
976                                    g_param_spec_object ("attached-to",
977                                                         P_("Attached to Widget"),
978                                                         P_("The widget where the window is attached"),
979                                                         GTK_TYPE_WIDGET,
980                                                         GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
981
982   /* Style properties.
983    */
984   gtk_widget_class_install_style_property (widget_class,
985                                            g_param_spec_int ("resize-grip-width",
986                                                              P_("Width of resize grip"),
987                                                              P_("Width of resize grip"),
988                                                              0, G_MAXINT, 16, GTK_PARAM_READWRITE));
989
990   gtk_widget_class_install_style_property (widget_class,
991                                            g_param_spec_int ("resize-grip-height",
992                                                              P_("Height of resize grip"),
993                                                              P_("Height of resize grip"),
994                                                              0, G_MAXINT, 16, GTK_PARAM_READWRITE));
995
996
997   /**
998    * GtkWindow:application:
999    *
1000    * The #GtkApplication associated with the window.
1001    *
1002    * The application will be kept alive for at least as long as it
1003    * has any windows associated with it (see g_application_hold()
1004    * for a way to keep it alive without windows).
1005    *
1006    * Normally, the connection between the application and the window
1007    * will remain until the window is destroyed, but you can explicitly
1008    * remove it by setting the ::application property to %NULL.
1009    *
1010    * Since: 3.0
1011    */
1012   g_object_class_install_property (gobject_class,
1013                                    PROP_APPLICATION,
1014                                    g_param_spec_object ("application",
1015                                                         P_("GtkApplication"),
1016                                                         P_("The GtkApplication for the window"),
1017                                                         GTK_TYPE_APPLICATION,
1018                                                         GTK_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1019
1020   window_signals[SET_FOCUS] =
1021     g_signal_new (I_("set-focus"),
1022                   G_TYPE_FROM_CLASS (gobject_class),
1023                   G_SIGNAL_RUN_LAST,
1024                   G_STRUCT_OFFSET (GtkWindowClass, set_focus),
1025                   NULL, NULL,
1026                   _gtk_marshal_VOID__OBJECT,
1027                   G_TYPE_NONE, 1,
1028                   GTK_TYPE_WIDGET);
1029
1030   /**
1031    * GtkWindow::activate-focus:
1032    * @window: the window which received the signal
1033    *
1034    * The ::activate-focus signal is a
1035    * <link linkend="keybinding-signals">keybinding signal</link>
1036    * which gets emitted when the user activates the currently
1037    * focused widget of @window.
1038    */
1039   window_signals[ACTIVATE_FOCUS] =
1040     g_signal_new (I_("activate-focus"),
1041                   G_TYPE_FROM_CLASS (gobject_class),
1042                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1043                   G_STRUCT_OFFSET (GtkWindowClass, activate_focus),
1044                   NULL, NULL,
1045                   _gtk_marshal_VOID__VOID,
1046                   G_TYPE_NONE,
1047                   0);
1048
1049   /**
1050    * GtkWindow::activate-default:
1051    * @window: the window which received the signal
1052    *
1053    * The ::activate-default signal is a
1054    * <link linkend="keybinding-signals">keybinding signal</link>
1055    * which gets emitted when the user activates the default widget
1056    * of @window.
1057    */
1058   window_signals[ACTIVATE_DEFAULT] =
1059     g_signal_new (I_("activate-default"),
1060                   G_TYPE_FROM_CLASS (gobject_class),
1061                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1062                   G_STRUCT_OFFSET (GtkWindowClass, activate_default),
1063                   NULL, NULL,
1064                   _gtk_marshal_VOID__VOID,
1065                   G_TYPE_NONE,
1066                   0);
1067
1068   /**
1069    * GtkWindow::keys-changed:
1070    * @window: the window which received the signal
1071    *
1072    * The ::keys-changed signal gets emitted when the set of accelerators
1073    * or mnemonics that are associated with @window changes.
1074    */
1075   window_signals[KEYS_CHANGED] =
1076     g_signal_new (I_("keys-changed"),
1077                   G_TYPE_FROM_CLASS (gobject_class),
1078                   G_SIGNAL_RUN_FIRST,
1079                   G_STRUCT_OFFSET (GtkWindowClass, keys_changed),
1080                   NULL, NULL,
1081                   _gtk_marshal_VOID__VOID,
1082                   G_TYPE_NONE,
1083                   0);
1084
1085   /*
1086    * Key bindings
1087    */
1088
1089   binding_set = gtk_binding_set_by_class (klass);
1090
1091   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0,
1092                                 "activate-focus", 0);
1093   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0,
1094                                 "activate-focus", 0);
1095   
1096   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0,
1097                                 "activate-default", 0);
1098   gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0,
1099                                 "activate-default", 0);
1100   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0,
1101                                 "activate-default", 0);
1102
1103   add_arrow_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP);
1104   add_arrow_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN);
1105   add_arrow_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT);
1106   add_arrow_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT);
1107
1108   add_tab_bindings (binding_set, 0, GTK_DIR_TAB_FORWARD);
1109   add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
1110   add_tab_bindings (binding_set, GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1111   add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1112
1113   gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_WINDOW_ACCESSIBLE);
1114 }
1115
1116 static void
1117 gtk_window_init (GtkWindow *window)
1118 {
1119   GtkStyleContext *context;
1120   GtkWindowPrivate *priv;
1121
1122   window->priv = G_TYPE_INSTANCE_GET_PRIVATE (window,
1123                                               GTK_TYPE_WINDOW,
1124                                               GtkWindowPrivate);
1125   priv = window->priv;
1126   
1127   gtk_widget_set_has_window (GTK_WIDGET (window), TRUE);
1128   _gtk_widget_set_is_toplevel (GTK_WIDGET (window), TRUE);
1129
1130   _gtk_widget_set_anchored (GTK_WIDGET (window), TRUE);
1131
1132   gtk_container_set_resize_mode (GTK_CONTAINER (window), GTK_RESIZE_QUEUE);
1133
1134   priv->title = NULL;
1135   priv->wmclass_name = g_strdup (g_get_prgname ());
1136   priv->wmclass_class = g_strdup (gdk_get_program_class ());
1137   priv->wm_role = NULL;
1138   priv->geometry_info = NULL;
1139   priv->type = GTK_WINDOW_TOPLEVEL;
1140   priv->focus_widget = NULL;
1141   priv->default_widget = NULL;
1142   priv->configure_request_count = 0;
1143   priv->resizable = TRUE;
1144   priv->configure_notify_received = FALSE;
1145   priv->position = GTK_WIN_POS_NONE;
1146   priv->need_default_size = TRUE;
1147   priv->need_default_position = TRUE;
1148   priv->modal = FALSE;
1149   priv->gdk_type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
1150   priv->gravity = GDK_GRAVITY_NORTH_WEST;
1151   priv->decorated = TRUE;
1152   priv->mnemonic_modifier = GDK_MOD1_MASK;
1153   priv->screen = gdk_screen_get_default ();
1154
1155   priv->accept_focus = TRUE;
1156   priv->focus_on_map = TRUE;
1157   priv->deletable = TRUE;
1158   priv->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
1159   priv->startup_id = NULL;
1160   priv->initial_timestamp = GDK_CURRENT_TIME;
1161   priv->has_resize_grip = TRUE;
1162   priv->mnemonics_visible = TRUE;
1163   priv->focus_visible = TRUE;
1164
1165   g_object_ref_sink (window);
1166   priv->has_user_ref_count = TRUE;
1167   toplevel_list = g_slist_prepend (toplevel_list, window);
1168
1169   if (priv->screen)
1170     g_signal_connect (priv->screen, "composited-changed",
1171                       G_CALLBACK (gtk_window_on_composited_changed), window);
1172
1173 #ifdef GDK_WINDOWING_X11
1174   g_signal_connect (gtk_settings_get_for_screen (priv->screen),
1175                     "notify::gtk-application-prefer-dark-theme",
1176                     G_CALLBACK (gtk_window_on_theme_variant_changed), window);
1177 #endif
1178
1179   context = gtk_widget_get_style_context (GTK_WIDGET (window));
1180   gtk_style_context_add_class (context, GTK_STYLE_CLASS_BACKGROUND);
1181 }
1182
1183 static void
1184 gtk_window_set_property (GObject      *object,
1185                          guint         prop_id,
1186                          const GValue *value,
1187                          GParamSpec   *pspec)
1188 {
1189   GtkWindow  *window = GTK_WINDOW (object);
1190   GtkWindowPrivate *priv = window->priv;
1191
1192   switch (prop_id)
1193     {
1194     case PROP_TYPE:
1195       priv->type = g_value_get_enum (value);
1196       break;
1197     case PROP_TITLE:
1198       gtk_window_set_title (window, g_value_get_string (value));
1199       break;
1200     case PROP_ROLE:
1201       gtk_window_set_role (window, g_value_get_string (value));
1202       break;
1203     case PROP_STARTUP_ID:
1204       gtk_window_set_startup_id (window, g_value_get_string (value));
1205       break;
1206     case PROP_RESIZABLE:
1207       gtk_window_set_resizable (window, g_value_get_boolean (value));
1208       break;
1209     case PROP_MODAL:
1210       gtk_window_set_modal (window, g_value_get_boolean (value));
1211       break;
1212     case PROP_WIN_POS:
1213       gtk_window_set_position (window, g_value_get_enum (value));
1214       break;
1215     case PROP_DEFAULT_WIDTH:
1216       gtk_window_set_default_size_internal (window,
1217                                             TRUE, g_value_get_int (value),
1218                                             FALSE, -1, FALSE);
1219       break;
1220     case PROP_DEFAULT_HEIGHT:
1221       gtk_window_set_default_size_internal (window,
1222                                             FALSE, -1,
1223                                             TRUE, g_value_get_int (value), FALSE);
1224       break;
1225     case PROP_DESTROY_WITH_PARENT:
1226       gtk_window_set_destroy_with_parent (window, g_value_get_boolean (value));
1227       break;
1228     case PROP_HIDE_TITLEBAR_WHEN_MAXIMIZED:
1229       gtk_window_set_hide_titlebar_when_maximized (window, g_value_get_boolean (value));
1230       break;
1231     case PROP_ICON:
1232       gtk_window_set_icon (window,
1233                            g_value_get_object (value));
1234       break;
1235     case PROP_ICON_NAME:
1236       gtk_window_set_icon_name (window, g_value_get_string (value));
1237       break;
1238     case PROP_SCREEN:
1239       gtk_window_set_screen (window, g_value_get_object (value));
1240       break;
1241     case PROP_TYPE_HINT:
1242       gtk_window_set_type_hint (window,
1243                                 g_value_get_enum (value));
1244       break;
1245     case PROP_SKIP_TASKBAR_HINT:
1246       gtk_window_set_skip_taskbar_hint (window,
1247                                         g_value_get_boolean (value));
1248       break;
1249     case PROP_SKIP_PAGER_HINT:
1250       gtk_window_set_skip_pager_hint (window,
1251                                       g_value_get_boolean (value));
1252       break;
1253     case PROP_URGENCY_HINT:
1254       gtk_window_set_urgency_hint (window,
1255                                    g_value_get_boolean (value));
1256       break;
1257     case PROP_ACCEPT_FOCUS:
1258       gtk_window_set_accept_focus (window,
1259                                    g_value_get_boolean (value));
1260       break;
1261     case PROP_FOCUS_ON_MAP:
1262       gtk_window_set_focus_on_map (window,
1263                                    g_value_get_boolean (value));
1264       break;
1265     case PROP_DECORATED:
1266       gtk_window_set_decorated (window, g_value_get_boolean (value));
1267       break;
1268     case PROP_DELETABLE:
1269       gtk_window_set_deletable (window, g_value_get_boolean (value));
1270       break;
1271     case PROP_GRAVITY:
1272       gtk_window_set_gravity (window, g_value_get_enum (value));
1273       break;
1274     case PROP_TRANSIENT_FOR:
1275       gtk_window_set_transient_for (window, g_value_get_object (value));
1276       break;
1277     case PROP_ATTACHED_TO:
1278       gtk_window_set_attached_to (window, g_value_get_object (value));
1279       break;
1280     case PROP_HAS_RESIZE_GRIP:
1281       gtk_window_set_has_resize_grip (window, g_value_get_boolean (value));
1282       break;
1283     case PROP_APPLICATION:
1284       gtk_window_set_application (window, g_value_get_object (value));
1285       break;
1286     case PROP_MNEMONICS_VISIBLE:
1287       gtk_window_set_mnemonics_visible (window, g_value_get_boolean (value));
1288       break;
1289     case PROP_FOCUS_VISIBLE:
1290       gtk_window_set_focus_visible (window, g_value_get_boolean (value));
1291       break;
1292     default:
1293       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1294       break;
1295     }
1296 }
1297
1298 static void
1299 gtk_window_get_property (GObject      *object,
1300                          guint         prop_id,
1301                          GValue       *value,
1302                          GParamSpec   *pspec)
1303 {
1304   GtkWindow  *window = GTK_WINDOW (object);
1305   GtkWindowPrivate *priv = window->priv;
1306
1307   switch (prop_id)
1308     {
1309       GtkWindowGeometryInfo *info;
1310     case PROP_TYPE:
1311       g_value_set_enum (value, priv->type);
1312       break;
1313     case PROP_ROLE:
1314       g_value_set_string (value, priv->wm_role);
1315       break;
1316     case PROP_TITLE:
1317       g_value_set_string (value, priv->title);
1318       break;
1319     case PROP_RESIZABLE:
1320       g_value_set_boolean (value, priv->resizable);
1321       break;
1322     case PROP_MODAL:
1323       g_value_set_boolean (value, priv->modal);
1324       break;
1325     case PROP_WIN_POS:
1326       g_value_set_enum (value, priv->position);
1327       break;
1328     case PROP_DEFAULT_WIDTH:
1329       info = gtk_window_get_geometry_info (window, FALSE);
1330       if (!info)
1331         g_value_set_int (value, -1);
1332       else
1333         g_value_set_int (value, info->default_width);
1334       break;
1335     case PROP_DEFAULT_HEIGHT:
1336       info = gtk_window_get_geometry_info (window, FALSE);
1337       if (!info)
1338         g_value_set_int (value, -1);
1339       else
1340         g_value_set_int (value, info->default_height);
1341       break;
1342     case PROP_DESTROY_WITH_PARENT:
1343       g_value_set_boolean (value, priv->destroy_with_parent);
1344       break;
1345     case PROP_HIDE_TITLEBAR_WHEN_MAXIMIZED:
1346       g_value_set_boolean (value, priv->hide_titlebar_when_maximized);
1347       break;
1348     case PROP_ICON:
1349       g_value_set_object (value, gtk_window_get_icon (window));
1350       break;
1351     case PROP_ICON_NAME:
1352       g_value_set_string (value, gtk_window_get_icon_name (window));
1353       break;
1354     case PROP_SCREEN:
1355       g_value_set_object (value, priv->screen);
1356       break;
1357     case PROP_IS_ACTIVE:
1358       g_value_set_boolean (value, priv->is_active);
1359       break;
1360     case PROP_HAS_TOPLEVEL_FOCUS:
1361       g_value_set_boolean (value, priv->has_toplevel_focus);
1362       break;
1363     case PROP_TYPE_HINT:
1364       g_value_set_enum (value, priv->type_hint);
1365       break;
1366     case PROP_SKIP_TASKBAR_HINT:
1367       g_value_set_boolean (value,
1368                            gtk_window_get_skip_taskbar_hint (window));
1369       break;
1370     case PROP_SKIP_PAGER_HINT:
1371       g_value_set_boolean (value,
1372                            gtk_window_get_skip_pager_hint (window));
1373       break;
1374     case PROP_URGENCY_HINT:
1375       g_value_set_boolean (value,
1376                            gtk_window_get_urgency_hint (window));
1377       break;
1378     case PROP_ACCEPT_FOCUS:
1379       g_value_set_boolean (value,
1380                            gtk_window_get_accept_focus (window));
1381       break;
1382     case PROP_FOCUS_ON_MAP:
1383       g_value_set_boolean (value,
1384                            gtk_window_get_focus_on_map (window));
1385       break;
1386     case PROP_DECORATED:
1387       g_value_set_boolean (value, gtk_window_get_decorated (window));
1388       break;
1389     case PROP_DELETABLE:
1390       g_value_set_boolean (value, gtk_window_get_deletable (window));
1391       break;
1392     case PROP_GRAVITY:
1393       g_value_set_enum (value, gtk_window_get_gravity (window));
1394       break;
1395     case PROP_TRANSIENT_FOR:
1396       g_value_set_object (value, gtk_window_get_transient_for (window));
1397       break;
1398     case PROP_ATTACHED_TO:
1399       g_value_set_object (value, gtk_window_get_attached_to (window));
1400       break;
1401     case PROP_HAS_RESIZE_GRIP:
1402       g_value_set_boolean (value, priv->has_resize_grip);
1403       break;
1404     case PROP_RESIZE_GRIP_VISIBLE:
1405       g_value_set_boolean (value, gtk_window_resize_grip_is_visible (window));
1406       break;
1407     case PROP_APPLICATION:
1408       g_value_set_object (value, gtk_window_get_application (window));
1409       break;
1410     case PROP_MNEMONICS_VISIBLE:
1411       g_value_set_boolean (value, priv->mnemonics_visible);
1412       break;
1413     case PROP_FOCUS_VISIBLE:
1414       g_value_set_boolean (value, priv->focus_visible);
1415       break;
1416     default:
1417       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1418       break;
1419     }
1420 }
1421
1422 static void
1423 gtk_window_buildable_interface_init (GtkBuildableIface *iface)
1424 {
1425   parent_buildable_iface = g_type_interface_peek_parent (iface);
1426   iface->set_buildable_property = gtk_window_buildable_set_buildable_property;
1427   iface->parser_finished = gtk_window_buildable_parser_finished;
1428   iface->custom_tag_start = gtk_window_buildable_custom_tag_start;
1429   iface->custom_finished = gtk_window_buildable_custom_finished;
1430 }
1431
1432 static void
1433 gtk_window_buildable_set_buildable_property (GtkBuildable        *buildable,
1434                                              GtkBuilder          *builder,
1435                                              const gchar         *name,
1436                                              const GValue        *value)
1437 {
1438   GtkWindow *window = GTK_WINDOW (buildable);
1439   GtkWindowPrivate *priv = window->priv;
1440
1441   if (strcmp (name, "visible") == 0 && g_value_get_boolean (value))
1442     priv->builder_visible = TRUE;
1443   else
1444     parent_buildable_iface->set_buildable_property (buildable, builder, name, value);
1445 }
1446
1447 static void
1448 gtk_window_buildable_parser_finished (GtkBuildable *buildable,
1449                                       GtkBuilder   *builder)
1450 {
1451   GtkWindow *window = GTK_WINDOW (buildable);
1452   GtkWindowPrivate *priv = window->priv;
1453   GObject *object;
1454   GSList *accels, *l;
1455
1456   if (priv->builder_visible)
1457     gtk_widget_show (GTK_WIDGET (buildable));
1458
1459   accels = g_object_get_qdata (G_OBJECT (buildable), quark_gtk_buildable_accels);
1460   for (l = accels; l; l = l->next)
1461     {
1462       object = gtk_builder_get_object (builder, l->data);
1463       if (!object)
1464         {
1465           g_warning ("Unknown accel group %s specified in window %s",
1466                      (const gchar*)l->data, gtk_buildable_get_name (buildable));
1467           continue;
1468         }
1469       gtk_window_add_accel_group (GTK_WINDOW (buildable),
1470                                   GTK_ACCEL_GROUP (object));
1471       g_free (l->data);
1472     }
1473
1474   g_object_set_qdata (G_OBJECT (buildable), quark_gtk_buildable_accels, NULL);
1475
1476   parent_buildable_iface->parser_finished (buildable, builder);
1477 }
1478
1479 typedef struct {
1480   GObject *object;
1481   GSList *items;
1482 } GSListSubParserData;
1483
1484 static void
1485 window_start_element (GMarkupParseContext *context,
1486                           const gchar         *element_name,
1487                           const gchar        **names,
1488                           const gchar        **values,
1489                           gpointer            user_data,
1490                           GError            **error)
1491 {
1492   guint i;
1493   GSListSubParserData *data = (GSListSubParserData*)user_data;
1494
1495   if (strcmp (element_name, "group") == 0)
1496     {
1497       for (i = 0; names[i]; i++)
1498         {
1499           if (strcmp (names[i], "name") == 0)
1500             data->items = g_slist_prepend (data->items, g_strdup (values[i]));
1501         }
1502     }
1503   else if (strcmp (element_name, "accel-groups") == 0)
1504     return;
1505   else
1506     g_warning ("Unsupported tag type for GtkWindow: %s\n",
1507                element_name);
1508
1509 }
1510
1511 static const GMarkupParser window_parser =
1512   {
1513     window_start_element
1514   };
1515
1516 static gboolean
1517 gtk_window_buildable_custom_tag_start (GtkBuildable  *buildable,
1518                                        GtkBuilder    *builder,
1519                                        GObject       *child,
1520                                        const gchar   *tagname,
1521                                        GMarkupParser *parser,
1522                                        gpointer      *data)
1523 {
1524   GSListSubParserData *parser_data;
1525
1526   if (parent_buildable_iface->custom_tag_start (buildable, builder, child, 
1527                                                 tagname, parser, data))
1528     return TRUE;
1529
1530   if (strcmp (tagname, "accel-groups") == 0)
1531     {
1532       parser_data = g_slice_new0 (GSListSubParserData);
1533       parser_data->items = NULL;
1534       parser_data->object = G_OBJECT (buildable);
1535
1536       *parser = window_parser;
1537       *data = parser_data;
1538       return TRUE;
1539     }
1540
1541   return FALSE;
1542 }
1543
1544 static void
1545 gtk_window_buildable_custom_finished (GtkBuildable  *buildable,
1546                                           GtkBuilder    *builder,
1547                                           GObject       *child,
1548                                           const gchar   *tagname,
1549                                           gpointer       user_data)
1550 {
1551   GSListSubParserData *data;
1552
1553   parent_buildable_iface->custom_finished (buildable, builder, child, 
1554                                            tagname, user_data);
1555
1556   if (strcmp (tagname, "accel-groups") != 0)
1557     return;
1558   
1559   data = (GSListSubParserData*)user_data;
1560
1561   g_object_set_qdata_full (G_OBJECT (buildable), quark_gtk_buildable_accels, 
1562                            data->items, (GDestroyNotify) g_slist_free);
1563
1564   g_slice_free (GSListSubParserData, data);
1565 }
1566
1567 /**
1568  * gtk_window_new:
1569  * @type: type of window
1570  * 
1571  * Creates a new #GtkWindow, which is a toplevel window that can
1572  * contain other widgets. Nearly always, the type of the window should
1573  * be #GTK_WINDOW_TOPLEVEL. If you're implementing something like a
1574  * popup menu from scratch (which is a bad idea, just use #GtkMenu),
1575  * you might use #GTK_WINDOW_POPUP. #GTK_WINDOW_POPUP is not for
1576  * dialogs, though in some other toolkits dialogs are called "popups".
1577  * In GTK+, #GTK_WINDOW_POPUP means a pop-up menu or pop-up tooltip.
1578  * On X11, popup windows are not controlled by the <link
1579  * linkend="gtk-X11-arch">window manager</link>.
1580  *
1581  * If you simply want an undecorated window (no window borders), use
1582  * gtk_window_set_decorated(), don't use #GTK_WINDOW_POPUP.
1583  * 
1584  * Return value: a new #GtkWindow.
1585  **/
1586 GtkWidget*
1587 gtk_window_new (GtkWindowType type)
1588 {
1589   GtkWindowPrivate *priv;
1590   GtkWindow *window;
1591
1592   g_return_val_if_fail (type >= GTK_WINDOW_TOPLEVEL && type <= GTK_WINDOW_POPUP, NULL);
1593
1594   window = g_object_new (GTK_TYPE_WINDOW, NULL);
1595   priv = window->priv;
1596
1597   priv->type = type;
1598
1599   return GTK_WIDGET (window);
1600 }
1601
1602 /**
1603  * gtk_window_set_title:
1604  * @window: a #GtkWindow
1605  * @title: title of the window
1606  * 
1607  * Sets the title of the #GtkWindow. The title of a window will be
1608  * displayed in its title bar; on the X Window System, the title bar
1609  * is rendered by the <link linkend="gtk-X11-arch">window
1610  * manager</link>, so exactly how the title appears to users may vary
1611  * according to a user's exact configuration. The title should help a
1612  * user distinguish this window from other windows they may have
1613  * open. A good title might include the application name and current
1614  * document filename, for example.
1615  * 
1616  **/
1617 void
1618 gtk_window_set_title (GtkWindow   *window,
1619                       const gchar *title)
1620 {
1621   GtkWindowPrivate *priv;
1622   GtkWidget *widget;
1623   char *new_title;
1624   
1625   g_return_if_fail (GTK_IS_WINDOW (window));
1626
1627   priv = window->priv;
1628   widget = GTK_WIDGET (window);
1629
1630   new_title = g_strdup (title);
1631   g_free (priv->title);
1632   priv->title = new_title;
1633
1634   if (gtk_widget_get_realized (widget))
1635     {
1636       gdk_window_set_title (gtk_widget_get_window (widget),
1637                             priv->title);
1638     }
1639
1640   g_object_notify (G_OBJECT (window), "title");
1641 }
1642
1643 /**
1644  * gtk_window_get_title:
1645  * @window: a #GtkWindow
1646  *
1647  * Retrieves the title of the window. See gtk_window_set_title().
1648  *
1649  * Return value: the title of the window, or %NULL if none has
1650  *    been set explicitely. The returned string is owned by the widget
1651  *    and must not be modified or freed.
1652  **/
1653 const gchar *
1654 gtk_window_get_title (GtkWindow *window)
1655 {
1656   g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
1657
1658   return window->priv->title;
1659 }
1660
1661 /**
1662  * gtk_window_set_wmclass:
1663  * @window: a #GtkWindow
1664  * @wmclass_name: window name hint
1665  * @wmclass_class: window class hint
1666  *
1667  * Don't use this function. It sets the X Window System "class" and
1668  * "name" hints for a window.  According to the ICCCM, you should
1669  * always set these to the same value for all windows in an
1670  * application, and GTK+ sets them to that value by default, so calling
1671  * this function is sort of pointless. However, you may want to call
1672  * gtk_window_set_role() on each window in your application, for the
1673  * benefit of the session manager. Setting the role allows the window
1674  * manager to restore window positions when loading a saved session.
1675  * 
1676  **/
1677 void
1678 gtk_window_set_wmclass (GtkWindow *window,
1679                         const gchar *wmclass_name,
1680                         const gchar *wmclass_class)
1681 {
1682   GtkWindowPrivate *priv;
1683
1684   g_return_if_fail (GTK_IS_WINDOW (window));
1685
1686   priv = window->priv;
1687
1688   g_free (priv->wmclass_name);
1689   priv->wmclass_name = g_strdup (wmclass_name);
1690
1691   g_free (priv->wmclass_class);
1692   priv->wmclass_class = g_strdup (wmclass_class);
1693
1694   if (gtk_widget_get_realized (GTK_WIDGET (window)))
1695     g_warning ("gtk_window_set_wmclass: shouldn't set wmclass after window is realized!\n");
1696 }
1697
1698 /**
1699  * gtk_window_set_role:
1700  * @window: a #GtkWindow
1701  * @role: unique identifier for the window to be used when restoring a session
1702  *
1703  * This function is only useful on X11, not with other GTK+ targets.
1704  * 
1705  * In combination with the window title, the window role allows a
1706  * <link linkend="gtk-X11-arch">window manager</link> to identify "the
1707  * same" window when an application is restarted. So for example you
1708  * might set the "toolbox" role on your app's toolbox window, so that
1709  * when the user restarts their session, the window manager can put
1710  * the toolbox back in the same place.
1711  *
1712  * If a window already has a unique title, you don't need to set the
1713  * role, since the WM can use the title to identify the window when
1714  * restoring the session.
1715  * 
1716  **/
1717 void
1718 gtk_window_set_role (GtkWindow   *window,
1719                      const gchar *role)
1720 {
1721   GtkWindowPrivate *priv;
1722   char *new_role;
1723   
1724   g_return_if_fail (GTK_IS_WINDOW (window));
1725
1726   priv = window->priv;
1727
1728   new_role = g_strdup (role);
1729   g_free (priv->wm_role);
1730   priv->wm_role = new_role;
1731
1732   if (gtk_widget_get_realized (GTK_WIDGET (window)))
1733     gdk_window_set_role (gtk_widget_get_window (GTK_WIDGET (window)),
1734                          priv->wm_role);
1735
1736   g_object_notify (G_OBJECT (window), "role");
1737 }
1738
1739 /**
1740  * gtk_window_set_startup_id:
1741  * @window: a #GtkWindow
1742  * @startup_id: a string with startup-notification identifier
1743  *
1744  * Startup notification identifiers are used by desktop environment to 
1745  * track application startup, to provide user feedback and other 
1746  * features. This function changes the corresponding property on the
1747  * underlying GdkWindow. Normally, startup identifier is managed 
1748  * automatically and you should only use this function in special cases
1749  * like transferring focus from other processes. You should use this
1750  * function before calling gtk_window_present() or any equivalent
1751  * function generating a window map event.
1752  *
1753  * This function is only useful on X11, not with other GTK+ targets.
1754  * 
1755  * Since: 2.12
1756  **/
1757 void
1758 gtk_window_set_startup_id (GtkWindow   *window,
1759                            const gchar *startup_id)
1760 {
1761   GtkWindowPrivate *priv;
1762   GtkWidget *widget;
1763
1764   g_return_if_fail (GTK_IS_WINDOW (window));
1765
1766   priv = window->priv;
1767   widget = GTK_WIDGET (window);
1768
1769   g_free (priv->startup_id);
1770   priv->startup_id = g_strdup (startup_id);
1771
1772   if (gtk_widget_get_realized (widget))
1773     {
1774       GdkWindow *gdk_window;
1775       guint32 timestamp = extract_time_from_startup_id (priv->startup_id);
1776
1777       gdk_window = gtk_widget_get_window (widget);
1778
1779 #ifdef GDK_WINDOWING_X11
1780       if (timestamp != GDK_CURRENT_TIME && GDK_IS_X11_WINDOW(gdk_window))
1781         gdk_x11_window_set_user_time (gdk_window, timestamp);
1782 #endif
1783
1784       /* Here we differentiate real and "fake" startup notification IDs,
1785        * constructed on purpose just to pass interaction timestamp
1786        */
1787       if (startup_id_is_fake (priv->startup_id))
1788         gtk_window_present_with_time (window, timestamp);
1789       else 
1790         {
1791           gdk_window_set_startup_id (gdk_window,
1792                                      priv->startup_id);
1793           
1794           /* If window is mapped, terminate the startup-notification too */
1795           if (gtk_widget_get_mapped (widget) &&
1796               !disable_startup_notification)
1797             gdk_notify_startup_complete_with_id (priv->startup_id);
1798         }
1799     }
1800
1801   g_object_notify (G_OBJECT (window), "startup-id");
1802 }
1803
1804 /**
1805  * gtk_window_get_role:
1806  * @window: a #GtkWindow
1807  *
1808  * Returns the role of the window. See gtk_window_set_role() for
1809  * further explanation.
1810  *
1811  * Return value: the role of the window if set, or %NULL. The
1812  *   returned is owned by the widget and must not be modified
1813  *   or freed.
1814  **/
1815 const gchar *
1816 gtk_window_get_role (GtkWindow *window)
1817 {
1818   g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
1819
1820   return window->priv->wm_role;
1821 }
1822
1823 /**
1824  * gtk_window_set_focus:
1825  * @window: a #GtkWindow
1826  * @focus: (allow-none): widget to be the new focus widget, or %NULL to unset
1827  *   any focus widget for the toplevel window.
1828  *
1829  * If @focus is not the current focus widget, and is focusable, sets
1830  * it as the focus widget for the window. If @focus is %NULL, unsets
1831  * the focus widget for this window. To set the focus to a particular
1832  * widget in the toplevel, it is usually more convenient to use
1833  * gtk_widget_grab_focus() instead of this function.
1834  **/
1835 void
1836 gtk_window_set_focus (GtkWindow *window,
1837                       GtkWidget *focus)
1838 {
1839   GtkWindowPrivate *priv;
1840   GtkWidget *parent;
1841
1842   g_return_if_fail (GTK_IS_WINDOW (window));
1843
1844   priv = window->priv;
1845
1846   if (focus)
1847     {
1848       g_return_if_fail (GTK_IS_WIDGET (focus));
1849       g_return_if_fail (gtk_widget_get_can_focus (focus));
1850     }
1851
1852   if (focus)
1853     gtk_widget_grab_focus (focus);
1854   else
1855     {
1856       /* Clear the existing focus chain, so that when we focus into
1857        * the window again, we start at the beginnning.
1858        */
1859       GtkWidget *widget = priv->focus_widget;
1860       if (widget)
1861         {
1862           while ((parent = gtk_widget_get_parent (widget)))
1863             {
1864               widget = parent;
1865               gtk_container_set_focus_child (GTK_CONTAINER (widget), NULL);
1866             }
1867         }
1868       
1869       _gtk_window_internal_set_focus (window, NULL);
1870     }
1871 }
1872
1873 void
1874 _gtk_window_internal_set_focus (GtkWindow *window,
1875                                 GtkWidget *focus)
1876 {
1877   GtkWindowPrivate *priv;
1878
1879   g_return_if_fail (GTK_IS_WINDOW (window));
1880
1881   priv = window->priv;
1882
1883   if ((priv->focus_widget != focus) ||
1884       (focus && !gtk_widget_has_focus (focus)))
1885     g_signal_emit (window, window_signals[SET_FOCUS], 0, focus);
1886 }
1887
1888 /**
1889  * gtk_window_set_default:
1890  * @window: a #GtkWindow
1891  * @default_widget: (allow-none): widget to be the default, or %NULL to unset the
1892  *                  default widget for the toplevel.
1893  *
1894  * The default widget is the widget that's activated when the user
1895  * presses Enter in a dialog (for example). This function sets or
1896  * unsets the default widget for a #GtkWindow about. When setting
1897  * (rather than unsetting) the default widget it's generally easier to
1898  * call gtk_widget_grab_focus() on the widget. Before making a widget
1899  * the default widget, you must call gtk_widget_set_can_default() on the
1900  * widget you'd like to make the default.
1901  **/
1902 void
1903 gtk_window_set_default (GtkWindow *window,
1904                         GtkWidget *default_widget)
1905 {
1906   GtkWindowPrivate *priv;
1907
1908   g_return_if_fail (GTK_IS_WINDOW (window));
1909
1910   priv = window->priv;
1911
1912   if (default_widget)
1913     g_return_if_fail (gtk_widget_get_can_default (default_widget));
1914
1915   if (priv->default_widget != default_widget)
1916     {
1917       GtkWidget *old_default_widget = NULL;
1918       
1919       if (default_widget)
1920         g_object_ref (default_widget);
1921
1922       if (priv->default_widget)
1923         {
1924           old_default_widget = priv->default_widget;
1925
1926           if (priv->focus_widget != priv->default_widget ||
1927               !gtk_widget_get_receives_default (priv->default_widget))
1928             _gtk_widget_set_has_default (priv->default_widget, FALSE);
1929
1930           gtk_widget_queue_draw (priv->default_widget);
1931         }
1932
1933       priv->default_widget = default_widget;
1934
1935       if (priv->default_widget)
1936         {
1937           if (priv->focus_widget == NULL ||
1938               !gtk_widget_get_receives_default (priv->focus_widget))
1939             _gtk_widget_set_has_default (priv->default_widget, TRUE);
1940
1941           gtk_widget_queue_draw (priv->default_widget);
1942         }
1943
1944       if (old_default_widget)
1945         g_object_notify (G_OBJECT (old_default_widget), "has-default");
1946       
1947       if (default_widget)
1948         {
1949           g_object_notify (G_OBJECT (default_widget), "has-default");
1950           g_object_unref (default_widget);
1951         }
1952     }
1953 }
1954
1955 /**
1956  * gtk_window_get_default_widget:
1957  * @window: a #GtkWindow
1958  *
1959  * Returns the default widget for @window. See gtk_window_set_default()
1960  * for more details.
1961  *
1962  * Returns: (transfer none): the default widget, or %NULL if there is none.
1963  *
1964  * Since: 2.14
1965  **/
1966 GtkWidget *
1967 gtk_window_get_default_widget (GtkWindow *window)
1968 {
1969   g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
1970
1971   return window->priv->default_widget;
1972 }
1973
1974 static gboolean
1975 handle_keys_changed (gpointer data)
1976 {
1977   GtkWindow *window = GTK_WINDOW (data);
1978   GtkWindowPrivate *priv = window->priv;
1979
1980   if (priv->keys_changed_handler)
1981     {
1982       g_source_remove (priv->keys_changed_handler);
1983       priv->keys_changed_handler = 0;
1984     }
1985
1986   g_signal_emit (window, window_signals[KEYS_CHANGED], 0);
1987   
1988   return FALSE;
1989 }
1990
1991 static void
1992 gtk_window_notify_keys_changed (GtkWindow *window)
1993 {
1994   GtkWindowPrivate *priv = window->priv;
1995
1996   if (!priv->keys_changed_handler)
1997     priv->keys_changed_handler = gdk_threads_add_idle (handle_keys_changed, window);
1998 }
1999
2000 /**
2001  * gtk_window_add_accel_group:
2002  * @window: window to attach accelerator group to
2003  * @accel_group: a #GtkAccelGroup
2004  *
2005  * Associate @accel_group with @window, such that calling
2006  * gtk_accel_groups_activate() on @window will activate accelerators
2007  * in @accel_group.
2008  **/
2009 void
2010 gtk_window_add_accel_group (GtkWindow     *window,
2011                             GtkAccelGroup *accel_group)
2012 {
2013   g_return_if_fail (GTK_IS_WINDOW (window));
2014   g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group));
2015
2016   _gtk_accel_group_attach (accel_group, G_OBJECT (window));
2017   g_signal_connect_object (accel_group, "accel-changed",
2018                            G_CALLBACK (gtk_window_notify_keys_changed),
2019                            window, G_CONNECT_SWAPPED);
2020   gtk_window_notify_keys_changed (window);
2021 }
2022
2023 /**
2024  * gtk_window_remove_accel_group:
2025  * @window: a #GtkWindow
2026  * @accel_group: a #GtkAccelGroup
2027  *
2028  * Reverses the effects of gtk_window_add_accel_group().
2029  **/
2030 void
2031 gtk_window_remove_accel_group (GtkWindow     *window,
2032                                GtkAccelGroup *accel_group)
2033 {
2034   g_return_if_fail (GTK_IS_WINDOW (window));
2035   g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group));
2036
2037   g_signal_handlers_disconnect_by_func (accel_group,
2038                                         gtk_window_notify_keys_changed,
2039                                         window);
2040   _gtk_accel_group_detach (accel_group, G_OBJECT (window));
2041   gtk_window_notify_keys_changed (window);
2042 }
2043
2044 static GtkMnemonicHash *
2045 gtk_window_get_mnemonic_hash (GtkWindow *window,
2046                               gboolean   create)
2047 {
2048   GtkWindowPrivate *private = window->priv;
2049
2050   if (!private->mnemonic_hash && create)
2051     private->mnemonic_hash = _gtk_mnemonic_hash_new ();
2052
2053   return private->mnemonic_hash;
2054 }
2055
2056 /**
2057  * gtk_window_add_mnemonic:
2058  * @window: a #GtkWindow
2059  * @keyval: the mnemonic
2060  * @target: the widget that gets activated by the mnemonic
2061  *
2062  * Adds a mnemonic to this window.
2063  */
2064 void
2065 gtk_window_add_mnemonic (GtkWindow *window,
2066                          guint      keyval,
2067                          GtkWidget *target)
2068 {
2069   g_return_if_fail (GTK_IS_WINDOW (window));
2070   g_return_if_fail (GTK_IS_WIDGET (target));
2071
2072   _gtk_mnemonic_hash_add (gtk_window_get_mnemonic_hash (window, TRUE),
2073                           keyval, target);
2074   gtk_window_notify_keys_changed (window);
2075 }
2076
2077 /**
2078  * gtk_window_remove_mnemonic:
2079  * @window: a #GtkWindow
2080  * @keyval: the mnemonic
2081  * @target: the widget that gets activated by the mnemonic
2082  *
2083  * Removes a mnemonic from this window.
2084  */
2085 void
2086 gtk_window_remove_mnemonic (GtkWindow *window,
2087                             guint      keyval,
2088                             GtkWidget *target)
2089 {
2090   g_return_if_fail (GTK_IS_WINDOW (window));
2091   g_return_if_fail (GTK_IS_WIDGET (target));
2092   
2093   _gtk_mnemonic_hash_remove (gtk_window_get_mnemonic_hash (window, TRUE),
2094                              keyval, target);
2095   gtk_window_notify_keys_changed (window);
2096 }
2097
2098 /**
2099  * gtk_window_mnemonic_activate:
2100  * @window: a #GtkWindow
2101  * @keyval: the mnemonic
2102  * @modifier: the modifiers
2103  *
2104  * Activates the targets associated with the mnemonic.
2105  *
2106  * Returns: %TRUE if the activation is done.
2107  */
2108 gboolean
2109 gtk_window_mnemonic_activate (GtkWindow      *window,
2110                               guint           keyval,
2111                               GdkModifierType modifier)
2112 {
2113   GtkWindowPrivate *priv;
2114
2115   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
2116
2117   priv = window->priv;
2118
2119   if (priv->mnemonic_modifier == (modifier & gtk_accelerator_get_default_mod_mask ()))
2120       {
2121         GtkMnemonicHash *mnemonic_hash = gtk_window_get_mnemonic_hash (window, FALSE);
2122         if (mnemonic_hash)
2123           return _gtk_mnemonic_hash_activate (mnemonic_hash, keyval);
2124       }
2125
2126   return FALSE;
2127 }
2128
2129 /**
2130  * gtk_window_set_mnemonic_modifier:
2131  * @window: a #GtkWindow
2132  * @modifier: the modifier mask used to activate
2133  *               mnemonics on this window.
2134  *
2135  * Sets the mnemonic modifier for this window. 
2136  **/
2137 void
2138 gtk_window_set_mnemonic_modifier (GtkWindow      *window,
2139                                   GdkModifierType modifier)
2140 {
2141   GtkWindowPrivate *priv;
2142
2143   g_return_if_fail (GTK_IS_WINDOW (window));
2144   g_return_if_fail ((modifier & ~GDK_MODIFIER_MASK) == 0);
2145
2146   priv = window->priv;
2147
2148   priv->mnemonic_modifier = modifier;
2149   gtk_window_notify_keys_changed (window);
2150 }
2151
2152 /**
2153  * gtk_window_get_mnemonic_modifier:
2154  * @window: a #GtkWindow
2155  *
2156  * Returns the mnemonic modifier for this window. See
2157  * gtk_window_set_mnemonic_modifier().
2158  *
2159  * Return value: the modifier mask used to activate
2160  *               mnemonics on this window.
2161  **/
2162 GdkModifierType
2163 gtk_window_get_mnemonic_modifier (GtkWindow *window)
2164 {
2165   g_return_val_if_fail (GTK_IS_WINDOW (window), 0);
2166
2167   return window->priv->mnemonic_modifier;
2168 }
2169
2170 /**
2171  * gtk_window_set_position:
2172  * @window: a #GtkWindow.
2173  * @position: a position constraint.
2174  *
2175  * Sets a position constraint for this window. If the old or new
2176  * constraint is %GTK_WIN_POS_CENTER_ALWAYS, this will also cause
2177  * the window to be repositioned to satisfy the new constraint. 
2178  **/
2179 void
2180 gtk_window_set_position (GtkWindow         *window,
2181                          GtkWindowPosition  position)
2182 {
2183   GtkWindowPrivate *priv;
2184
2185   g_return_if_fail (GTK_IS_WINDOW (window));
2186
2187   priv = window->priv;
2188
2189   if (position == GTK_WIN_POS_CENTER_ALWAYS ||
2190       priv->position == GTK_WIN_POS_CENTER_ALWAYS)
2191     {
2192       GtkWindowGeometryInfo *info;
2193
2194       info = gtk_window_get_geometry_info (window, TRUE);
2195
2196       /* this flag causes us to re-request the CENTER_ALWAYS
2197        * constraint in gtk_window_move_resize(), see
2198        * comment in that function.
2199        */
2200       info->position_constraints_changed = TRUE;
2201
2202       gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window));
2203     }
2204
2205   priv->position = position;
2206   
2207   g_object_notify (G_OBJECT (window), "window-position");
2208 }
2209
2210 /**
2211  * gtk_window_activate_focus:
2212  * @window: a #GtkWindow
2213  * 
2214  * Activates the current focused widget within the window.
2215  * 
2216  * Return value: %TRUE if a widget got activated.
2217  **/
2218 gboolean 
2219 gtk_window_activate_focus (GtkWindow *window)
2220 {
2221   GtkWindowPrivate *priv;
2222
2223   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
2224
2225   priv = window->priv;
2226
2227   if (priv->focus_widget && gtk_widget_is_sensitive (priv->focus_widget))
2228     return gtk_widget_activate (priv->focus_widget);
2229
2230   return FALSE;
2231 }
2232
2233 /**
2234  * gtk_window_get_focus:
2235  * @window: a #GtkWindow
2236  * 
2237  * Retrieves the current focused widget within the window.
2238  * Note that this is the widget that would have the focus
2239  * if the toplevel window focused; if the toplevel window
2240  * is not focused then  <literal>gtk_widget_has_focus (widget)</literal> will
2241  * not be %TRUE for the widget.
2242  *
2243  * Return value: (transfer none): the currently focused widget, or %NULL if there is none.
2244  **/
2245 GtkWidget *
2246 gtk_window_get_focus (GtkWindow *window)
2247 {
2248   g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
2249
2250   return window->priv->focus_widget;
2251 }
2252
2253 /**
2254  * gtk_window_activate_default:
2255  * @window: a #GtkWindow
2256  * 
2257  * Activates the default widget for the window, unless the current 
2258  * focused widget has been configured to receive the default action 
2259  * (see gtk_widget_set_receives_default()), in which case the
2260  * focused widget is activated. 
2261  * 
2262  * Return value: %TRUE if a widget got activated.
2263  **/
2264 gboolean
2265 gtk_window_activate_default (GtkWindow *window)
2266 {
2267   GtkWindowPrivate *priv;
2268
2269   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
2270
2271   priv = window->priv;
2272
2273   if (priv->default_widget && gtk_widget_is_sensitive (priv->default_widget) &&
2274       (!priv->focus_widget || !gtk_widget_get_receives_default (priv->focus_widget)))
2275     return gtk_widget_activate (priv->default_widget);
2276   else if (priv->focus_widget && gtk_widget_is_sensitive (priv->focus_widget))
2277     return gtk_widget_activate (priv->focus_widget);
2278
2279   return FALSE;
2280 }
2281
2282 /**
2283  * gtk_window_set_modal:
2284  * @window: a #GtkWindow
2285  * @modal: whether the window is modal
2286  * 
2287  * Sets a window modal or non-modal. Modal windows prevent interaction
2288  * with other windows in the same application. To keep modal dialogs
2289  * on top of main application windows, use
2290  * gtk_window_set_transient_for() to make the dialog transient for the
2291  * parent; most <link linkend="gtk-X11-arch">window managers</link>
2292  * will then disallow lowering the dialog below the parent.
2293  * 
2294  * 
2295  **/
2296 void
2297 gtk_window_set_modal (GtkWindow *window,
2298                       gboolean   modal)
2299 {
2300   GtkWindowPrivate *priv;
2301   GtkWidget *widget;
2302
2303   g_return_if_fail (GTK_IS_WINDOW (window));
2304
2305   priv = window->priv;
2306
2307   modal = modal != FALSE;
2308   if (priv->modal == modal)
2309     return;
2310
2311   priv->modal = modal;
2312   widget = GTK_WIDGET (window);
2313   
2314   /* adjust desired modality state */
2315   if (gtk_widget_get_realized (widget))
2316     {
2317       if (priv->modal)
2318         gdk_window_set_modal_hint (gtk_widget_get_window (widget), TRUE);
2319       else
2320         gdk_window_set_modal_hint (gtk_widget_get_window (widget), FALSE);
2321     }
2322
2323   if (gtk_widget_get_visible (widget))
2324     {
2325       if (priv->modal)
2326         gtk_grab_add (widget);
2327       else
2328         gtk_grab_remove (widget);
2329     }
2330
2331   g_object_notify (G_OBJECT (window), "modal");
2332 }
2333
2334 /**
2335  * gtk_window_get_modal:
2336  * @window: a #GtkWindow
2337  * 
2338  * Returns whether the window is modal. See gtk_window_set_modal().
2339  *
2340  * Return value: %TRUE if the window is set to be modal and
2341  *               establishes a grab when shown
2342  **/
2343 gboolean
2344 gtk_window_get_modal (GtkWindow *window)
2345 {
2346   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
2347
2348   return window->priv->modal;
2349 }
2350
2351 /**
2352  * gtk_window_list_toplevels:
2353  * 
2354  * Returns a list of all existing toplevel windows. The widgets
2355  * in the list are not individually referenced. If you want
2356  * to iterate through the list and perform actions involving
2357  * callbacks that might destroy the widgets, you <emphasis>must</emphasis> call
2358  * <literal>g_list_foreach (result, (GFunc)g_object_ref, NULL)</literal> first, and
2359  * then unref all the widgets afterwards.
2360  *
2361  * Return value: (element-type GtkWidget) (transfer container): list of toplevel widgets
2362  **/
2363 GList*
2364 gtk_window_list_toplevels (void)
2365 {
2366   GList *list = NULL;
2367   GSList *slist;
2368
2369   for (slist = toplevel_list; slist; slist = slist->next)
2370     list = g_list_prepend (list, slist->data);
2371
2372   return list;
2373 }
2374
2375 static void
2376 remove_attach_widget (GtkWindow *window)
2377 {
2378   GtkWindowPrivate *priv = window->priv;
2379
2380   if (priv->attach_widget)
2381     {
2382       _gtk_widget_remove_attached_window (priv->attach_widget, window);
2383
2384       g_object_unref (priv->attach_widget);
2385       priv->attach_widget = NULL;
2386     }
2387 }
2388
2389 static void
2390 gtk_window_dispose (GObject *object)
2391 {
2392   GtkWindow *window = GTK_WINDOW (object);
2393
2394   gtk_window_set_focus (window, NULL);
2395   gtk_window_set_default (window, NULL);
2396
2397   remove_attach_widget (GTK_WINDOW (object));
2398
2399   G_OBJECT_CLASS (gtk_window_parent_class)->dispose (object);
2400 }
2401
2402 static void
2403 parent_destroyed_callback (GtkWindow *parent, GtkWindow *child)
2404 {
2405   gtk_widget_destroy (GTK_WIDGET (child));
2406 }
2407
2408 static void
2409 connect_parent_destroyed (GtkWindow *window)
2410 {
2411   GtkWindowPrivate *priv = window->priv;
2412
2413   if (priv->transient_parent)
2414     {
2415       g_signal_connect (priv->transient_parent,
2416                         "destroy",
2417                         G_CALLBACK (parent_destroyed_callback),
2418                         window);
2419     }  
2420 }
2421
2422 static void
2423 disconnect_parent_destroyed (GtkWindow *window)
2424 {
2425   GtkWindowPrivate *priv = window->priv;
2426
2427   if (priv->transient_parent)
2428     {
2429       g_signal_handlers_disconnect_by_func (priv->transient_parent,
2430                                             parent_destroyed_callback,
2431                                             window);
2432     }
2433 }
2434
2435 static void
2436 gtk_window_transient_parent_realized (GtkWidget *parent,
2437                                       GtkWidget *window)
2438 {
2439   if (gtk_widget_get_realized (window))
2440     gdk_window_set_transient_for (gtk_widget_get_window (window),
2441                                   gtk_widget_get_window (parent));
2442 }
2443
2444 static void
2445 gtk_window_transient_parent_unrealized (GtkWidget *parent,
2446                                         GtkWidget *window)
2447 {
2448   if (gtk_widget_get_realized (window))
2449     gdk_property_delete (gtk_widget_get_window (window),
2450                          gdk_atom_intern_static_string ("WM_TRANSIENT_FOR"));
2451 }
2452
2453 static void
2454 gtk_window_transient_parent_screen_changed (GtkWindow   *parent,
2455                                             GParamSpec  *pspec,
2456                                             GtkWindow   *window)
2457 {
2458   gtk_window_set_screen (window, parent->priv->screen);
2459 }
2460
2461 static void       
2462 gtk_window_unset_transient_for  (GtkWindow *window)
2463 {
2464   GtkWindowPrivate *priv = window->priv;
2465
2466   if (priv->transient_parent)
2467     {
2468       g_signal_handlers_disconnect_by_func (priv->transient_parent,
2469                                             gtk_window_transient_parent_realized,
2470                                             window);
2471       g_signal_handlers_disconnect_by_func (priv->transient_parent,
2472                                             gtk_window_transient_parent_unrealized,
2473                                             window);
2474       g_signal_handlers_disconnect_by_func (priv->transient_parent,
2475                                             gtk_window_transient_parent_screen_changed,
2476                                             window);
2477       g_signal_handlers_disconnect_by_func (priv->transient_parent,
2478                                             gtk_widget_destroyed,
2479                                             &priv->transient_parent);
2480
2481       if (priv->destroy_with_parent)
2482         disconnect_parent_destroyed (window);
2483
2484       priv->transient_parent = NULL;
2485
2486       if (priv->transient_parent_group)
2487         {
2488           priv->transient_parent_group = FALSE;
2489           gtk_window_group_remove_window (priv->group,
2490                                           window);
2491         }
2492     }
2493 }
2494
2495 /**
2496  * gtk_window_set_transient_for:
2497  * @window: a #GtkWindow
2498  * @parent: (allow-none): parent window, or %NULL
2499  *
2500  * Dialog windows should be set transient for the main application
2501  * window they were spawned from. This allows <link
2502  * linkend="gtk-X11-arch">window managers</link> to e.g. keep the
2503  * dialog on top of the main window, or center the dialog over the
2504  * main window. gtk_dialog_new_with_buttons() and other convenience
2505  * functions in GTK+ will sometimes call
2506  * gtk_window_set_transient_for() on your behalf.
2507  *
2508  * Passing %NULL for @parent unsets the current transient window.
2509  *
2510  * On Windows, this function puts the child window on top of the parent,
2511  * much as the window manager would have done on X.
2512  */
2513 void
2514 gtk_window_set_transient_for  (GtkWindow *window,
2515                                GtkWindow *parent)
2516 {
2517   GtkWindowPrivate *priv;
2518
2519   g_return_if_fail (GTK_IS_WINDOW (window));
2520   g_return_if_fail (parent == NULL || GTK_IS_WINDOW (parent));
2521   g_return_if_fail (window != parent);
2522
2523   priv = window->priv;
2524
2525   if (priv->transient_parent)
2526     {
2527       if (gtk_widget_get_realized (GTK_WIDGET (window)) &&
2528           gtk_widget_get_realized (GTK_WIDGET (priv->transient_parent)) &&
2529           (!parent || !gtk_widget_get_realized (GTK_WIDGET (parent))))
2530         gtk_window_transient_parent_unrealized (GTK_WIDGET (priv->transient_parent),
2531                                                 GTK_WIDGET (window));
2532
2533       gtk_window_unset_transient_for (window);
2534     }
2535
2536   priv->transient_parent = parent;
2537
2538   if (parent)
2539     {
2540       g_signal_connect (parent, "destroy",
2541                         G_CALLBACK (gtk_widget_destroyed),
2542                         &priv->transient_parent);
2543       g_signal_connect (parent, "realize",
2544                         G_CALLBACK (gtk_window_transient_parent_realized),
2545                         window);
2546       g_signal_connect (parent, "unrealize",
2547                         G_CALLBACK (gtk_window_transient_parent_unrealized),
2548                         window);
2549       g_signal_connect (parent, "notify::screen",
2550                         G_CALLBACK (gtk_window_transient_parent_screen_changed),
2551                         window);
2552
2553       gtk_window_set_screen (window, parent->priv->screen);
2554
2555       if (priv->destroy_with_parent)
2556         connect_parent_destroyed (window);
2557       
2558       if (gtk_widget_get_realized (GTK_WIDGET (window)) &&
2559           gtk_widget_get_realized (GTK_WIDGET (parent)))
2560         gtk_window_transient_parent_realized (GTK_WIDGET (parent),
2561                                               GTK_WIDGET (window));
2562
2563       if (parent->priv->group)
2564         {
2565           gtk_window_group_add_window (parent->priv->group, window);
2566           priv->transient_parent_group = TRUE;
2567         }
2568     }
2569 }
2570
2571 /**
2572  * gtk_window_get_transient_for:
2573  * @window: a #GtkWindow
2574  *
2575  * Fetches the transient parent for this window. See
2576  * gtk_window_set_transient_for().
2577  *
2578  * Return value: (transfer none): the transient parent for this window, or %NULL
2579  *    if no transient parent has been set.
2580  **/
2581 GtkWindow *
2582 gtk_window_get_transient_for (GtkWindow *window)
2583 {
2584   g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
2585
2586   return window->priv->transient_parent;
2587 }
2588
2589 /**
2590  * gtk_window_set_attached_to:
2591  * @window: a #GtkWindow
2592  * @attach_widget: (allow-none): a #GtkWidget, or %NULL
2593  *
2594  * Marks @window as attached to @attach_widget. This creates a logical binding
2595  * between the window and the widget it belongs to, which is used by GTK+ to
2596  * propagate information such as styling or accessibility to @window as if it
2597  * was a children of @attach_widget.
2598  *
2599  * Examples of places where specifying this relation is useful are for instance
2600  * a #GtkMenu created by a #GtkComboBox, a completion popup window
2601  * created by #GtkEntry or a typeahead search entry created by #GtkTreeView.
2602  *
2603  * Note that this function should not be confused with
2604  * gtk_window_set_transient_for(), which specifies a window manager relation
2605  * between two toplevels instead.
2606  *
2607  * Passing %NULL for @attach_widget detaches the window.
2608  *
2609  * Since: 3.4
2610  **/
2611 void
2612 gtk_window_set_attached_to (GtkWindow *window,
2613                             GtkWidget *attach_widget)
2614 {
2615   GtkStyleContext *context;
2616   GtkWindowPrivate *priv;
2617
2618   g_return_if_fail (GTK_IS_WINDOW (window));
2619   g_return_if_fail (GTK_WIDGET (window) != attach_widget);
2620
2621   priv = window->priv;
2622
2623   if (priv->attach_widget == attach_widget)
2624     return;
2625
2626   remove_attach_widget (window);
2627
2628   priv->attach_widget = attach_widget;
2629
2630   if (priv->attach_widget)
2631     {
2632       _gtk_widget_add_attached_window (priv->attach_widget, window);
2633
2634       g_object_ref (priv->attach_widget);
2635     }
2636
2637   /* Update the style, as the widget path might change. */
2638   context = gtk_widget_get_style_context (GTK_WIDGET (window));
2639   if (priv->attach_widget)
2640     gtk_style_context_set_parent (context, gtk_widget_get_style_context (priv->attach_widget));
2641   else
2642     gtk_style_context_set_parent (context, NULL);
2643 }
2644
2645 /**
2646  * gtk_window_get_attached_to:
2647  * @window: a #GtkWindow
2648  *
2649  * Fetches the attach widget for this window. See
2650  * gtk_window_set_attached_to().
2651  *
2652  * Return value: (transfer none): the widget where the window is attached,
2653  *   or %NULL if the window is not attached to any widget.
2654  *
2655  * Since: 3.4
2656  **/
2657 GtkWidget *
2658 gtk_window_get_attached_to (GtkWindow *window)
2659 {
2660   g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
2661
2662   return window->priv->attach_widget;
2663 }
2664
2665 /**
2666  * gtk_window_set_opacity:
2667  * @window: a #GtkWindow
2668  * @opacity: desired opacity, between 0 and 1
2669  *
2670  * Request the windowing system to make @window partially transparent,
2671  * with opacity 0 being fully transparent and 1 fully opaque. (Values
2672  * of the opacity parameter are clamped to the [0,1] range.) On X11
2673  * this has any effect only on X screens with a compositing manager
2674  * running. See gtk_widget_is_composited(). On Windows it should work
2675  * always.
2676  * 
2677  * Note that setting a window's opacity after the window has been
2678  * shown causes it to flicker once on Windows.
2679  *
2680  * Since: 2.12
2681  * Deprecated: 3.8: Use gtk_widget_set_opacity instead.
2682  **/
2683 void       
2684 gtk_window_set_opacity  (GtkWindow *window, 
2685                          gdouble    opacity)
2686 {
2687   gtk_widget_set_opacity (GTK_WIDGET (window), opacity);
2688 }
2689
2690 /**
2691  * gtk_window_get_opacity:
2692  * @window: a #GtkWindow
2693  *
2694  * Fetches the requested opacity for this window. See
2695  * gtk_window_set_opacity().
2696  *
2697  * Return value: the requested opacity for this window.
2698  *
2699  * Since: 2.12
2700  * Deprecated: 3.8: Use gtk_widget_get_opacity instead.
2701  **/
2702 gdouble
2703 gtk_window_get_opacity (GtkWindow *window)
2704 {
2705   g_return_val_if_fail (GTK_IS_WINDOW (window), 0.0);
2706
2707   return gtk_widget_get_opacity (GTK_WIDGET (window));
2708 }
2709
2710 /**
2711  * gtk_window_get_application:
2712  * @window: a #GtkWindow
2713  *
2714  * Gets the #GtkApplication associated with the window (if any).
2715  *
2716  * Return value: (transfer none): a #GtkApplication, or %NULL
2717  *
2718  * Since: 3.0
2719  **/
2720 GtkApplication *
2721 gtk_window_get_application (GtkWindow *window)
2722 {
2723   g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
2724
2725   return window->priv->application;
2726 }
2727
2728 static void
2729 gtk_window_release_application (GtkWindow *window)
2730 {
2731   if (window->priv->application)
2732     {
2733       GtkApplication *application;
2734
2735       /* steal reference into temp variable */
2736       application = window->priv->application;
2737       window->priv->application = NULL;
2738
2739       gtk_application_remove_window (application, window);
2740       g_object_unref (application);
2741     }
2742 }
2743
2744 /**
2745  * gtk_window_set_application:
2746  * @window: a #GtkWindow
2747  * @application: (allow-none): a #GtkApplication, or %NULL
2748  *
2749  * Sets or unsets the #GtkApplication associated with the window.
2750  *
2751  * The application will be kept alive for at least as long as the window
2752  * is open.
2753  *
2754  * Since: 3.0
2755  **/
2756 void
2757 gtk_window_set_application (GtkWindow      *window,
2758                             GtkApplication *application)
2759 {
2760   GtkWindowPrivate *priv;
2761
2762   g_return_if_fail (GTK_IS_WINDOW (window));
2763
2764   priv = window->priv;
2765   if (priv->application != application)
2766     {
2767       gtk_window_release_application (window);
2768
2769       priv->application = application;
2770
2771       if (priv->application != NULL)
2772         {
2773           g_object_ref (priv->application);
2774
2775           gtk_application_add_window (priv->application, window);
2776         }
2777
2778       /* don't use a normal cast: application may be NULL */
2779       gtk_widget_insert_action_group (GTK_WIDGET (window), "app", (GActionGroup *) application);
2780
2781       g_object_notify (G_OBJECT (window), "application");
2782     }
2783 }
2784
2785 /**
2786  * gtk_window_set_type_hint:
2787  * @window: a #GtkWindow
2788  * @hint: the window type
2789  *
2790  * By setting the type hint for the window, you allow the window
2791  * manager to decorate and handle the window in a way which is
2792  * suitable to the function of the window in your application.
2793  *
2794  * This function should be called before the window becomes visible.
2795  *
2796  * gtk_dialog_new_with_buttons() and other convenience functions in GTK+
2797  * will sometimes call gtk_window_set_type_hint() on your behalf.
2798  * 
2799  **/
2800 void
2801 gtk_window_set_type_hint (GtkWindow           *window, 
2802                           GdkWindowTypeHint    hint)
2803 {
2804   GtkWindowPrivate *priv;
2805
2806   g_return_if_fail (GTK_IS_WINDOW (window));
2807   g_return_if_fail (!gtk_widget_get_mapped (GTK_WIDGET (window)));
2808
2809   priv = window->priv;
2810
2811   if (hint < GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU)
2812     priv->type_hint = hint;
2813   else
2814     priv->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
2815
2816   priv->reset_type_hint = TRUE;
2817   priv->gdk_type_hint = hint;
2818 }
2819
2820 /**
2821  * gtk_window_get_type_hint:
2822  * @window: a #GtkWindow
2823  *
2824  * Gets the type hint for this window. See gtk_window_set_type_hint().
2825  *
2826  * Return value: the type hint for @window.
2827  **/
2828 GdkWindowTypeHint
2829 gtk_window_get_type_hint (GtkWindow *window)
2830 {
2831   g_return_val_if_fail (GTK_IS_WINDOW (window), GDK_WINDOW_TYPE_HINT_NORMAL);
2832
2833   return window->priv->gdk_type_hint;
2834 }
2835
2836 /**
2837  * gtk_window_set_skip_taskbar_hint:
2838  * @window: a #GtkWindow 
2839  * @setting: %TRUE to keep this window from appearing in the task bar
2840  * 
2841  * Windows may set a hint asking the desktop environment not to display
2842  * the window in the task bar. This function sets this hint.
2843  * 
2844  * Since: 2.2
2845  **/
2846 void
2847 gtk_window_set_skip_taskbar_hint (GtkWindow *window,
2848                                   gboolean   setting)
2849 {
2850   GtkWindowPrivate *priv;
2851
2852   g_return_if_fail (GTK_IS_WINDOW (window));
2853
2854   priv = window->priv;
2855
2856   setting = setting != FALSE;
2857
2858   if (priv->skips_taskbar != setting)
2859     {
2860       priv->skips_taskbar = setting;
2861       if (gtk_widget_get_realized (GTK_WIDGET (window)))
2862         gdk_window_set_skip_taskbar_hint (gtk_widget_get_window (GTK_WIDGET (window)),
2863                                           priv->skips_taskbar);
2864       g_object_notify (G_OBJECT (window), "skip-taskbar-hint");
2865     }
2866 }
2867
2868 /**
2869  * gtk_window_get_skip_taskbar_hint:
2870  * @window: a #GtkWindow
2871  * 
2872  * Gets the value set by gtk_window_set_skip_taskbar_hint()
2873  * 
2874  * Return value: %TRUE if window shouldn't be in taskbar
2875  * 
2876  * Since: 2.2
2877  **/
2878 gboolean
2879 gtk_window_get_skip_taskbar_hint (GtkWindow *window)
2880 {
2881   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
2882
2883   return window->priv->skips_taskbar;
2884 }
2885
2886 /**
2887  * gtk_window_set_skip_pager_hint:
2888  * @window: a #GtkWindow 
2889  * @setting: %TRUE to keep this window from appearing in the pager
2890  * 
2891  * Windows may set a hint asking the desktop environment not to display
2892  * the window in the pager. This function sets this hint.
2893  * (A "pager" is any desktop navigation tool such as a workspace
2894  * switcher that displays a thumbnail representation of the windows
2895  * on the screen.)
2896  * 
2897  * Since: 2.2
2898  **/
2899 void
2900 gtk_window_set_skip_pager_hint (GtkWindow *window,
2901                                 gboolean   setting)
2902 {
2903   GtkWindowPrivate *priv;
2904
2905   g_return_if_fail (GTK_IS_WINDOW (window));
2906
2907   priv = window->priv;
2908
2909   setting = setting != FALSE;
2910
2911   if (priv->skips_pager != setting)
2912     {
2913       priv->skips_pager = setting;
2914       if (gtk_widget_get_realized (GTK_WIDGET (window)))
2915         gdk_window_set_skip_pager_hint (gtk_widget_get_window (GTK_WIDGET (window)),
2916                                         priv->skips_pager);
2917       g_object_notify (G_OBJECT (window), "skip-pager-hint");
2918     }
2919 }
2920
2921 /**
2922  * gtk_window_get_skip_pager_hint:
2923  * @window: a #GtkWindow
2924  * 
2925  * Gets the value set by gtk_window_set_skip_pager_hint().
2926  * 
2927  * Return value: %TRUE if window shouldn't be in pager
2928  * 
2929  * Since: 2.2
2930  **/
2931 gboolean
2932 gtk_window_get_skip_pager_hint (GtkWindow *window)
2933 {
2934   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
2935
2936   return window->priv->skips_pager;
2937 }
2938
2939 /**
2940  * gtk_window_set_urgency_hint:
2941  * @window: a #GtkWindow 
2942  * @setting: %TRUE to mark this window as urgent
2943  * 
2944  * Windows may set a hint asking the desktop environment to draw
2945  * the users attention to the window. This function sets this hint.
2946  * 
2947  * Since: 2.8
2948  **/
2949 void
2950 gtk_window_set_urgency_hint (GtkWindow *window,
2951                              gboolean   setting)
2952 {
2953   GtkWindowPrivate *priv;
2954
2955   g_return_if_fail (GTK_IS_WINDOW (window));
2956
2957   priv = window->priv;
2958
2959   setting = setting != FALSE;
2960
2961   if (priv->urgent != setting)
2962     {
2963       priv->urgent = setting;
2964       if (gtk_widget_get_realized (GTK_WIDGET (window)))
2965         gdk_window_set_urgency_hint (gtk_widget_get_window (GTK_WIDGET (window)),
2966                                      priv->urgent);
2967       g_object_notify (G_OBJECT (window), "urgency-hint");
2968     }
2969 }
2970
2971 /**
2972  * gtk_window_get_urgency_hint:
2973  * @window: a #GtkWindow
2974  * 
2975  * Gets the value set by gtk_window_set_urgency_hint()
2976  * 
2977  * Return value: %TRUE if window is urgent
2978  * 
2979  * Since: 2.8
2980  **/
2981 gboolean
2982 gtk_window_get_urgency_hint (GtkWindow *window)
2983 {
2984   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
2985
2986   return window->priv->urgent;
2987 }
2988
2989 /**
2990  * gtk_window_set_accept_focus:
2991  * @window: a #GtkWindow 
2992  * @setting: %TRUE to let this window receive input focus
2993  * 
2994  * Windows may set a hint asking the desktop environment not to receive
2995  * the input focus. This function sets this hint.
2996  * 
2997  * Since: 2.4
2998  **/
2999 void
3000 gtk_window_set_accept_focus (GtkWindow *window,
3001                              gboolean   setting)
3002 {
3003   GtkWindowPrivate *priv;
3004
3005   g_return_if_fail (GTK_IS_WINDOW (window));
3006
3007   priv = window->priv;
3008
3009   setting = setting != FALSE;
3010
3011   if (priv->accept_focus != setting)
3012     {
3013       priv->accept_focus = setting;
3014       if (gtk_widget_get_realized (GTK_WIDGET (window)))
3015         gdk_window_set_accept_focus (gtk_widget_get_window (GTK_WIDGET (window)),
3016                                      priv->accept_focus);
3017       g_object_notify (G_OBJECT (window), "accept-focus");
3018     }
3019 }
3020
3021 /**
3022  * gtk_window_get_accept_focus:
3023  * @window: a #GtkWindow
3024  * 
3025  * Gets the value set by gtk_window_set_accept_focus().
3026  * 
3027  * Return value: %TRUE if window should receive the input focus
3028  * 
3029  * Since: 2.4
3030  **/
3031 gboolean
3032 gtk_window_get_accept_focus (GtkWindow *window)
3033 {
3034   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
3035
3036   return window->priv->accept_focus;
3037 }
3038
3039 /**
3040  * gtk_window_set_focus_on_map:
3041  * @window: a #GtkWindow 
3042  * @setting: %TRUE to let this window receive input focus on map
3043  * 
3044  * Windows may set a hint asking the desktop environment not to receive
3045  * the input focus when the window is mapped.  This function sets this
3046  * hint.
3047  * 
3048  * Since: 2.6
3049  **/
3050 void
3051 gtk_window_set_focus_on_map (GtkWindow *window,
3052                              gboolean   setting)
3053 {
3054   GtkWindowPrivate *priv;
3055
3056   g_return_if_fail (GTK_IS_WINDOW (window));
3057
3058   priv = window->priv;
3059
3060   setting = setting != FALSE;
3061
3062   if (priv->focus_on_map != setting)
3063     {
3064       priv->focus_on_map = setting;
3065       if (gtk_widget_get_realized (GTK_WIDGET (window)))
3066         gdk_window_set_focus_on_map (gtk_widget_get_window (GTK_WIDGET (window)),
3067                                      priv->focus_on_map);
3068       g_object_notify (G_OBJECT (window), "focus-on-map");
3069     }
3070 }
3071
3072 /**
3073  * gtk_window_get_focus_on_map:
3074  * @window: a #GtkWindow
3075  * 
3076  * Gets the value set by gtk_window_set_focus_on_map().
3077  * 
3078  * Return value: %TRUE if window should receive the input focus when
3079  * mapped.
3080  * 
3081  * Since: 2.6
3082  **/
3083 gboolean
3084 gtk_window_get_focus_on_map (GtkWindow *window)
3085 {
3086   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
3087
3088   return window->priv->focus_on_map;
3089 }
3090
3091 /**
3092  * gtk_window_set_destroy_with_parent:
3093  * @window: a #GtkWindow
3094  * @setting: whether to destroy @window with its transient parent
3095  * 
3096  * If @setting is %TRUE, then destroying the transient parent of @window
3097  * will also destroy @window itself. This is useful for dialogs that
3098  * shouldn't persist beyond the lifetime of the main window they're
3099  * associated with, for example.
3100  **/
3101 void
3102 gtk_window_set_destroy_with_parent  (GtkWindow *window,
3103                                      gboolean   setting)
3104 {
3105   GtkWindowPrivate *priv;
3106
3107   g_return_if_fail (GTK_IS_WINDOW (window));
3108
3109   priv = window->priv;
3110
3111   if (priv->destroy_with_parent == (setting != FALSE))
3112     return;
3113
3114   if (priv->destroy_with_parent)
3115     {
3116       disconnect_parent_destroyed (window);
3117     }
3118   else
3119     {
3120       connect_parent_destroyed (window);
3121     }
3122
3123   priv->destroy_with_parent = setting;
3124
3125   g_object_notify (G_OBJECT (window), "destroy-with-parent");
3126 }
3127
3128 /**
3129  * gtk_window_get_destroy_with_parent:
3130  * @window: a #GtkWindow
3131  * 
3132  * Returns whether the window will be destroyed with its transient parent. See
3133  * gtk_window_set_destroy_with_parent ().
3134  *
3135  * Return value: %TRUE if the window will be destroyed with its transient parent.
3136  **/
3137 gboolean
3138 gtk_window_get_destroy_with_parent (GtkWindow *window)
3139 {
3140   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
3141
3142   return window->priv->destroy_with_parent;
3143 }
3144
3145 /**
3146  * gtk_window_set_hide_titlebar_when_maximized:
3147  * @window: a #GtkWindow
3148  * @setting: whether to hide the titlebar when @window is maximized
3149  *
3150  * If @setting is %TRUE, then @window will request that it's titlebar
3151  * should be hidden when maximized.
3152  * This is useful for windows that don't convey any information other
3153  * than the application name in the titlebar, to put the available
3154  * screen space to better use. If the underlying window system does not
3155  * support the request, the setting will not have any effect.
3156  *
3157  * Since: 3.4
3158  **/
3159 void
3160 gtk_window_set_hide_titlebar_when_maximized (GtkWindow *window,
3161                                              gboolean   setting)
3162 {
3163   g_return_if_fail (GTK_IS_WINDOW (window));
3164
3165 #ifdef GDK_WINDOWING_X11
3166   {
3167     GdkWindow *gdk_window;
3168
3169     gdk_window = gtk_widget_get_window (GTK_WIDGET (window));
3170
3171     if (GDK_IS_X11_WINDOW (gdk_window))
3172       gdk_x11_window_set_hide_titlebar_when_maximized (gdk_window, setting);
3173   }
3174 #endif
3175
3176   window->priv->hide_titlebar_when_maximized = setting;
3177   g_object_notify (G_OBJECT (window), "hide-titlebar-when-maximized");
3178 }
3179
3180 /**
3181  * gtk_window_get_hide_titlebar_when_maximized:
3182  * @window: a #GtkWindow
3183  *
3184  * Returns whether the window has requested to have its titlebar hidden
3185  * when maximized. See gtk_window_set_hide_titlebar_when_maximized ().
3186  *
3187  * Return value: %TRUE if the window has requested to have its titlebar
3188  *               hidden when maximized
3189  *
3190  * Since: 3.4
3191  **/
3192 gboolean
3193 gtk_window_get_hide_titlebar_when_maximized (GtkWindow *window)
3194 {
3195   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
3196
3197   return window->priv->hide_titlebar_when_maximized;
3198 }
3199
3200 static GtkWindowGeometryInfo*
3201 gtk_window_get_geometry_info (GtkWindow *window,
3202                               gboolean   create)
3203 {
3204   GtkWindowPrivate *priv = window->priv;
3205   GtkWindowGeometryInfo *info;
3206
3207   info = priv->geometry_info;
3208   if (!info && create)
3209     {
3210       info = g_new0 (GtkWindowGeometryInfo, 1);
3211
3212       info->default_width = -1;
3213       info->default_height = -1;
3214       info->resize_width = -1;
3215       info->resize_height = -1;
3216       info->initial_x = 0;
3217       info->initial_y = 0;
3218       info->initial_pos_set = FALSE;
3219       info->default_is_geometry = FALSE;
3220       info->position_constraints_changed = FALSE;
3221       info->last.configure_request.x = 0;
3222       info->last.configure_request.y = 0;
3223       info->last.configure_request.width = -1;
3224       info->last.configure_request.height = -1;
3225       info->widget = NULL;
3226       info->mask = 0;
3227       priv->geometry_info = info;
3228     }
3229
3230   return info;
3231 }
3232
3233 /**
3234  * gtk_window_set_geometry_hints:
3235  * @window: a #GtkWindow
3236  * @geometry_widget: (allow-none): widget the geometry hints will be applied to or %NULL
3237  * @geometry: (allow-none): struct containing geometry information or %NULL
3238  * @geom_mask: mask indicating which struct fields should be paid attention to
3239  *
3240  * This function sets up hints about how a window can be resized by
3241  * the user.  You can set a minimum and maximum size; allowed resize
3242  * increments (e.g. for xterm, you can only resize by the size of a
3243  * character); aspect ratios; and more. See the #GdkGeometry struct.
3244  * 
3245  **/
3246 void       
3247 gtk_window_set_geometry_hints (GtkWindow       *window,
3248                                GtkWidget       *geometry_widget,
3249                                GdkGeometry     *geometry,
3250                                GdkWindowHints   geom_mask)
3251 {
3252   GtkWindowGeometryInfo *info;
3253
3254   g_return_if_fail (GTK_IS_WINDOW (window));
3255   g_return_if_fail (geometry_widget == NULL || GTK_IS_WIDGET (geometry_widget));
3256
3257   info = gtk_window_get_geometry_info (window, TRUE);
3258   
3259   if (info->widget)
3260     g_signal_handlers_disconnect_by_func (info->widget,
3261                                           gtk_widget_destroyed,
3262                                           &info->widget);
3263   
3264   info->widget = geometry_widget;
3265   if (info->widget)
3266     g_signal_connect (geometry_widget, "destroy",
3267                       G_CALLBACK (gtk_widget_destroyed),
3268                       &info->widget);
3269
3270   if (geometry)
3271     info->geometry = *geometry;
3272
3273   /* We store gravity in priv->gravity not in the hints. */
3274   info->mask = geom_mask & ~(GDK_HINT_WIN_GRAVITY);
3275
3276   if (geom_mask & GDK_HINT_WIN_GRAVITY)
3277     {
3278       gtk_window_set_gravity (window, geometry->win_gravity);
3279     }
3280
3281   gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window));
3282 }
3283
3284 /**
3285  * gtk_window_set_decorated:
3286  * @window: a #GtkWindow
3287  * @setting: %TRUE to decorate the window
3288  *
3289  * By default, windows are decorated with a title bar, resize
3290  * controls, etc.  Some <link linkend="gtk-X11-arch">window
3291  * managers</link> allow GTK+ to disable these decorations, creating a
3292  * borderless window. If you set the decorated property to %FALSE
3293  * using this function, GTK+ will do its best to convince the window
3294  * manager not to decorate the window. Depending on the system, this
3295  * function may not have any effect when called on a window that is
3296  * already visible, so you should call it before calling gtk_widget_show().
3297  *
3298  * On Windows, this function always works, since there's no window manager
3299  * policy involved.
3300  * 
3301  **/
3302 void
3303 gtk_window_set_decorated (GtkWindow *window,
3304                           gboolean   setting)
3305 {
3306   GtkWindowPrivate *priv;
3307   GdkWindow *gdk_window;
3308
3309   g_return_if_fail (GTK_IS_WINDOW (window));
3310
3311   priv = window->priv;
3312
3313   setting = setting != FALSE;
3314
3315   if (setting == priv->decorated)
3316     return;
3317
3318   priv->decorated = setting;
3319
3320   gdk_window = gtk_widget_get_window (GTK_WIDGET (window));
3321   if (gdk_window)
3322     {
3323       if (priv->decorated)
3324         gdk_window_set_decorations (gdk_window,
3325                                     GDK_DECOR_ALL);
3326       else
3327         gdk_window_set_decorations (gdk_window,
3328                                     0);
3329     }
3330
3331   g_object_notify (G_OBJECT (window), "decorated");
3332 }
3333
3334 /**
3335  * gtk_window_get_decorated:
3336  * @window: a #GtkWindow
3337  *
3338  * Returns whether the window has been set to have decorations
3339  * such as a title bar via gtk_window_set_decorated().
3340  *
3341  * Return value: %TRUE if the window has been set to have decorations
3342  **/
3343 gboolean
3344 gtk_window_get_decorated (GtkWindow *window)
3345 {
3346   g_return_val_if_fail (GTK_IS_WINDOW (window), TRUE);
3347
3348   return window->priv->decorated;
3349 }
3350
3351 /**
3352  * gtk_window_set_deletable:
3353  * @window: a #GtkWindow
3354  * @setting: %TRUE to decorate the window as deletable
3355  *
3356  * By default, windows have a close button in the window frame. Some 
3357  * <link linkend="gtk-X11-arch">window managers</link> allow GTK+ to 
3358  * disable this button. If you set the deletable property to %FALSE
3359  * using this function, GTK+ will do its best to convince the window
3360  * manager not to show a close button. Depending on the system, this
3361  * function may not have any effect when called on a window that is
3362  * already visible, so you should call it before calling gtk_widget_show().
3363  *
3364  * On Windows, this function always works, since there's no window manager
3365  * policy involved.
3366  *
3367  * Since: 2.10
3368  */
3369 void
3370 gtk_window_set_deletable (GtkWindow *window,
3371                           gboolean   setting)
3372 {
3373   GtkWindowPrivate *priv;
3374   GdkWindow *gdk_window;
3375
3376   g_return_if_fail (GTK_IS_WINDOW (window));
3377
3378   priv = window->priv;
3379
3380   setting = setting != FALSE;
3381
3382   if (setting == priv->deletable)
3383     return;
3384
3385   priv->deletable = setting;
3386
3387   gdk_window = gtk_widget_get_window (GTK_WIDGET (window));
3388   if (gdk_window)
3389     {
3390       if (priv->deletable)
3391         gdk_window_set_functions (gdk_window,
3392                                   GDK_FUNC_ALL);
3393       else
3394         gdk_window_set_functions (gdk_window,
3395                                   GDK_FUNC_ALL | GDK_FUNC_CLOSE);
3396     }
3397
3398   g_object_notify (G_OBJECT (window), "deletable");  
3399 }
3400
3401 /**
3402  * gtk_window_get_deletable:
3403  * @window: a #GtkWindow
3404  *
3405  * Returns whether the window has been set to have a close button
3406  * via gtk_window_set_deletable().
3407  *
3408  * Return value: %TRUE if the window has been set to have a close button
3409  *
3410  * Since: 2.10
3411  **/
3412 gboolean
3413 gtk_window_get_deletable (GtkWindow *window)
3414 {
3415   g_return_val_if_fail (GTK_IS_WINDOW (window), TRUE);
3416
3417   return window->priv->deletable;
3418 }
3419
3420 static GtkWindowIconInfo*
3421 get_icon_info (GtkWindow *window)
3422 {
3423   return g_object_get_qdata (G_OBJECT (window), quark_gtk_window_icon_info);
3424 }
3425      
3426 static void
3427 free_icon_info (GtkWindowIconInfo *info)
3428 {
3429   g_free (info->icon_name);
3430   g_slice_free (GtkWindowIconInfo, info);
3431 }
3432
3433
3434 static GtkWindowIconInfo*
3435 ensure_icon_info (GtkWindow *window)
3436 {
3437   GtkWindowIconInfo *info;
3438
3439   info = get_icon_info (window);
3440   
3441   if (info == NULL)
3442     {
3443       info = g_slice_new0 (GtkWindowIconInfo);
3444       g_object_set_qdata_full (G_OBJECT (window),
3445                               quark_gtk_window_icon_info,
3446                               info,
3447                               (GDestroyNotify)free_icon_info);
3448     }
3449
3450   return info;
3451 }
3452
3453 static GList *
3454 icon_list_from_theme (GtkWidget    *widget,
3455                       const gchar  *name)
3456 {
3457   GList *list;
3458
3459   GtkIconTheme *icon_theme;
3460   GdkPixbuf *icon;
3461   gint *sizes;
3462   gint i;
3463
3464   icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (widget));
3465
3466   sizes = gtk_icon_theme_get_icon_sizes (icon_theme, name);
3467
3468   list = NULL;
3469   for (i = 0; sizes[i]; i++)
3470     {      
3471       /* FIXME
3472        * We need an EWMH extension to handle scalable icons 
3473        * by passing their name to the WM. For now just use a 
3474        * fixed size of 48.
3475        */ 
3476       if (sizes[i] == -1)
3477         icon = gtk_icon_theme_load_icon (icon_theme, name,
3478                                          48, 0, NULL);
3479       else
3480         icon = gtk_icon_theme_load_icon (icon_theme, name,
3481                                          sizes[i], 0, NULL);
3482       if (icon)
3483         list = g_list_append (list, icon);
3484     }
3485
3486   g_free (sizes);
3487
3488   return list;
3489 }
3490
3491
3492 static void
3493 gtk_window_realize_icon (GtkWindow *window)
3494 {
3495   GtkWindowPrivate *priv = window->priv;
3496   GtkWidget *widget;
3497   GtkWindowIconInfo *info;
3498   GdkWindow *gdk_window;
3499   GList *icon_list;
3500
3501   widget = GTK_WIDGET (window);
3502   gdk_window = gtk_widget_get_window (widget);
3503
3504   g_return_if_fail (gdk_window != NULL);
3505
3506   /* no point setting an icon on override-redirect */
3507   if (priv->type == GTK_WINDOW_POPUP)
3508     return;
3509
3510   icon_list = NULL;
3511   
3512   info = ensure_icon_info (window);
3513
3514   if (info->realized)
3515     return;
3516
3517   info->using_default_icon = FALSE;
3518   info->using_parent_icon = FALSE;
3519   info->using_themed_icon = FALSE;
3520   
3521   icon_list = info->icon_list;
3522
3523   /* Look up themed icon */
3524   if (icon_list == NULL && info->icon_name) 
3525     {
3526       icon_list = icon_list_from_theme (widget, info->icon_name);
3527       if (icon_list)
3528         info->using_themed_icon = TRUE;
3529     }
3530
3531   /* Inherit from transient parent */
3532   if (icon_list == NULL && priv->transient_parent)
3533     {
3534       icon_list = ensure_icon_info (priv->transient_parent)->icon_list;
3535       if (icon_list)
3536         info->using_parent_icon = TRUE;
3537     }      
3538
3539   /* Inherit from default */
3540   if (icon_list == NULL)
3541     {
3542       icon_list = default_icon_list;
3543       if (icon_list)
3544         info->using_default_icon = TRUE;
3545     }
3546
3547   /* Look up themed icon */
3548   if (icon_list == NULL && default_icon_name) 
3549     {
3550       icon_list = icon_list_from_theme (widget, default_icon_name);
3551       info->using_default_icon = TRUE;
3552       info->using_themed_icon = TRUE;  
3553     }
3554
3555   info->realized = TRUE;
3556
3557   gdk_window_set_icon_list (gtk_widget_get_window (widget), icon_list);
3558   
3559   if (info->using_themed_icon) 
3560     {
3561       GtkIconTheme *icon_theme;
3562
3563       g_list_free_full (icon_list, g_object_unref);
3564  
3565       icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (window)));
3566       g_signal_connect (icon_theme, "changed",
3567                         G_CALLBACK (update_themed_icon), window);
3568     }
3569 }
3570
3571 static void
3572 gtk_window_unrealize_icon (GtkWindow *window)
3573 {
3574   GtkWindowIconInfo *info;
3575
3576   info = get_icon_info (window);
3577
3578   if (info == NULL)
3579     return;
3580   
3581   if (info->using_themed_icon)
3582     {
3583       GtkIconTheme *icon_theme;
3584
3585       icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (window)));
3586
3587       g_signal_handlers_disconnect_by_func (icon_theme, update_themed_icon, window);
3588     }
3589     
3590   /* We don't clear the properties on the window, just figure the
3591    * window is going away.
3592    */
3593
3594   info->realized = FALSE;
3595
3596 }
3597
3598 /**
3599  * gtk_window_set_icon_list:
3600  * @window: a #GtkWindow
3601  * @list: (element-type GdkPixbuf): list of #GdkPixbuf
3602  *
3603  * Sets up the icon representing a #GtkWindow. The icon is used when
3604  * the window is minimized (also known as iconified).  Some window
3605  * managers or desktop environments may also place it in the window
3606  * frame, or display it in other contexts.
3607  *
3608  * gtk_window_set_icon_list() allows you to pass in the same icon in
3609  * several hand-drawn sizes. The list should contain the natural sizes
3610  * your icon is available in; that is, don't scale the image before
3611  * passing it to GTK+. Scaling is postponed until the last minute,
3612  * when the desired final size is known, to allow best quality.
3613  *
3614  * By passing several sizes, you may improve the final image quality
3615  * of the icon, by reducing or eliminating automatic image scaling.
3616  *
3617  * Recommended sizes to provide: 16x16, 32x32, 48x48 at minimum, and
3618  * larger images (64x64, 128x128) if you have them.
3619  *
3620  * See also gtk_window_set_default_icon_list() to set the icon
3621  * for all windows in your application in one go.
3622  *
3623  * Note that transient windows (those who have been set transient for another
3624  * window using gtk_window_set_transient_for()) will inherit their
3625  * icon from their transient parent. So there's no need to explicitly
3626  * set the icon on transient windows.
3627  **/
3628 void
3629 gtk_window_set_icon_list (GtkWindow  *window,
3630                           GList      *list)
3631 {
3632   GtkWindowIconInfo *info;
3633
3634   g_return_if_fail (GTK_IS_WINDOW (window));
3635
3636   info = ensure_icon_info (window);
3637
3638   if (info->icon_list == list) /* check for NULL mostly */
3639     return;
3640
3641   g_list_foreach (list,
3642                   (GFunc) g_object_ref, NULL);
3643
3644   g_list_free_full (info->icon_list, g_object_unref);
3645
3646   info->icon_list = g_list_copy (list);
3647
3648   g_object_notify (G_OBJECT (window), "icon");
3649   
3650   gtk_window_unrealize_icon (window);
3651   
3652   if (gtk_widget_get_realized (GTK_WIDGET (window)))
3653     gtk_window_realize_icon (window);
3654
3655   /* We could try to update our transient children, but I don't think
3656    * it's really worth it. If we did it, the best way would probably
3657    * be to have children connect to notify::icon-list
3658    */
3659 }
3660
3661 /**
3662  * gtk_window_get_icon_list:
3663  * @window: a #GtkWindow
3664  * 
3665  * Retrieves the list of icons set by gtk_window_set_icon_list().
3666  * The list is copied, but the reference count on each
3667  * member won't be incremented.
3668  *
3669  * Return value: (element-type GdkPixbuf) (transfer container): copy of window's icon list
3670  **/
3671 GList*
3672 gtk_window_get_icon_list (GtkWindow  *window)
3673 {
3674   GtkWindowIconInfo *info;
3675   
3676   g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
3677
3678   info = get_icon_info (window);
3679
3680   if (info)
3681     return g_list_copy (info->icon_list);
3682   else
3683     return NULL;  
3684 }
3685
3686 /**
3687  * gtk_window_set_icon:
3688  * @window: a #GtkWindow
3689  * @icon: (allow-none): icon image, or %NULL
3690  *
3691  * Sets up the icon representing a #GtkWindow. This icon is used when
3692  * the window is minimized (also known as iconified).  Some window
3693  * managers or desktop environments may also place it in the window
3694  * frame, or display it in other contexts.
3695  *
3696  * The icon should be provided in whatever size it was naturally
3697  * drawn; that is, don't scale the image before passing it to
3698  * GTK+. Scaling is postponed until the last minute, when the desired
3699  * final size is known, to allow best quality.
3700  *
3701  * If you have your icon hand-drawn in multiple sizes, use
3702  * gtk_window_set_icon_list(). Then the best size will be used.
3703  *
3704  * This function is equivalent to calling gtk_window_set_icon_list()
3705  * with a 1-element list.
3706  *
3707  * See also gtk_window_set_default_icon_list() to set the icon
3708  * for all windows in your application in one go.
3709  **/
3710 void
3711 gtk_window_set_icon (GtkWindow  *window,
3712                      GdkPixbuf  *icon)
3713 {
3714   GList *list;
3715   
3716   g_return_if_fail (GTK_IS_WINDOW (window));
3717   g_return_if_fail (icon == NULL || GDK_IS_PIXBUF (icon));
3718
3719   list = NULL;
3720
3721   if (icon)
3722     list = g_list_append (list, icon);
3723   
3724   gtk_window_set_icon_list (window, list);
3725   g_list_free (list);  
3726 }
3727
3728
3729 static void 
3730 update_themed_icon (GtkIconTheme *icon_theme,
3731                     GtkWindow    *window)
3732 {
3733   g_object_notify (G_OBJECT (window), "icon");
3734   
3735   gtk_window_unrealize_icon (window);
3736   
3737   if (gtk_widget_get_realized (GTK_WIDGET (window)))
3738     gtk_window_realize_icon (window);  
3739 }
3740
3741 /**
3742  * gtk_window_set_icon_name:
3743  * @window: a #GtkWindow
3744  * @name: (allow-none): the name of the themed icon
3745  *
3746  * Sets the icon for the window from a named themed icon. See
3747  * the docs for #GtkIconTheme for more details.
3748  *
3749  * Note that this has nothing to do with the WM_ICON_NAME 
3750  * property which is mentioned in the ICCCM.
3751  *
3752  * Since: 2.6
3753  */
3754 void 
3755 gtk_window_set_icon_name (GtkWindow   *window,
3756                           const gchar *name)
3757 {
3758   GtkWindowIconInfo *info;
3759   gchar *tmp;
3760   
3761   g_return_if_fail (GTK_IS_WINDOW (window));
3762
3763   info = ensure_icon_info (window);
3764
3765   if (g_strcmp0 (info->icon_name, name) == 0)
3766     return;
3767
3768   tmp = info->icon_name;
3769   info->icon_name = g_strdup (name);
3770   g_free (tmp);
3771
3772   g_list_free_full (info->icon_list, g_object_unref);
3773   info->icon_list = NULL;
3774   
3775   update_themed_icon (NULL, window);
3776
3777   g_object_notify (G_OBJECT (window), "icon-name");
3778 }
3779
3780 /**
3781  * gtk_window_get_icon_name:
3782  * @window: a #GtkWindow
3783  *
3784  * Returns the name of the themed icon for the window,
3785  * see gtk_window_set_icon_name().
3786  *
3787  * Returns: the icon name or %NULL if the window has 
3788  * no themed icon
3789  *
3790  * Since: 2.6
3791  */
3792 const gchar *
3793 gtk_window_get_icon_name (GtkWindow *window)
3794 {
3795   GtkWindowIconInfo *info;
3796
3797   g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
3798
3799   info = ensure_icon_info (window);
3800
3801   return info->icon_name;
3802 }
3803
3804 /**
3805  * gtk_window_get_icon:
3806  * @window: a #GtkWindow
3807  * 
3808  * Gets the value set by gtk_window_set_icon() (or if you've
3809  * called gtk_window_set_icon_list(), gets the first icon in
3810  * the icon list).
3811  *
3812  * Return value: (transfer none): icon for window
3813  **/
3814 GdkPixbuf*
3815 gtk_window_get_icon (GtkWindow  *window)
3816 {
3817   GtkWindowIconInfo *info;
3818
3819   g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
3820
3821   info = get_icon_info (window);
3822   if (info && info->icon_list)
3823     return GDK_PIXBUF (info->icon_list->data);
3824   else
3825     return NULL;
3826 }
3827
3828 /* Load pixbuf, printing warning on failure if error == NULL
3829  */
3830 static GdkPixbuf *
3831 load_pixbuf_verbosely (const char *filename,
3832                        GError    **err)
3833 {
3834   GError *local_err = NULL;
3835   GdkPixbuf *pixbuf;
3836
3837   pixbuf = gdk_pixbuf_new_from_file (filename, &local_err);
3838
3839   if (!pixbuf)
3840     {
3841       if (err)
3842         *err = local_err;
3843       else
3844         {
3845           g_warning ("Error loading icon from file '%s':\n\t%s",
3846                      filename, local_err->message);
3847           g_error_free (local_err);
3848         }
3849     }
3850
3851   return pixbuf;
3852 }
3853
3854 /**
3855  * gtk_window_set_icon_from_file:
3856  * @window: a #GtkWindow
3857  * @filename: (type filename): location of icon file
3858  * @err: (allow-none): location to store error, or %NULL.
3859  *
3860  * Sets the icon for @window.  
3861  * Warns on failure if @err is %NULL.
3862  *
3863  * This function is equivalent to calling gtk_window_set_icon()
3864  * with a pixbuf created by loading the image from @filename.
3865  *
3866  * Returns: %TRUE if setting the icon succeeded.
3867  *
3868  * Since: 2.2
3869  **/
3870 gboolean
3871 gtk_window_set_icon_from_file (GtkWindow   *window,
3872                                const gchar *filename,
3873                                GError     **err)
3874 {
3875   GdkPixbuf *pixbuf = load_pixbuf_verbosely (filename, err);
3876
3877   if (pixbuf)
3878     {
3879       gtk_window_set_icon (window, pixbuf);
3880       g_object_unref (pixbuf);
3881       
3882       return TRUE;
3883     }
3884   else
3885     return FALSE;
3886 }
3887
3888 /**
3889  * gtk_window_set_default_icon_list:
3890  * @list: (element-type GdkPixbuf) (transfer container): a list of #GdkPixbuf
3891  *
3892  * Sets an icon list to be used as fallback for windows that haven't
3893  * had gtk_window_set_icon_list() called on them to set up a
3894  * window-specific icon list. This function allows you to set up the
3895  * icon for all windows in your app at once.
3896  *
3897  * See gtk_window_set_icon_list() for more details.
3898  * 
3899  **/
3900 void
3901 gtk_window_set_default_icon_list (GList *list)
3902 {
3903   GList *toplevels;
3904   GList *tmp_list;
3905   if (list == default_icon_list)
3906     return;
3907
3908   /* Update serial so we don't used cached pixmaps/masks
3909    */
3910   default_icon_serial++;
3911   
3912   g_list_foreach (list,
3913                   (GFunc) g_object_ref, NULL);
3914
3915   g_list_free_full (default_icon_list, g_object_unref);
3916
3917   default_icon_list = g_list_copy (list);
3918   
3919   /* Update all toplevels */
3920   toplevels = gtk_window_list_toplevels ();
3921   tmp_list = toplevels;
3922   while (tmp_list != NULL)
3923     {
3924       GtkWindowIconInfo *info;
3925       GtkWindow *w = tmp_list->data;
3926       
3927       info = get_icon_info (w);
3928       if (info && info->using_default_icon)
3929         {
3930           gtk_window_unrealize_icon (w);
3931           if (gtk_widget_get_realized (GTK_WIDGET (w)))
3932             gtk_window_realize_icon (w);
3933         }
3934
3935       tmp_list = tmp_list->next;
3936     }
3937   g_list_free (toplevels);
3938 }
3939
3940 /**
3941  * gtk_window_set_default_icon:
3942  * @icon: the icon
3943  *
3944  * Sets an icon to be used as fallback for windows that haven't
3945  * had gtk_window_set_icon() called on them from a pixbuf.
3946  *
3947  * Since: 2.4
3948  **/
3949 void
3950 gtk_window_set_default_icon (GdkPixbuf *icon)
3951 {
3952   GList *list;
3953   
3954   g_return_if_fail (GDK_IS_PIXBUF (icon));
3955
3956   list = g_list_prepend (NULL, icon);
3957   gtk_window_set_default_icon_list (list);
3958   g_list_free (list);
3959 }
3960
3961 /**
3962  * gtk_window_set_default_icon_name:
3963  * @name: the name of the themed icon
3964  *
3965  * Sets an icon to be used as fallback for windows that haven't
3966  * had gtk_window_set_icon_list() called on them from a named
3967  * themed icon, see gtk_window_set_icon_name().
3968  *
3969  * Since: 2.6
3970  **/
3971 void
3972 gtk_window_set_default_icon_name (const gchar *name)
3973 {
3974   GList *tmp_list;
3975   GList *toplevels;
3976
3977   /* Update serial so we don't used cached pixmaps/masks
3978    */
3979   default_icon_serial++;
3980
3981   g_free (default_icon_name);
3982   default_icon_name = g_strdup (name);
3983
3984   g_list_free_full (default_icon_list, g_object_unref);
3985   default_icon_list = NULL;
3986   
3987   /* Update all toplevels */
3988   toplevels = gtk_window_list_toplevels ();
3989   tmp_list = toplevels;
3990   while (tmp_list != NULL)
3991     {
3992       GtkWindowIconInfo *info;
3993       GtkWindow *w = tmp_list->data;
3994       
3995       info = get_icon_info (w);
3996       if (info && info->using_default_icon && info->using_themed_icon)
3997         {
3998           gtk_window_unrealize_icon (w);
3999           if (gtk_widget_get_realized (GTK_WIDGET (w)))
4000             gtk_window_realize_icon (w);
4001         }
4002
4003       tmp_list = tmp_list->next;
4004     }
4005   g_list_free (toplevels);
4006 }
4007
4008 /**
4009  * gtk_window_get_default_icon_name:
4010  *
4011  * Returns the fallback icon name for windows that has been set
4012  * with gtk_window_set_default_icon_name(). The returned
4013  * string is owned by GTK+ and should not be modified. It
4014  * is only valid until the next call to
4015  * gtk_window_set_default_icon_name().
4016  *
4017  * Returns: the fallback icon name for windows
4018  *
4019  * Since: 2.16
4020  */
4021 const gchar *
4022 gtk_window_get_default_icon_name (void)
4023 {
4024   return default_icon_name;
4025 }
4026
4027 /**
4028  * gtk_window_set_default_icon_from_file:
4029  * @filename: (type filename): location of icon file
4030  * @err: (allow-none): location to store error, or %NULL.
4031  *
4032  * Sets an icon to be used as fallback for windows that haven't
4033  * had gtk_window_set_icon_list() called on them from a file
4034  * on disk. Warns on failure if @err is %NULL.
4035  *
4036  * Returns: %TRUE if setting the icon succeeded.
4037  *
4038  * Since: 2.2
4039  **/
4040 gboolean
4041 gtk_window_set_default_icon_from_file (const gchar *filename,
4042                                        GError     **err)
4043 {
4044   GdkPixbuf *pixbuf = load_pixbuf_verbosely (filename, err);
4045
4046   if (pixbuf)
4047     {
4048       gtk_window_set_default_icon (pixbuf);
4049       g_object_unref (pixbuf);
4050       
4051       return TRUE;
4052     }
4053   else
4054     return FALSE;
4055 }
4056
4057 /**
4058  * gtk_window_get_default_icon_list:
4059  * 
4060  * Gets the value set by gtk_window_set_default_icon_list().
4061  * The list is a copy and should be freed with g_list_free(),
4062  * but the pixbufs in the list have not had their reference count
4063  * incremented.
4064  * 
4065  * Return value: (element-type GdkPixbuf) (transfer container): copy of default icon list 
4066  **/
4067 GList*
4068 gtk_window_get_default_icon_list (void)
4069 {
4070   return g_list_copy (default_icon_list);
4071 }
4072
4073 static void
4074 gtk_window_set_default_size_internal (GtkWindow    *window,
4075                                       gboolean      change_width,
4076                                       gint          width,
4077                                       gboolean      change_height,
4078                                       gint          height,
4079                                       gboolean      is_geometry)
4080 {
4081   GtkWindowGeometryInfo *info;
4082
4083   g_return_if_fail (change_width == FALSE || width >= -1);
4084   g_return_if_fail (change_height == FALSE || height >= -1);
4085
4086   info = gtk_window_get_geometry_info (window, TRUE);
4087
4088   g_object_freeze_notify (G_OBJECT (window));
4089
4090   info->default_is_geometry = is_geometry != FALSE;
4091
4092   if (change_width)
4093     {
4094       if (width == 0)
4095         width = 1;
4096
4097       if (width < 0)
4098         width = -1;
4099
4100       info->default_width = width;
4101
4102       g_object_notify (G_OBJECT (window), "default-width");
4103     }
4104
4105   if (change_height)
4106     {
4107       if (height == 0)
4108         height = 1;
4109
4110       if (height < 0)
4111         height = -1;
4112
4113       info->default_height = height;
4114       
4115       g_object_notify (G_OBJECT (window), "default-height");
4116     }
4117   
4118   g_object_thaw_notify (G_OBJECT (window));
4119   
4120   gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window));
4121 }
4122
4123 /**
4124  * gtk_window_set_default_size:
4125  * @window: a #GtkWindow
4126  * @width: width in pixels, or -1 to unset the default width
4127  * @height: height in pixels, or -1 to unset the default height
4128  *
4129  * Sets the default size of a window. If the window's "natural" size
4130  * (its size request) is larger than the default, the default will be
4131  * ignored. More generally, if the default size does not obey the
4132  * geometry hints for the window (gtk_window_set_geometry_hints() can
4133  * be used to set these explicitly), the default size will be clamped
4134  * to the nearest permitted size.
4135  * 
4136  * Unlike gtk_widget_set_size_request(), which sets a size request for
4137  * a widget and thus would keep users from shrinking the window, this
4138  * function only sets the initial size, just as if the user had
4139  * resized the window themselves. Users can still shrink the window
4140  * again as they normally would. Setting a default size of -1 means to
4141  * use the "natural" default size (the size request of the window).
4142  *
4143  * For more control over a window's initial size and how resizing works,
4144  * investigate gtk_window_set_geometry_hints().
4145  *
4146  * For some uses, gtk_window_resize() is a more appropriate function.
4147  * gtk_window_resize() changes the current size of the window, rather
4148  * than the size to be used on initial display. gtk_window_resize() always
4149  * affects the window itself, not the geometry widget.
4150  *
4151  * The default size of a window only affects the first time a window is
4152  * shown; if a window is hidden and re-shown, it will remember the size
4153  * it had prior to hiding, rather than using the default size.
4154  *
4155  * Windows can't actually be 0x0 in size, they must be at least 1x1, but
4156  * passing 0 for @width and @height is OK, resulting in a 1x1 default size.
4157  **/
4158 void       
4159 gtk_window_set_default_size (GtkWindow   *window,
4160                              gint         width,
4161                              gint         height)
4162 {
4163   g_return_if_fail (GTK_IS_WINDOW (window));
4164   g_return_if_fail (width >= -1);
4165   g_return_if_fail (height >= -1);
4166
4167   gtk_window_set_default_size_internal (window, TRUE, width, TRUE, height, FALSE);
4168 }
4169
4170 /**
4171  * gtk_window_set_default_geometry:
4172  * @window: a #GtkWindow
4173  * @width: width in resize increments, or -1 to unset the default width
4174  * @height: height in resize increments, or -1 to unset the default height
4175  *
4176  * Like gtk_window_set_default_size(), but @width and @height are interpreted
4177  * in terms of the base size and increment set with
4178  * gtk_window_set_geometry_hints.
4179  *
4180  * Since: 3.0
4181  */
4182 void
4183 gtk_window_set_default_geometry (GtkWindow *window,
4184                                  gint       width,
4185                                  gint       height)
4186 {
4187   g_return_if_fail (GTK_IS_WINDOW (window));
4188   g_return_if_fail (width >= -1);
4189   g_return_if_fail (height >= -1);
4190
4191   gtk_window_set_default_size_internal (window, TRUE, width, TRUE, height, TRUE);
4192 }
4193
4194 /**
4195  * gtk_window_get_default_size:
4196  * @window: a #GtkWindow
4197  * @width: (out) (allow-none): location to store the default width, or %NULL
4198  * @height: (out) (allow-none): location to store the default height, or %NULL
4199  *
4200  * Gets the default size of the window. A value of -1 for the width or
4201  * height indicates that a default size has not been explicitly set
4202  * for that dimension, so the "natural" size of the window will be
4203  * used.
4204  * 
4205  **/
4206 void
4207 gtk_window_get_default_size (GtkWindow *window,
4208                              gint      *width,
4209                              gint      *height)
4210 {
4211   GtkWindowGeometryInfo *info;
4212
4213   g_return_if_fail (GTK_IS_WINDOW (window));
4214
4215   info = gtk_window_get_geometry_info (window, FALSE);
4216
4217   if (width)
4218     *width = info ? info->default_width : -1;
4219
4220   if (height)
4221     *height = info ? info->default_height : -1;
4222 }
4223
4224 /**
4225  * gtk_window_resize:
4226  * @window: a #GtkWindow
4227  * @width: width in pixels to resize the window to
4228  * @height: height in pixels to resize the window to
4229  *
4230  * Resizes the window as if the user had done so, obeying geometry
4231  * constraints. The default geometry constraint is that windows may
4232  * not be smaller than their size request; to override this
4233  * constraint, call gtk_widget_set_size_request() to set the window's
4234  * request to a smaller value.
4235  *
4236  * If gtk_window_resize() is called before showing a window for the
4237  * first time, it overrides any default size set with
4238  * gtk_window_set_default_size().
4239  *
4240  * Windows may not be resized smaller than 1 by 1 pixels.
4241  * 
4242  **/
4243 void
4244 gtk_window_resize (GtkWindow *window,
4245                    gint       width,
4246                    gint       height)
4247 {
4248   GtkWindowGeometryInfo *info;
4249   
4250   g_return_if_fail (GTK_IS_WINDOW (window));
4251   g_return_if_fail (width > 0);
4252   g_return_if_fail (height > 0);
4253
4254   info = gtk_window_get_geometry_info (window, TRUE);
4255
4256   info->resize_width = width;
4257   info->resize_height = height;
4258   info->resize_is_geometry = FALSE;
4259
4260   gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window));
4261 }
4262
4263 /**
4264  * gtk_window_resize_to_geometry:
4265  * @window: a #GtkWindow
4266  * @width: width in resize increments to resize the window to
4267  * @height: height in resize increments to resize the window to
4268  *
4269  * Like gtk_window_resize(), but @width and @height are interpreted
4270  * in terms of the base size and increment set with
4271  * gtk_window_set_geometry_hints.
4272  *
4273  * Since: 3.0
4274  */
4275 void
4276 gtk_window_resize_to_geometry (GtkWindow *window,
4277                                gint       width,
4278                                gint       height)
4279 {
4280   GtkWindowGeometryInfo *info;
4281
4282   g_return_if_fail (GTK_IS_WINDOW (window));
4283   g_return_if_fail (width > 0);
4284   g_return_if_fail (height > 0);
4285
4286   info = gtk_window_get_geometry_info (window, TRUE);
4287
4288   info->resize_width = width;
4289   info->resize_height = height;
4290   info->resize_is_geometry = TRUE;
4291
4292   gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window));
4293 }
4294
4295 /**
4296  * gtk_window_get_size:
4297  * @window: a #GtkWindow
4298  * @width: (out) (allow-none): return location for width, or %NULL
4299  * @height: (out) (allow-none): return location for height, or %NULL
4300  *
4301  * Obtains the current size of @window. If @window is not onscreen,
4302  * it returns the size GTK+ will suggest to the <link
4303  * linkend="gtk-X11-arch">window manager</link> for the initial window
4304  * size (but this is not reliably the same as the size the window
4305  * manager will actually select). The size obtained by
4306  * gtk_window_get_size() is the last size received in a
4307  * #GdkEventConfigure, that is, GTK+ uses its locally-stored size,
4308  * rather than querying the X server for the size. As a result, if you
4309  * call gtk_window_resize() then immediately call
4310  * gtk_window_get_size(), the size won't have taken effect yet. After
4311  * the window manager processes the resize request, GTK+ receives
4312  * notification that the size has changed via a configure event, and
4313  * the size of the window gets updated.
4314  *
4315  * Note 1: Nearly any use of this function creates a race condition,
4316  * because the size of the window may change between the time that you
4317  * get the size and the time that you perform some action assuming
4318  * that size is the current size. To avoid race conditions, connect to
4319  * "configure-event" on the window and adjust your size-dependent
4320  * state to match the size delivered in the #GdkEventConfigure.
4321  *
4322  * Note 2: The returned size does <emphasis>not</emphasis> include the
4323  * size of the window manager decorations (aka the window frame or
4324  * border). Those are not drawn by GTK+ and GTK+ has no reliable
4325  * method of determining their size.
4326  *
4327  * Note 3: If you are getting a window size in order to position
4328  * the window onscreen, there may be a better way. The preferred
4329  * way is to simply set the window's semantic type with
4330  * gtk_window_set_type_hint(), which allows the window manager to
4331  * e.g. center dialogs. Also, if you set the transient parent of
4332  * dialogs with gtk_window_set_transient_for() window managers
4333  * will often center the dialog over its parent window. It's
4334  * much preferred to let the window manager handle these
4335  * things rather than doing it yourself, because all apps will
4336  * behave consistently and according to user prefs if the window
4337  * manager handles it. Also, the window manager can take the size
4338  * of the window decorations/border into account, while your
4339  * application cannot.
4340  *
4341  * In any case, if you insist on application-specified window
4342  * positioning, there's <emphasis>still</emphasis> a better way than
4343  * doing it yourself - gtk_window_set_position() will frequently
4344  * handle the details for you.
4345  * 
4346  **/
4347 void
4348 gtk_window_get_size (GtkWindow *window,
4349                      gint      *width,
4350                      gint      *height)
4351 {
4352   gint w, h;
4353   
4354   g_return_if_fail (GTK_IS_WINDOW (window));
4355
4356   if (width == NULL && height == NULL)
4357     return;
4358
4359   if (gtk_widget_get_mapped (GTK_WIDGET (window)))
4360     {
4361       w = gdk_window_get_width (gtk_widget_get_window (GTK_WIDGET (window)));
4362       h = gdk_window_get_height (gtk_widget_get_window (GTK_WIDGET (window)));
4363     }
4364   else
4365     {
4366       GdkRectangle configure_request;
4367
4368       gtk_window_compute_configure_request (window,
4369                                             &configure_request,
4370                                             NULL, NULL);
4371
4372       w = configure_request.width;
4373       h = configure_request.height;
4374     }
4375   
4376   if (width)
4377     *width = w;
4378   if (height)
4379     *height = h;
4380 }
4381
4382 /**
4383  * gtk_window_move:
4384  * @window: a #GtkWindow
4385  * @x: X coordinate to move window to
4386  * @y: Y coordinate to move window to
4387  *
4388  * Asks the <link linkend="gtk-X11-arch">window manager</link> to move
4389  * @window to the given position.  Window managers are free to ignore
4390  * this; most window managers ignore requests for initial window
4391  * positions (instead using a user-defined placement algorithm) and
4392  * honor requests after the window has already been shown.
4393  *
4394  * Note: the position is the position of the gravity-determined
4395  * reference point for the window. The gravity determines two things:
4396  * first, the location of the reference point in root window
4397  * coordinates; and second, which point on the window is positioned at
4398  * the reference point.
4399  *
4400  * By default the gravity is #GDK_GRAVITY_NORTH_WEST, so the reference
4401  * point is simply the @x, @y supplied to gtk_window_move(). The
4402  * top-left corner of the window decorations (aka window frame or
4403  * border) will be placed at @x, @y.  Therefore, to position a window
4404  * at the top left of the screen, you want to use the default gravity
4405  * (which is #GDK_GRAVITY_NORTH_WEST) and move the window to 0,0.
4406  *
4407  * To position a window at the bottom right corner of the screen, you
4408  * would set #GDK_GRAVITY_SOUTH_EAST, which means that the reference
4409  * point is at @x + the window width and @y + the window height, and
4410  * the bottom-right corner of the window border will be placed at that
4411  * reference point. So, to place a window in the bottom right corner
4412  * you would first set gravity to south east, then write:
4413  * <literal>gtk_window_move (window, gdk_screen_width () - window_width,
4414  * gdk_screen_height () - window_height)</literal> (note that this
4415  * example does not take multi-head scenarios into account).
4416  *
4417  * The Extended Window Manager Hints specification at <ulink
4418  * url="http://www.freedesktop.org/Standards/wm-spec">
4419  * http://www.freedesktop.org/Standards/wm-spec</ulink> has a
4420  * nice table of gravities in the "implementation notes" section.
4421  *
4422  * The gtk_window_get_position() documentation may also be relevant.
4423  */
4424 void
4425 gtk_window_move (GtkWindow *window,
4426                  gint       x,
4427                  gint       y)
4428 {
4429   GtkWindowGeometryInfo *info;
4430   GtkWidget *widget;
4431
4432   g_return_if_fail (GTK_IS_WINDOW (window));
4433
4434   widget = GTK_WIDGET (window);
4435
4436   info = gtk_window_get_geometry_info (window, TRUE);  
4437
4438   if (gtk_widget_get_mapped (widget))
4439     {
4440       GtkAllocation allocation;
4441
4442       gtk_widget_get_allocation (widget, &allocation);
4443
4444       /* we have now sent a request with this position
4445        * with currently-active constraints, so toggle flag.
4446        */
4447       info->position_constraints_changed = FALSE;
4448
4449       /* we only constrain if mapped - if not mapped,
4450        * then gtk_window_compute_configure_request()
4451        * will apply the constraints later, and we
4452        * don't want to lose information about
4453        * what position the user set before then.
4454        * i.e. if you do a move() then turn off POS_CENTER
4455        * then show the window, your move() will work.
4456        */
4457       gtk_window_constrain_position (window,
4458                                      allocation.width, allocation.height,
4459                                      &x, &y);
4460
4461       /* Note that this request doesn't go through our standard request
4462        * framework, e.g. doesn't increment configure_request_count,
4463        * doesn't set info->last, etc.; that's because
4464        * we don't save the info needed to arrive at this same request
4465        * again.
4466        *
4467        * To gtk_window_move_resize(), this will end up looking exactly
4468        * the same as the position being changed by the window
4469        * manager.
4470        */
4471       gdk_window_move (gtk_widget_get_window (GTK_WIDGET (window)), x, y);
4472     }
4473   else
4474     {
4475       /* Save this position to apply on mapping */
4476       info->initial_x = x;
4477       info->initial_y = y;
4478       info->initial_pos_set = TRUE;
4479     }
4480 }
4481
4482 /**
4483  * gtk_window_get_position:
4484  * @window: a #GtkWindow
4485  * @root_x: (out) (allow-none): return location for X coordinate of
4486  *     gravity-determined reference point, or %NULL
4487  * @root_y: (out) (allow-none): return location for Y coordinate of
4488  *     gravity-determined reference point, or %NULL
4489  *
4490  * This function returns the position you need to pass to
4491  * gtk_window_move() to keep @window in its current position.
4492  * This means that the meaning of the returned value varies with
4493  * window gravity. See gtk_window_move() for more details.
4494  *
4495  * If you haven't changed the window gravity, its gravity will be
4496  * #GDK_GRAVITY_NORTH_WEST. This means that gtk_window_get_position()
4497  * gets the position of the top-left corner of the window manager
4498  * frame for the window. gtk_window_move() sets the position of this
4499  * same top-left corner.
4500  *
4501  * gtk_window_get_position() is not 100% reliable because the X Window System
4502  * does not specify a way to obtain the geometry of the
4503  * decorations placed on a window by the window manager.
4504  * Thus GTK+ is using a "best guess" that works with most
4505  * window managers.
4506  *
4507  * Moreover, nearly all window managers are historically broken with
4508  * respect to their handling of window gravity. So moving a window to
4509  * its current position as returned by gtk_window_get_position() tends
4510  * to result in moving the window slightly. Window managers are
4511  * slowly getting better over time.
4512  *
4513  * If a window has gravity #GDK_GRAVITY_STATIC the window manager
4514  * frame is not relevant, and thus gtk_window_get_position() will
4515  * always produce accurate results. However you can't use static
4516  * gravity to do things like place a window in a corner of the screen,
4517  * because static gravity ignores the window manager decorations.
4518  *
4519  * If you are saving and restoring your application's window
4520  * positions, you should know that it's impossible for applications to
4521  * do this without getting it somewhat wrong because applications do
4522  * not have sufficient knowledge of window manager state. The Correct
4523  * Mechanism is to support the session management protocol (see the
4524  * "GnomeClient" object in the GNOME libraries for example) and allow
4525  * the window manager to save your window sizes and positions.
4526  * 
4527  **/
4528
4529 void
4530 gtk_window_get_position (GtkWindow *window,
4531                          gint      *root_x,
4532                          gint      *root_y)
4533 {
4534   GtkWindowPrivate *priv;
4535   GtkWidget *widget;
4536   GdkWindow *gdk_window;
4537
4538   g_return_if_fail (GTK_IS_WINDOW (window));
4539
4540   priv = window->priv;
4541   widget = GTK_WIDGET (window);
4542   gdk_window = gtk_widget_get_window (widget);
4543
4544   if (priv->gravity == GDK_GRAVITY_STATIC)
4545     {
4546       if (gtk_widget_get_mapped (widget))
4547         {
4548           /* This does a server round-trip, which is sort of wrong;
4549            * but a server round-trip is inevitable for
4550            * gdk_window_get_frame_extents() in the usual
4551            * NorthWestGravity case below, so not sure what else to
4552            * do. We should likely be consistent about whether we get
4553            * the client-side info or the server-side info.
4554            */
4555           gdk_window_get_origin (gdk_window, root_x, root_y);
4556         }
4557       else
4558         {
4559           GdkRectangle configure_request;
4560           
4561           gtk_window_compute_configure_request (window,
4562                                                 &configure_request,
4563                                                 NULL, NULL);
4564           
4565           *root_x = configure_request.x;
4566           *root_y = configure_request.y;
4567         }
4568     }
4569   else
4570     {
4571       GdkRectangle frame_extents;
4572       
4573       gint x, y;
4574       gint w, h;
4575       
4576       if (gtk_widget_get_mapped (widget))
4577         {
4578           gdk_window_get_frame_extents (gdk_window, &frame_extents);
4579           x = frame_extents.x;
4580           y = frame_extents.y;
4581           gtk_window_get_size (window, &w, &h);
4582         }
4583       else
4584         {
4585           /* We just say the frame has 0 size on all sides.
4586            * Not sure what else to do.
4587            */
4588           gtk_window_compute_configure_request (window,
4589                                                 &frame_extents,
4590                                                 NULL, NULL);
4591           x = frame_extents.x;
4592           y = frame_extents.y;
4593           w = frame_extents.width;
4594           h = frame_extents.height;
4595         }
4596       
4597       switch (priv->gravity)
4598         {
4599         case GDK_GRAVITY_NORTH:
4600         case GDK_GRAVITY_CENTER:
4601         case GDK_GRAVITY_SOUTH:
4602           /* Find center of frame. */
4603           x += frame_extents.width / 2;
4604           /* Center client window on that point. */
4605           x -= w / 2;
4606           break;
4607
4608         case GDK_GRAVITY_SOUTH_EAST:
4609         case GDK_GRAVITY_EAST:
4610         case GDK_GRAVITY_NORTH_EAST:
4611           /* Find right edge of frame */
4612           x += frame_extents.width;
4613           /* Align left edge of client at that point. */
4614           x -= w;
4615           break;
4616         default:
4617           break;
4618         }
4619
4620       switch (priv->gravity)
4621         {
4622         case GDK_GRAVITY_WEST:
4623         case GDK_GRAVITY_CENTER:
4624         case GDK_GRAVITY_EAST:
4625           /* Find center of frame. */
4626           y += frame_extents.height / 2;
4627           /* Center client window there. */
4628           y -= h / 2;
4629           break;
4630         case GDK_GRAVITY_SOUTH_WEST:
4631         case GDK_GRAVITY_SOUTH:
4632         case GDK_GRAVITY_SOUTH_EAST:
4633           /* Find south edge of frame */
4634           y += frame_extents.height;
4635           /* Place bottom edge of client there */
4636           y -= h;
4637           break;
4638         default:
4639           break;
4640         }
4641       
4642       if (root_x)
4643         *root_x = x;
4644       if (root_y)
4645         *root_y = y;
4646     }
4647 }
4648
4649 /**
4650  * gtk_window_reshow_with_initial_size:
4651  * @window: a #GtkWindow
4652  * 
4653  * Hides @window, then reshows it, resetting the
4654  * default size and position of the window. Used
4655  * by GUI builders only.
4656  **/
4657 void
4658 gtk_window_reshow_with_initial_size (GtkWindow *window)
4659 {
4660   GtkWidget *widget;
4661   
4662   g_return_if_fail (GTK_IS_WINDOW (window));
4663
4664   widget = GTK_WIDGET (window);
4665   
4666   gtk_widget_hide (widget);
4667   gtk_widget_unrealize (widget);
4668   gtk_widget_show (widget);
4669 }
4670
4671 static void
4672 gtk_window_destroy (GtkWidget *widget)
4673 {
4674   GtkWindow *window = GTK_WINDOW (widget);
4675   GtkWindowPrivate *priv = window->priv;
4676
4677   gtk_window_release_application (window);
4678
4679   toplevel_list = g_slist_remove (toplevel_list, window);
4680
4681   if (priv->transient_parent)
4682     gtk_window_set_transient_for (window, NULL);
4683
4684   remove_attach_widget (GTK_WINDOW (widget));
4685
4686   /* frees the icons */
4687   gtk_window_set_icon_list (window, NULL);
4688
4689   if (priv->has_user_ref_count)
4690     {
4691       priv->has_user_ref_count = FALSE;
4692       g_object_unref (window);
4693     }
4694
4695   if (priv->group)
4696     gtk_window_group_remove_window (priv->group, window);
4697
4698    gtk_window_free_key_hash (window);
4699
4700   GTK_WIDGET_CLASS (gtk_window_parent_class)->destroy (widget);
4701 }
4702
4703 static void
4704 gtk_window_finalize (GObject *object)
4705 {
4706   GtkWindow *window = GTK_WINDOW (object);
4707   GtkWindowPrivate *priv = window->priv;
4708   GtkMnemonicHash *mnemonic_hash;
4709
4710   g_free (priv->title);
4711   g_free (priv->wmclass_name);
4712   g_free (priv->wmclass_class);
4713   g_free (priv->wm_role);
4714   gtk_window_release_application (window);
4715
4716   mnemonic_hash = gtk_window_get_mnemonic_hash (window, FALSE);
4717   if (mnemonic_hash)
4718     _gtk_mnemonic_hash_free (mnemonic_hash);
4719
4720   if (priv->geometry_info)
4721     {
4722       if (priv->geometry_info->widget)
4723         g_signal_handlers_disconnect_by_func (priv->geometry_info->widget,
4724                                               gtk_widget_destroyed,
4725                                               &priv->geometry_info->widget);
4726       g_free (priv->geometry_info);
4727     }
4728
4729   if (priv->keys_changed_handler)
4730     {
4731       g_source_remove (priv->keys_changed_handler);
4732       priv->keys_changed_handler = 0;
4733     }
4734
4735   if (priv->screen)
4736     g_signal_handlers_disconnect_by_func (priv->screen,
4737                                           gtk_window_on_composited_changed, window);
4738
4739   g_free (priv->startup_id);
4740
4741   if (priv->auto_mnemonics_timeout_id)
4742     {
4743       g_source_remove (priv->auto_mnemonics_timeout_id);
4744       priv->auto_mnemonics_timeout_id = 0;
4745     }
4746
4747 #ifdef GDK_WINDOWING_X11
4748   g_signal_handlers_disconnect_by_func (gtk_settings_get_default (),
4749                                         gtk_window_on_theme_variant_changed,
4750                                         window);
4751 #endif
4752
4753   G_OBJECT_CLASS (gtk_window_parent_class)->finalize (object);
4754 }
4755
4756 static void
4757 gtk_window_show (GtkWidget *widget)
4758 {
4759   GtkWindow *window = GTK_WINDOW (widget);
4760   GtkWindowPrivate *priv = window->priv;
4761   GtkContainer *container = GTK_CONTAINER (window);
4762   GtkBitmask *empty;
4763   gboolean need_resize;
4764   gboolean is_plug;
4765
4766   if (!gtk_widget_is_toplevel (GTK_WIDGET (widget)))
4767     {
4768       GTK_WIDGET_CLASS (gtk_window_parent_class)->show (widget);
4769       return;
4770     }
4771
4772   _gtk_widget_set_visible_flag (widget, TRUE);
4773
4774   need_resize = _gtk_widget_get_alloc_needed (widget) || !gtk_widget_get_realized (widget);
4775
4776   empty = _gtk_bitmask_new ();
4777   _gtk_style_context_validate (gtk_widget_get_style_context (widget),
4778                                g_get_monotonic_time (),
4779                                0,
4780                                empty);
4781   _gtk_bitmask_free (empty);
4782
4783   if (need_resize)
4784     {
4785       GtkWindowGeometryInfo *info = gtk_window_get_geometry_info (window, TRUE);
4786       GtkAllocation allocation = { 0, 0 };
4787       GdkRectangle configure_request;
4788       GdkGeometry new_geometry;
4789       guint new_flags;
4790       gboolean was_realized;
4791
4792       /* We are going to go ahead and perform this configure request
4793        * and then emulate a configure notify by going ahead and
4794        * doing a size allocate. Sort of a synchronous
4795        * mini-copy of gtk_window_move_resize() here.
4796        */
4797       gtk_window_compute_configure_request (window,
4798                                             &configure_request,
4799                                             &new_geometry,
4800                                             &new_flags);
4801       
4802       /* We update this because we are going to go ahead
4803        * and gdk_window_resize() below, rather than
4804        * queuing it.
4805        */
4806       info->last.configure_request.width = configure_request.width;
4807       info->last.configure_request.height = configure_request.height;
4808       
4809       /* and allocate the window - this is normally done
4810        * in move_resize in response to configure notify
4811        */
4812       allocation.width  = configure_request.width;
4813       allocation.height = configure_request.height;
4814       gtk_widget_size_allocate (widget, &allocation);
4815
4816       /* Then we guarantee we have a realize */
4817       was_realized = FALSE;
4818       if (!gtk_widget_get_realized (widget))
4819         {
4820           gtk_widget_realize (widget);
4821           was_realized = TRUE;
4822         }
4823
4824       /* We only send configure request if we didn't just finish
4825        * creating the window; if we just created the window
4826        * then we created it with widget->allocation anyhow.
4827        */
4828       if (!was_realized)
4829         gdk_window_move_resize (gtk_widget_get_window (widget),
4830                                 configure_request.x,
4831                                 configure_request.y,
4832                                 configure_request.width,
4833                                 configure_request.height);
4834     }
4835   
4836   gtk_container_check_resize (container);
4837
4838   gtk_widget_map (widget);
4839
4840   /* Try to make sure that we have some focused widget
4841    */
4842 #ifdef GDK_WINDOWING_X11
4843   is_plug = GDK_IS_X11_WINDOW (gtk_widget_get_window (widget)) &&
4844     GTK_IS_PLUG (window);
4845 #else
4846   is_plug = FALSE;
4847 #endif
4848   if (!priv->focus_widget && !is_plug)
4849     gtk_window_move_focus (widget, GTK_DIR_TAB_FORWARD);
4850   
4851   if (priv->modal)
4852     gtk_grab_add (widget);
4853 }
4854
4855 static void
4856 gtk_window_hide (GtkWidget *widget)
4857 {
4858   GtkWindow *window = GTK_WINDOW (widget);
4859   GtkWindowPrivate *priv = window->priv;
4860
4861   if (!gtk_widget_is_toplevel (GTK_WIDGET (widget)))
4862     {
4863       GTK_WIDGET_CLASS (gtk_window_parent_class)->hide (widget);
4864       return;
4865     }
4866
4867   _gtk_widget_set_visible_flag (widget, FALSE);
4868   gtk_widget_unmap (widget);
4869
4870   if (priv->modal)
4871     gtk_grab_remove (widget);
4872 }
4873
4874 static void
4875 gtk_window_map (GtkWidget *widget)
4876 {
4877   GtkWidget *child;
4878   GtkWindow *window = GTK_WINDOW (widget);
4879   GtkWindowPrivate *priv = window->priv;
4880   GdkWindow *gdk_window;
4881   gboolean auto_mnemonics;
4882   GtkPolicyType visible_focus;
4883
4884   if (!gtk_widget_is_toplevel (widget))
4885     {
4886       GTK_WIDGET_CLASS (gtk_window_parent_class)->map (widget);
4887       return;
4888     }
4889
4890   gtk_widget_set_mapped (widget, TRUE);
4891
4892   child = gtk_bin_get_child (&(window->bin));
4893   if (child &&
4894       gtk_widget_get_visible (child) &&
4895       !gtk_widget_get_mapped (child))
4896     gtk_widget_map (child);
4897
4898   gdk_window = gtk_widget_get_window (widget);
4899
4900   if (priv->maximize_initially)
4901     gdk_window_maximize (gdk_window);
4902   else
4903     gdk_window_unmaximize (gdk_window);
4904
4905   if (priv->stick_initially)
4906     gdk_window_stick (gdk_window);
4907   else
4908     gdk_window_unstick (gdk_window);
4909
4910   if (priv->iconify_initially)
4911     gdk_window_iconify (gdk_window);
4912   else
4913     gdk_window_deiconify (gdk_window);
4914
4915   if (priv->fullscreen_initially)
4916     gdk_window_fullscreen (gdk_window);
4917   else
4918     gdk_window_unfullscreen (gdk_window);
4919
4920   gdk_window_set_keep_above (gdk_window, priv->above_initially);
4921
4922   gdk_window_set_keep_below (gdk_window, priv->below_initially);
4923
4924   if (priv->type == GTK_WINDOW_TOPLEVEL)
4925     {
4926       gtk_window_set_theme_variant (window);
4927       gtk_window_set_hide_titlebar_when_maximized (window,
4928                                                    priv->hide_titlebar_when_maximized);
4929     }
4930
4931   /* No longer use the default settings */
4932   priv->need_default_size = FALSE;
4933   priv->need_default_position = FALSE;
4934
4935   if (priv->reset_type_hint)
4936     {
4937       /* We should only reset the type hint when the application
4938        * used gtk_window_set_type_hint() to change the hint.
4939        * Some applications use X directly to change the properties;
4940        * in that case, we shouldn't overwrite what they did.
4941        */
4942       gdk_window_set_type_hint (gdk_window, priv->gdk_type_hint);
4943       priv->reset_type_hint = FALSE;
4944     }
4945
4946   gdk_window_show (gdk_window);
4947
4948   if (priv->grip_window)
4949     gdk_window_show (priv->grip_window);
4950
4951   if (!disable_startup_notification)
4952     {
4953       /* Do we have a custom startup-notification id? */
4954       if (priv->startup_id != NULL)
4955         {
4956           /* Make sure we have a "real" id */
4957           if (!startup_id_is_fake (priv->startup_id))
4958             gdk_notify_startup_complete_with_id (priv->startup_id);
4959
4960           g_free (priv->startup_id);
4961           priv->startup_id = NULL;
4962         }
4963       else if (!sent_startup_notification)
4964         {
4965           sent_startup_notification = TRUE;
4966           gdk_notify_startup_complete ();
4967         }
4968     }
4969
4970   /* if auto-mnemonics is enabled and mnemonics visible is not already set
4971    * (as in the case of popup menus), then hide mnemonics initially
4972    */
4973   g_object_get (gtk_widget_get_settings (widget),
4974                 "gtk-auto-mnemonics", &auto_mnemonics,
4975                 "gtk-visible-focus", &visible_focus,
4976                 NULL);
4977
4978   if (auto_mnemonics && !priv->mnemonics_visible_set)
4979     gtk_window_set_mnemonics_visible (window, FALSE);
4980
4981   /* inherit from transient parent, so that a dialog that is
4982    * opened via keynav shows focus initially
4983    */
4984   if (priv->transient_parent)
4985     gtk_window_set_focus_visible (window, gtk_window_get_focus_visible (priv->transient_parent));
4986   else
4987     gtk_window_set_focus_visible (window, visible_focus == GTK_POLICY_ALWAYS);
4988 }
4989
4990 static gboolean
4991 gtk_window_map_event (GtkWidget   *widget,
4992                       GdkEventAny *event)
4993 {
4994   if (!gtk_widget_get_mapped (widget))
4995     {
4996       /* we should be be unmapped, but are getting a MapEvent, this may happen
4997        * to toplevel XWindows if mapping was intercepted by a window manager
4998        * and an unmap request occoured while the MapRequestEvent was still
4999        * being handled. we work around this situaiton here by re-requesting
5000        * the window being unmapped. more details can be found in:
5001        *   http://bugzilla.gnome.org/show_bug.cgi?id=316180
5002        */
5003       gdk_window_hide (gtk_widget_get_window (widget));
5004     }
5005   return FALSE;
5006 }
5007
5008 static void
5009 gtk_window_unmap (GtkWidget *widget)
5010 {
5011   GtkWindow *window = GTK_WINDOW (widget);
5012   GtkWindowPrivate *priv = window->priv;
5013   GtkWidget *child;
5014   GtkWindowGeometryInfo *info;
5015   GdkWindow *gdk_window;
5016   GdkWindowState state;
5017
5018   if (!gtk_widget_is_toplevel (GTK_WIDGET (widget)))
5019     {
5020       GTK_WIDGET_CLASS (gtk_window_parent_class)->unmap (widget);
5021       return;
5022     }
5023
5024   gdk_window = gtk_widget_get_window (widget);
5025
5026   gtk_widget_set_mapped (widget, FALSE);
5027   gdk_window_withdraw (gdk_window);
5028
5029   priv->configure_request_count = 0;
5030   priv->configure_notify_received = FALSE;
5031
5032   /* on unmap, we reset the default positioning of the window,
5033    * so it's placed again, but we don't reset the default
5034    * size of the window, so it's remembered.
5035    */
5036   priv->need_default_position = TRUE;
5037
5038   info = gtk_window_get_geometry_info (window, FALSE);
5039   if (info)
5040     {
5041       info->initial_pos_set = FALSE;
5042       info->position_constraints_changed = FALSE;
5043     }
5044
5045   state = gdk_window_get_state (gdk_window);
5046   priv->iconify_initially = (state & GDK_WINDOW_STATE_ICONIFIED) != 0;
5047   priv->maximize_initially = (state & GDK_WINDOW_STATE_MAXIMIZED) != 0;
5048   priv->stick_initially = (state & GDK_WINDOW_STATE_STICKY) != 0;
5049   priv->above_initially = (state & GDK_WINDOW_STATE_ABOVE) != 0;
5050   priv->below_initially = (state & GDK_WINDOW_STATE_BELOW) != 0;
5051
5052   child = gtk_bin_get_child (&(window->bin));
5053   if (child)
5054     gtk_widget_unmap (child);
5055 }
5056
5057 /* (Note: Replace "size" with "width" or "height". Also, the request
5058  * mode is honoured.)
5059  * For selecting the default window size, the following conditions
5060  * should hold (in order of importance):
5061  * - the size is not below the minimum size
5062  *   Windows cannot be resized below their minimum size, so we must
5063  *   ensure we don't do that either.
5064  * - the size is not above the natural size
5065  *   It seems weird to allocate more than this in an initial guess.
5066  * - the size does not exceed that of a maximized window
5067  *   We want to see the whole window after all.
5068  *   (Note that this may not be possible to achieve due to imperfect
5069  *    information from the windowing system.)
5070  */
5071
5072 /* We use these for now to not make windows too big by accident. Note
5073  * that we still clamp these numbers by screen size. Also note that
5074  * minimum size still overrides this. So keep your windows small! :)
5075  */
5076 #define MAX_DEFAULT_WINDOW_WIDTH 640
5077 #define MAX_DEFAULT_WINDOW_HEIGHT 480
5078
5079 static void
5080 gtk_window_guess_default_size (GtkWindow *window,
5081                                gint      *width,
5082                                gint      *height)
5083 {
5084   GtkWidget *widget = GTK_WIDGET (window);
5085   GdkScreen *screen;
5086   int minimum, natural;
5087
5088   screen = gtk_widget_get_screen (widget);
5089
5090   *width = gdk_screen_get_width (screen);
5091   *height = gdk_screen_get_height (screen);
5092
5093   if (*width >= *height)
5094     {
5095       /* landscape */
5096       *width = MIN (*width, MAX_DEFAULT_WINDOW_WIDTH);
5097       *height = MIN (*height, MAX_DEFAULT_WINDOW_HEIGHT);
5098     }
5099   else
5100     {
5101       /* portrait */
5102       *width = MIN (*width, MAX_DEFAULT_WINDOW_HEIGHT);
5103       *height = MIN (*height, MAX_DEFAULT_WINDOW_WIDTH);
5104     }
5105
5106   if (gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT)
5107     {
5108       gtk_widget_get_preferred_height (widget, &minimum, &natural);
5109       *height = MAX (minimum, MIN (*height, natural));
5110
5111       gtk_widget_get_preferred_width_for_height (widget, *height, &minimum, &natural);
5112       *width = MAX (minimum, MIN (*width, natural));
5113     }
5114   else /* GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH or CONSTANT_SIZE */
5115     {
5116       gtk_widget_get_preferred_width (widget, &minimum, &natural);
5117       *width = MAX (minimum, MIN (*width, natural));
5118
5119       gtk_widget_get_preferred_height_for_width (widget, *width, &minimum, &natural);
5120       *height = MAX (minimum, MIN (*height, natural));
5121     }
5122 }
5123
5124 static void
5125 gtk_window_realize (GtkWidget *widget)
5126 {
5127   GtkAllocation allocation;
5128   GtkWindow *window;
5129   GdkWindow *parent_window;
5130   GdkWindow *gdk_window;
5131   GdkWindowAttr attributes;
5132   gint attributes_mask;
5133   GtkWindowPrivate *priv;
5134   GtkStyleContext *context;
5135
5136   window = GTK_WINDOW (widget);
5137   priv = window->priv;
5138
5139   gtk_widget_get_allocation (widget, &allocation);
5140
5141   if (gtk_widget_get_parent_window (widget))
5142     {
5143       gtk_container_set_resize_mode (GTK_CONTAINER (widget), GTK_RESIZE_PARENT);
5144
5145       gtk_widget_set_realized (widget, TRUE);
5146
5147       attributes.x = allocation.x;
5148       attributes.y = allocation.y;
5149       attributes.width = allocation.width;
5150       attributes.height = allocation.height;
5151       attributes.window_type = GDK_WINDOW_CHILD;
5152
5153       attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK;
5154
5155       attributes.visual = gtk_widget_get_visual (widget);
5156       attributes.wclass = GDK_INPUT_OUTPUT;
5157
5158       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
5159
5160       gdk_window = gdk_window_new (gtk_widget_get_parent_window (widget),
5161                                    &attributes, attributes_mask);
5162       gtk_widget_set_window (widget, gdk_window);
5163       gtk_widget_register_window (widget, gdk_window);
5164
5165       gtk_style_context_set_background (gtk_widget_get_style_context (widget), gdk_window);
5166
5167       gdk_window_enable_synchronized_configure (gdk_window);
5168       return;
5169     }
5170
5171   gtk_container_set_resize_mode (GTK_CONTAINER (window), GTK_RESIZE_QUEUE);
5172
5173   /* ensure widget tree is properly size allocated */
5174   if (allocation.x == -1 &&
5175       allocation.y == -1 &&
5176       allocation.width == 1 &&
5177       allocation.height == 1)
5178     {
5179
5180       allocation.x = 0;
5181       allocation.y = 0;
5182
5183       gtk_window_guess_default_size (window, &allocation.width, &allocation.height);
5184       if (allocation.width == 0 || allocation.height == 0)
5185         {
5186           /* non-empty window */
5187           allocation.width = 200;
5188           allocation.height = 200;
5189         }
5190       gtk_widget_size_allocate (widget, &allocation);
5191       
5192       _gtk_container_queue_resize (GTK_CONTAINER (widget));
5193
5194       g_return_if_fail (!gtk_widget_get_realized (widget));
5195     }
5196   
5197   gtk_widget_set_realized (widget, TRUE);
5198   
5199   switch (priv->type)
5200     {
5201     case GTK_WINDOW_TOPLEVEL:
5202       attributes.window_type = GDK_WINDOW_TOPLEVEL;
5203       break;
5204     case GTK_WINDOW_POPUP:
5205       attributes.window_type = GDK_WINDOW_TEMP;
5206       break;
5207     default:
5208       g_warning (G_STRLOC": Unknown window type %d!", priv->type);
5209       break;
5210     }
5211
5212   attributes.title = priv->title;
5213   attributes.wmclass_name = priv->wmclass_name;
5214   attributes.wmclass_class = priv->wmclass_class;
5215   attributes.wclass = GDK_INPUT_OUTPUT;
5216   attributes.visual = gtk_widget_get_visual (widget);
5217
5218   attributes_mask = 0;
5219   parent_window = gtk_widget_get_root_window (widget);
5220
5221   gtk_widget_get_allocation (widget, &allocation);
5222   attributes.width = allocation.width;
5223   attributes.height = allocation.height;
5224   attributes.event_mask = gtk_widget_get_events (widget);
5225   attributes.event_mask |= (GDK_EXPOSURE_MASK |
5226                             GDK_KEY_PRESS_MASK |
5227                             GDK_KEY_RELEASE_MASK |
5228                             GDK_ENTER_NOTIFY_MASK |
5229                             GDK_LEAVE_NOTIFY_MASK |
5230                             GDK_FOCUS_CHANGE_MASK |
5231                             GDK_STRUCTURE_MASK);
5232   attributes.type_hint = priv->type_hint;
5233
5234   attributes_mask |= GDK_WA_VISUAL | GDK_WA_TYPE_HINT;
5235   attributes_mask |= (priv->title ? GDK_WA_TITLE : 0);
5236   attributes_mask |= (priv->wmclass_name ? GDK_WA_WMCLASS : 0);
5237
5238   gdk_window = gdk_window_new (parent_window, &attributes, attributes_mask);
5239   gtk_widget_set_window (widget, gdk_window);
5240
5241   gdk_window_enable_synchronized_configure (gdk_window);
5242
5243   gtk_widget_register_window (widget, gdk_window);
5244
5245   context = gtk_widget_get_style_context (widget);
5246   gtk_style_context_set_background (context, gdk_window);
5247
5248
5249   if (priv->transient_parent &&
5250       gtk_widget_get_realized (GTK_WIDGET (priv->transient_parent)))
5251     gdk_window_set_transient_for (gdk_window,
5252                                   gtk_widget_get_window (GTK_WIDGET (priv->transient_parent)));
5253
5254   if (priv->wm_role)
5255     gdk_window_set_role (gdk_window, priv->wm_role);
5256   
5257   if (!priv->decorated)
5258     gdk_window_set_decorations (gdk_window, 0);
5259   
5260   if (!priv->deletable)
5261     gdk_window_set_functions (gdk_window, GDK_FUNC_ALL | GDK_FUNC_CLOSE);
5262   
5263   if (gtk_window_get_skip_pager_hint (window))
5264     gdk_window_set_skip_pager_hint (gdk_window, TRUE);
5265   
5266   if (gtk_window_get_skip_taskbar_hint (window))
5267     gdk_window_set_skip_taskbar_hint (gdk_window, TRUE);
5268   
5269   if (gtk_window_get_accept_focus (window))
5270     gdk_window_set_accept_focus (gdk_window, TRUE);
5271   else
5272     gdk_window_set_accept_focus (gdk_window, FALSE);
5273   
5274   if (gtk_window_get_focus_on_map (window))
5275     gdk_window_set_focus_on_map (gdk_window, TRUE);
5276   else
5277     gdk_window_set_focus_on_map (gdk_window, FALSE);
5278   
5279   if (priv->modal)
5280     gdk_window_set_modal_hint (gdk_window, TRUE);
5281   else
5282     gdk_window_set_modal_hint (gdk_window, FALSE);
5283
5284   if (priv->startup_id)
5285     {
5286 #ifdef GDK_WINDOWING_X11
5287       if (GDK_IS_X11_WINDOW (gdk_window))
5288         {
5289           guint32 timestamp = extract_time_from_startup_id (priv->startup_id);
5290           if (timestamp != GDK_CURRENT_TIME)
5291             gdk_x11_window_set_user_time (gdk_window, timestamp);
5292         }
5293 #endif
5294       if (!startup_id_is_fake (priv->startup_id))
5295         gdk_window_set_startup_id (gdk_window, priv->startup_id);
5296     }
5297
5298 #ifdef GDK_WINDOWING_X11
5299   if (priv->initial_timestamp != GDK_CURRENT_TIME)
5300     {
5301       if (GDK_IS_X11_WINDOW (gdk_window))
5302         gdk_x11_window_set_user_time (gdk_window, priv->initial_timestamp);
5303     }
5304 #endif
5305
5306   /* Icons */
5307   gtk_window_realize_icon (window);
5308   
5309   if (priv->has_resize_grip)
5310     resize_grip_create_window (window);
5311 }
5312
5313 static void
5314 gtk_window_unrealize (GtkWidget *widget)
5315 {
5316   GtkWindow *window = GTK_WINDOW (widget);
5317   GtkWindowPrivate *priv = window->priv;
5318   GtkWindowGeometryInfo *info;
5319
5320   /* On unrealize, we reset the size of the window such
5321    * that we will re-apply the default sizing stuff
5322    * next time we show the window.
5323    *
5324    * Default positioning is reset on unmap, instead of unrealize.
5325    */
5326   priv->need_default_size = TRUE;
5327   info = gtk_window_get_geometry_info (window, FALSE);
5328   if (info)
5329     {
5330       info->resize_width = -1;
5331       info->resize_height = -1;
5332       info->last.configure_request.x = 0;
5333       info->last.configure_request.y = 0;
5334       info->last.configure_request.width = -1;
5335       info->last.configure_request.height = -1;
5336       /* be sure we reset geom hints on re-realize */
5337       info->last.flags = 0;
5338     }
5339
5340   /* Icons */
5341   gtk_window_unrealize_icon (window);
5342
5343   if (priv->grip_window != NULL)
5344     resize_grip_destroy_window (window);
5345
5346   GTK_WIDGET_CLASS (gtk_window_parent_class)->unrealize (widget);
5347 }
5348
5349 static GtkJunctionSides
5350 get_grip_junction (GtkWidget *widget)
5351 {
5352   if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
5353     return GTK_JUNCTION_CORNER_BOTTOMRIGHT;
5354   else
5355     return GTK_JUNCTION_CORNER_BOTTOMLEFT;
5356 }
5357
5358 static gboolean
5359 get_drag_edge (GtkWidget     *widget,
5360                GdkWindowEdge *edge)
5361 {
5362   GtkWindowPrivate *priv = GTK_WINDOW (widget)->priv;
5363   gboolean hresizable;
5364   gboolean vresizable;
5365   GtkTextDirection dir;
5366   GtkWindowGeometryInfo *info;
5367
5368   hresizable = TRUE;
5369   vresizable = TRUE;
5370
5371   info = priv->geometry_info;
5372   if (info)
5373     {
5374       GdkWindowHints flags = info->last.flags;
5375       GdkGeometry *geometry = &info->last.geometry;
5376
5377       if ((flags & GDK_HINT_MIN_SIZE) && (flags & GDK_HINT_MAX_SIZE))
5378         {
5379           hresizable = geometry->min_width < geometry->max_width;
5380           vresizable = geometry->min_height < geometry->max_height;
5381         }
5382     }
5383
5384   dir = gtk_widget_get_direction (widget);
5385
5386   if (hresizable && vresizable)
5387     *edge = dir == GTK_TEXT_DIR_LTR ? GDK_WINDOW_EDGE_SOUTH_EAST : GDK_WINDOW_EDGE_SOUTH_WEST;
5388   else if (hresizable)
5389     *edge = dir == GTK_TEXT_DIR_LTR ? GDK_WINDOW_EDGE_EAST : GDK_WINDOW_EDGE_WEST;
5390   else if (vresizable)
5391     *edge = GDK_WINDOW_EDGE_SOUTH;
5392   else
5393     return FALSE;
5394
5395   return TRUE;
5396 }
5397
5398 static void
5399 set_grip_cursor (GtkWindow *window)
5400 {
5401   GtkWidget *widget = GTK_WIDGET (window);
5402   GtkWindowPrivate *priv = window->priv;
5403
5404   if (priv->grip_window == NULL)
5405     return;
5406
5407   if (gtk_widget_is_sensitive (widget))
5408     {
5409       GdkWindowEdge edge;
5410       GdkDisplay *display;
5411       GdkCursorType cursor_type;
5412       GdkCursor *cursor;
5413
5414       cursor_type = GDK_LEFT_PTR;
5415
5416       if (get_drag_edge (widget, &edge))
5417         {
5418           switch (edge)
5419             {
5420             case GDK_WINDOW_EDGE_EAST:
5421               cursor_type = GDK_RIGHT_SIDE;
5422               break;
5423             case GDK_WINDOW_EDGE_SOUTH_EAST:
5424               cursor_type = GDK_BOTTOM_RIGHT_CORNER;
5425               break;
5426             case GDK_WINDOW_EDGE_SOUTH:
5427               cursor_type = GDK_BOTTOM_SIDE;
5428               break;
5429             case GDK_WINDOW_EDGE_SOUTH_WEST:
5430               cursor_type = GDK_BOTTOM_LEFT_CORNER;
5431               break;
5432             case GDK_WINDOW_EDGE_WEST:
5433               cursor_type = GDK_LEFT_SIDE;
5434               break;
5435             default: ;
5436             }
5437         }
5438
5439       display = gtk_widget_get_display (widget);
5440       cursor = gdk_cursor_new_for_display (display, cursor_type);
5441       gdk_window_set_cursor (priv->grip_window, cursor);
5442       g_object_unref (cursor);
5443     }
5444   else
5445     gdk_window_set_cursor (priv->grip_window, NULL);
5446 }
5447
5448 static void
5449 set_grip_shape (GtkWindow *window)
5450 {
5451   GtkWindowPrivate *priv = window->priv;
5452   cairo_region_t *region;
5453   cairo_surface_t *surface;
5454   cairo_t *cr;
5455   double width, height;
5456
5457   if (priv->grip_window == NULL)
5458     return;
5459
5460   width = gdk_window_get_width (priv->grip_window);
5461   height = gdk_window_get_height (priv->grip_window);
5462   surface = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
5463
5464   cr = cairo_create (surface);
5465   cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0);
5466   cairo_paint (cr);
5467   cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0);
5468   if (get_grip_junction (GTK_WIDGET (window)) & GTK_JUNCTION_CORNER_BOTTOMRIGHT)
5469     {
5470       cairo_move_to (cr, width, 0.0);
5471       cairo_line_to (cr, width, height);
5472       cairo_line_to (cr, 0.0, height);
5473     }
5474   else
5475     {
5476       cairo_move_to (cr, 0.0, 0.0);
5477       cairo_line_to (cr, width, height);
5478       cairo_line_to (cr, 0.0, height);
5479     }
5480   cairo_close_path (cr);
5481   cairo_fill (cr);
5482   cairo_destroy (cr);
5483   region = gdk_cairo_region_create_from_surface (surface);
5484   cairo_surface_destroy (surface);
5485
5486   gdk_window_shape_combine_region (priv->grip_window, region, 0, 0);
5487   cairo_region_destroy (region);
5488 }
5489
5490 static void
5491 set_grip_position (GtkWindow *window)
5492 {
5493   GtkWindowPrivate *priv = window->priv;
5494   GdkRectangle rect;
5495
5496   if (priv->grip_window == NULL)
5497     return;
5498
5499   gtk_window_get_resize_grip_area (window, &rect);
5500   gdk_window_raise (priv->grip_window);
5501   gdk_window_move_resize (priv->grip_window,
5502                           rect.x, rect.y,
5503                           rect.width, rect.height);
5504 }
5505
5506 /* _gtk_window_set_allocation:
5507  * @window: a #GtkWindow
5508  * @allocation: the new allocation
5509  *
5510  * This function is like gtk_widget_set_allocation()
5511  * but does the necessary extra work to update
5512  * the resize grip positioning, etc.
5513  *
5514  * Call this instead of gtk_widget_set_allocation()
5515  * when overriding ::size_allocate in a GtkWindow
5516  * subclass without chaining up.
5517  */
5518 void
5519 _gtk_window_set_allocation (GtkWindow     *window,
5520                             GtkAllocation *allocation)
5521 {
5522   GtkWidget *widget = (GtkWidget *)window;
5523
5524   gtk_widget_set_allocation (widget, allocation);
5525
5526   if (gtk_widget_get_realized (widget))
5527     {
5528       /* If it's not a toplevel we're embedded, we need to resize
5529        * the window's window and skip the grip.
5530        */
5531       if (!gtk_widget_is_toplevel (widget))
5532         {
5533           gdk_window_move_resize (gtk_widget_get_window (widget),
5534                                   allocation->x, allocation->y,
5535                                   allocation->width, allocation->height);
5536         }
5537       else
5538         {
5539           update_grip_visibility (window);
5540           set_grip_position (window);
5541         }
5542     }
5543 }
5544
5545 static void
5546 gtk_window_size_allocate (GtkWidget     *widget,
5547                           GtkAllocation *allocation)
5548 {
5549   GtkWindow *window = GTK_WINDOW (widget);
5550   GtkAllocation child_allocation;
5551   GtkWidget *child;
5552   guint border_width;
5553
5554   _gtk_window_set_allocation (window, allocation);
5555
5556   child = gtk_bin_get_child (&(window->bin));
5557   if (child && gtk_widget_get_visible (child))
5558     {
5559       border_width = gtk_container_get_border_width (GTK_CONTAINER (window));
5560       child_allocation.x = border_width;
5561       child_allocation.y = border_width;
5562       child_allocation.width = MAX (1, allocation->width - border_width * 2);
5563       child_allocation.height = MAX (1, allocation->height - border_width * 2);
5564
5565       gtk_widget_size_allocate (child, &child_allocation);
5566     }
5567 }
5568
5569 static gint
5570 gtk_window_configure_event (GtkWidget         *widget,
5571                             GdkEventConfigure *event)
5572 {
5573   GtkAllocation allocation;
5574   GtkWindow *window = GTK_WINDOW (widget);
5575   GtkWindowPrivate *priv = window->priv;
5576   gboolean expected_reply = priv->configure_request_count > 0;
5577
5578   if (!gtk_widget_is_toplevel (GTK_WIDGET (widget)))
5579     {
5580       if (GTK_WIDGET_CLASS (gtk_window_parent_class)->configure_event)
5581         return GTK_WIDGET_CLASS (gtk_window_parent_class)->configure_event (widget, event);
5582
5583       gdk_window_configure_finished (gtk_widget_get_window (widget));
5584       return FALSE;
5585     }
5586
5587   /* priv->configure_request_count incremented for each
5588    * configure request, and decremented to a min of 0 for
5589    * each configure notify.
5590    *
5591    * All it means is that we know we will get at least
5592    * priv->configure_request_count more configure notifies.
5593    * We could get more configure notifies than that; some
5594    * of the configure notifies we get may be unrelated to
5595    * the configure requests. But we will get at least
5596    * priv->configure_request_count notifies.
5597    */
5598
5599   if (priv->configure_request_count > 0)
5600     {
5601       priv->configure_request_count -= 1;
5602       gdk_window_thaw_toplevel_updates_libgtk_only (gtk_widget_get_window (widget));
5603     }
5604   
5605   /* As an optimization, we avoid a resize when possible.
5606    *
5607    * The only times we can avoid a resize are:
5608    *   - we know only the position changed, not the size
5609    *   - we know we have made more requests and so will get more
5610    *     notifies and can wait to resize when we get them
5611    */
5612   gtk_widget_get_allocation (widget, &allocation);
5613   if (!expected_reply &&
5614       (allocation.width == event->width &&
5615        allocation.height == event->height))
5616     {
5617       gdk_window_configure_finished (gtk_widget_get_window (widget));
5618       return TRUE;
5619     }
5620
5621   /*
5622    * If we do need to resize, we do that by:
5623    *   - setting configure_notify_received to TRUE
5624    *     for use in gtk_window_move_resize()
5625    *   - queueing a resize, leading to invocation of
5626    *     gtk_window_move_resize() in an idle handler
5627    *
5628    */
5629   
5630   priv->configure_notify_received = TRUE;
5631
5632   gdk_window_invalidate_rect (gtk_widget_get_window (widget), NULL, FALSE); // XXX - What was this for again?
5633
5634   _gtk_container_queue_resize (GTK_CONTAINER (widget));
5635   
5636   return TRUE;
5637 }
5638
5639 static gboolean
5640 gtk_window_state_event (GtkWidget           *widget,
5641                         GdkEventWindowState *event)
5642 {
5643   update_grip_visibility (GTK_WINDOW (widget));
5644
5645   if (event->changed_mask & GDK_WINDOW_STATE_FOCUSED)
5646     ensure_state_flag_backdrop (widget);
5647
5648   return FALSE;
5649 }
5650
5651 static void
5652 gtk_window_direction_changed (GtkWidget        *widget,
5653                               GtkTextDirection  prev_dir)
5654 {
5655   GtkWindow *window = GTK_WINDOW (widget);
5656
5657   set_grip_cursor (window);
5658   set_grip_position (window);
5659   set_grip_shape (window);
5660 }
5661
5662 static void
5663 gtk_window_state_changed (GtkWidget    *widget,
5664                           GtkStateType  previous_state)
5665 {
5666   GtkWindow *window = GTK_WINDOW (widget);
5667
5668   update_grip_visibility (window);
5669 }
5670
5671 static void
5672 gtk_window_style_updated (GtkWidget *widget)
5673 {
5674   GtkWindow *window = GTK_WINDOW (widget);
5675   GtkWindowPrivate *priv = window->priv;
5676   GdkRectangle rect;
5677
5678   GTK_WIDGET_CLASS (gtk_window_parent_class)->style_updated (widget);
5679
5680   if (priv->grip_window != NULL && gtk_window_get_resize_grip_area (window, &rect))
5681     {
5682       gdk_window_move_resize (priv->grip_window,
5683                               rect.x, rect.y,
5684                               rect.width, rect.height);
5685
5686       set_grip_shape (window);
5687     }
5688 }
5689
5690 static void
5691 resize_grip_create_window (GtkWindow *window)
5692 {
5693   GtkWidget *widget;
5694   GtkWindowPrivate *priv;
5695   GdkWindowAttr attributes;
5696   gint attributes_mask;
5697   GdkRectangle rect;
5698   GdkRGBA transparent = {0, 0, 0, 0};
5699
5700   priv = window->priv;
5701   widget = GTK_WIDGET (window);
5702
5703   g_return_if_fail (gtk_widget_get_realized (widget));
5704   g_return_if_fail (priv->grip_window == NULL);
5705
5706   gtk_window_get_resize_grip_area (window, &rect);
5707
5708   attributes.x = rect.x;
5709   attributes.y = rect.y;
5710   attributes.width = rect.width;
5711   attributes.height = rect.height;
5712   attributes.window_type = GDK_WINDOW_CHILD;
5713   attributes.wclass = GDK_INPUT_OUTPUT;
5714   attributes.event_mask = gtk_widget_get_events (widget) |
5715                           GDK_EXPOSURE_MASK |
5716                           GDK_BUTTON_PRESS_MASK;
5717
5718   attributes_mask = GDK_WA_X | GDK_WA_Y;
5719
5720   priv->grip_window = gdk_window_new (gtk_widget_get_window (widget),
5721                                       &attributes,
5722                                       attributes_mask);
5723   gdk_window_set_background_rgba (priv->grip_window, &transparent);
5724
5725   gtk_widget_register_window (widget, priv->grip_window);
5726
5727   gdk_window_raise (priv->grip_window);
5728
5729   set_grip_shape (window);
5730   update_grip_visibility (window);
5731 }
5732
5733 static void
5734 resize_grip_destroy_window (GtkWindow *window)
5735 {
5736   GtkWindowPrivate *priv = window->priv;
5737
5738   gtk_widget_unregister_window (GTK_WIDGET (window), priv->grip_window);
5739   gdk_window_destroy (priv->grip_window);
5740   priv->grip_window = NULL;
5741   update_grip_visibility (window);
5742 }
5743
5744 /**
5745  * gtk_window_set_has_resize_grip:
5746  * @window: a #GtkWindow
5747  * @value: %TRUE to allow a resize grip
5748  *
5749  * Sets whether @window has a corner resize grip.
5750  *
5751  * Note that the resize grip is only shown if the window
5752  * is actually resizable and not maximized. Use
5753  * gtk_window_resize_grip_is_visible() to find out if the
5754  * resize grip is currently shown.
5755  *
5756  * Since: 3.0
5757  */
5758 void
5759 gtk_window_set_has_resize_grip (GtkWindow *window,
5760                                 gboolean   value)
5761 {
5762   GtkWidget *widget = GTK_WIDGET (window);
5763   GtkWindowPrivate *priv = window->priv;
5764
5765   value = value != FALSE;
5766
5767   if (value != priv->has_resize_grip)
5768     {
5769       priv->has_resize_grip = value;
5770       gtk_widget_queue_draw (widget);
5771
5772       if (gtk_widget_get_realized (widget) && 
5773           gtk_widget_is_toplevel (GTK_WIDGET (widget)))
5774         {
5775           if (priv->has_resize_grip && priv->grip_window == NULL)
5776             resize_grip_create_window (window);
5777           else if (!priv->has_resize_grip && priv->grip_window != NULL)
5778             resize_grip_destroy_window (window);
5779         }
5780
5781       g_object_notify (G_OBJECT (window), "has-resize-grip");
5782     }
5783 }
5784
5785 static void
5786 update_grip_visibility (GtkWindow *window)
5787 {
5788   GtkWindowPrivate *priv = window->priv;
5789   gboolean val;
5790
5791   val = gtk_window_resize_grip_is_visible (window);
5792
5793   if (priv->grip_window != NULL)
5794     {
5795       if (val)
5796         {
5797           gdk_window_show (priv->grip_window);
5798           set_grip_cursor (window);
5799         }
5800       else
5801         {
5802           gdk_window_hide (priv->grip_window);
5803         }
5804     }
5805
5806   if (priv->resize_grip_visible != val)
5807     {
5808       priv->resize_grip_visible = val;
5809
5810       g_object_notify (G_OBJECT (window), "resize-grip-visible");
5811     }
5812 }
5813
5814 /**
5815  * gtk_window_resize_grip_is_visible:
5816  * @window: a #GtkWindow
5817  *
5818  * Determines whether a resize grip is visible for the specified window.
5819  *
5820  * Returns: %TRUE if a resize grip exists and is visible
5821  *
5822  * Since: 3.0
5823  */
5824 gboolean
5825 gtk_window_resize_grip_is_visible (GtkWindow *window)
5826 {
5827   GtkWidget *widget;
5828   GtkWindowPrivate *priv;
5829   GdkWindowEdge edge;
5830
5831   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
5832
5833   priv = window->priv;
5834   widget = GTK_WIDGET (window);
5835
5836   if (priv->type == GTK_WINDOW_POPUP)
5837     return FALSE;
5838
5839   if (!priv->resizable)
5840     return FALSE;
5841
5842   if (!gtk_widget_is_toplevel (GTK_WIDGET (widget)))
5843     return FALSE;
5844
5845   if (gtk_widget_get_realized (widget))
5846     {
5847       GdkWindowState state;
5848
5849       state = gdk_window_get_state (gtk_widget_get_window (widget));
5850
5851       if (state & GDK_WINDOW_STATE_MAXIMIZED || state & GDK_WINDOW_STATE_FULLSCREEN)
5852         return FALSE;
5853     }
5854
5855   if (!get_drag_edge (widget, &edge))
5856     return FALSE;
5857
5858   return window->priv->has_resize_grip;
5859 }
5860
5861 /**
5862  * gtk_window_get_has_resize_grip:
5863  * @window: a #GtkWindow
5864  *
5865  * Determines whether the window may have a resize grip.
5866  *
5867  * Returns: %TRUE if the window has a resize grip
5868  *
5869  * Since: 3.0
5870  */
5871 gboolean
5872 gtk_window_get_has_resize_grip (GtkWindow *window)
5873 {
5874   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
5875
5876   return window->priv->has_resize_grip;
5877 }
5878
5879 /**
5880  * gtk_window_get_resize_grip_area:
5881  * @window: a #GtkWindow
5882  * @rect: (out): a pointer to a #GdkRectangle which we should store
5883  *     the resize grip area
5884  *
5885  * If a window has a resize grip, this will retrieve the grip
5886  * position, width and height into the specified #GdkRectangle.
5887  *
5888  * Returns: %TRUE if the resize grip's area was retrieved
5889  *
5890  * Since: 3.0
5891  */
5892 gboolean
5893 gtk_window_get_resize_grip_area (GtkWindow    *window,
5894                                  GdkRectangle *rect)
5895 {
5896   GtkWidget *widget = GTK_WIDGET (window);
5897   GtkAllocation allocation;
5898   gint grip_width;
5899   gint grip_height;
5900
5901   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
5902
5903   if (!window->priv->has_resize_grip)
5904     return FALSE;
5905
5906   gtk_widget_get_allocation (widget, &allocation);
5907
5908   gtk_widget_style_get (widget,
5909                         "resize-grip-width", &grip_width,
5910                         "resize-grip-height", &grip_height,
5911                         NULL);
5912
5913   if (grip_width > allocation.width)
5914     grip_width = allocation.width;
5915
5916   if (grip_height > allocation.height)
5917     grip_height = allocation.height;
5918
5919   rect->width = grip_width;
5920   rect->height = grip_height;
5921   rect->y = allocation.y + allocation.height - grip_height;
5922
5923   if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
5924     rect->x = allocation.x + allocation.width - grip_width;
5925   else
5926     rect->x = allocation.x;
5927
5928   return TRUE;
5929 }
5930
5931 /* the accel_key and accel_mods fields of the key have to be setup
5932  * upon calling this function. it'll then return whether that key
5933  * is at all used as accelerator, and if so will OR in the
5934  * accel_flags member of the key.
5935  */
5936 gboolean
5937 _gtk_window_query_nonaccels (GtkWindow      *window,
5938                              guint           accel_key,
5939                              GdkModifierType accel_mods)
5940 {
5941   GtkWindowPrivate *priv;
5942
5943   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
5944
5945   priv = window->priv;
5946
5947   /* movement keys are considered locked accels */
5948   if (!accel_mods)
5949     {
5950       static const guint bindings[] = {
5951         GDK_KEY_space, GDK_KEY_KP_Space, GDK_KEY_Return, GDK_KEY_ISO_Enter, GDK_KEY_KP_Enter, GDK_KEY_Up, GDK_KEY_KP_Up, GDK_KEY_Down, GDK_KEY_KP_Down,
5952         GDK_KEY_Left, GDK_KEY_KP_Left, GDK_KEY_Right, GDK_KEY_KP_Right, GDK_KEY_Tab, GDK_KEY_KP_Tab, GDK_KEY_ISO_Left_Tab,
5953       };
5954       guint i;
5955       
5956       for (i = 0; i < G_N_ELEMENTS (bindings); i++)
5957         if (bindings[i] == accel_key)
5958           return TRUE;
5959     }
5960
5961   /* mnemonics are considered locked accels */
5962   if (accel_mods == priv->mnemonic_modifier)
5963     {
5964       GtkMnemonicHash *mnemonic_hash = gtk_window_get_mnemonic_hash (window, FALSE);
5965       if (mnemonic_hash && _gtk_mnemonic_hash_lookup (mnemonic_hash, accel_key))
5966         return TRUE;
5967     }
5968
5969   return FALSE;
5970 }
5971
5972 /**
5973  * gtk_window_propagate_key_event:
5974  * @window:  a #GtkWindow
5975  * @event:   a #GdkEventKey
5976  *
5977  * Propagate a key press or release event to the focus widget and
5978  * up the focus container chain until a widget handles @event.
5979  * This is normally called by the default ::key_press_event and
5980  * ::key_release_event handlers for toplevel windows,
5981  * however in some cases it may be useful to call this directly when
5982  * overriding the standard key handling for a toplevel window.
5983  *
5984  * Return value: %TRUE if a widget in the focus chain handled the event.
5985  *
5986  * Since: 2.4
5987  */
5988 gboolean
5989 gtk_window_propagate_key_event (GtkWindow        *window,
5990                                 GdkEventKey      *event)
5991 {
5992   GtkWindowPrivate *priv;
5993   gboolean handled = FALSE;
5994   GtkWidget *widget, *focus;
5995
5996   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
5997
5998   priv = window->priv;
5999   widget = GTK_WIDGET (window);
6000
6001   focus = priv->focus_widget;
6002   if (focus)
6003     g_object_ref (focus);
6004   
6005   while (!handled &&
6006          focus && focus != widget &&
6007          gtk_widget_get_toplevel (focus) == widget)
6008     {
6009       GtkWidget *parent;
6010       
6011       if (gtk_widget_is_sensitive (focus))
6012         handled = gtk_widget_event (focus, (GdkEvent*) event);
6013
6014       parent = gtk_widget_get_parent (focus);
6015       if (parent)
6016         g_object_ref (parent);
6017       
6018       g_object_unref (focus);
6019       
6020       focus = parent;
6021     }
6022   
6023   if (focus)
6024     g_object_unref (focus);
6025
6026   return handled;
6027 }
6028
6029 static gint
6030 gtk_window_key_press_event (GtkWidget   *widget,
6031                             GdkEventKey *event)
6032 {
6033   GtkWindow *window = GTK_WINDOW (widget);
6034   gboolean handled = FALSE;
6035
6036   /* handle mnemonics and accelerators */
6037   if (!handled)
6038     handled = gtk_window_activate_key (window, event);
6039
6040   /* handle focus widget key events */
6041   if (!handled)
6042     handled = gtk_window_propagate_key_event (window, event);
6043
6044   /* Chain up, invokes binding set */
6045   if (!handled)
6046     handled = GTK_WIDGET_CLASS (gtk_window_parent_class)->key_press_event (widget, event);
6047
6048   return handled;
6049 }
6050
6051 static gint
6052 gtk_window_key_release_event (GtkWidget   *widget,
6053                               GdkEventKey *event)
6054 {
6055   GtkWindow *window = GTK_WINDOW (widget);
6056   gboolean handled = FALSE;
6057
6058   /* handle focus widget key events */
6059   if (!handled)
6060     handled = gtk_window_propagate_key_event (window, event);
6061
6062   /* Chain up, invokes binding set */
6063   if (!handled)
6064     handled = GTK_WIDGET_CLASS (gtk_window_parent_class)->key_release_event (widget, event);
6065
6066   return handled;
6067 }
6068
6069 static gint
6070 gtk_window_button_press_event (GtkWidget *widget,
6071                                GdkEventButton *event)
6072 {
6073   GtkWindowPrivate *priv = GTK_WINDOW (widget)->priv;
6074   GdkWindowEdge edge;
6075
6076   if (event->window == priv->grip_window)
6077     {
6078       if (get_drag_edge (widget, &edge))
6079         gdk_window_begin_resize_drag_for_device (gtk_widget_get_window (widget),
6080                                                  edge,
6081                                                  gdk_event_get_device ((GdkEvent *) event),
6082                                                  event->button,
6083                                                  event->x_root,
6084                                                  event->y_root,
6085                                                  event->time);
6086
6087       return TRUE;
6088     }
6089
6090   return FALSE;
6091 }
6092
6093 static void
6094 gtk_window_real_activate_default (GtkWindow *window)
6095 {
6096   gtk_window_activate_default (window);
6097 }
6098
6099 static void
6100 gtk_window_real_activate_focus (GtkWindow *window)
6101 {
6102   gtk_window_activate_focus (window);
6103 }
6104
6105 static gint
6106 gtk_window_enter_notify_event (GtkWidget        *widget,
6107                                GdkEventCrossing *event)
6108 {
6109   return FALSE;
6110 }
6111
6112 static gint
6113 gtk_window_leave_notify_event (GtkWidget        *widget,
6114                                GdkEventCrossing *event)
6115 {
6116   return FALSE;
6117 }
6118
6119 static void
6120 do_focus_change (GtkWidget *widget,
6121                  gboolean   in)
6122 {
6123   GdkWindow *window;
6124   GdkDeviceManager *device_manager;
6125   GList *devices, *d;
6126
6127   g_object_ref (widget);
6128
6129   device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
6130   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
6131   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
6132   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
6133
6134   for (d = devices; d; d = d->next)
6135     {
6136       GdkDevice *dev = d->data;
6137       GdkEvent *fevent;
6138
6139       if (gdk_device_get_source (dev) != GDK_SOURCE_KEYBOARD)
6140         continue;
6141
6142       /* Skip non-master keyboards that haven't
6143        * selected for events from this window
6144        */
6145       window = gtk_widget_get_window (widget);
6146       if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
6147           window && !gdk_window_get_device_events (window, dev))
6148         continue;
6149
6150       fevent = gdk_event_new (GDK_FOCUS_CHANGE);
6151
6152       fevent->focus_change.type = GDK_FOCUS_CHANGE;
6153       fevent->focus_change.window = window;
6154       if (window)
6155         g_object_ref (window);
6156       fevent->focus_change.in = in;
6157       gdk_event_set_device (fevent, dev);
6158
6159       gtk_widget_send_focus_change (widget, fevent);
6160
6161       gdk_event_free (fevent);
6162     }
6163
6164   g_list_free (devices);
6165   g_object_unref (widget);
6166 }
6167
6168 static void
6169 maybe_set_mnemonics_visible (GtkWindow *window)
6170 {
6171   GList *devices, *d;
6172   GdkDeviceManager *device_manager;
6173
6174   device_manager = gdk_display_get_device_manager (gtk_widget_get_display (GTK_WIDGET (window)));
6175   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
6176
6177   for (d = devices; d; d = d->next)
6178     {
6179       GdkDevice *dev = d->data;
6180
6181       if (gdk_device_get_source (dev) == GDK_SOURCE_MOUSE)
6182         {
6183           GdkModifierType mask;
6184
6185           gdk_device_get_state (dev, gtk_widget_get_window (GTK_WIDGET (window)),
6186                                 NULL, &mask);
6187           if (window->priv->mnemonic_modifier == (mask & gtk_accelerator_get_default_mod_mask ()))
6188             {
6189               _gtk_window_set_auto_mnemonics_visible (window);
6190               break;
6191             }
6192         }
6193     }
6194
6195   g_list_free (devices);
6196 }
6197
6198 static gint
6199 gtk_window_focus_in_event (GtkWidget     *widget,
6200                            GdkEventFocus *event)
6201 {
6202   GtkWindow *window = GTK_WINDOW (widget);
6203   gboolean auto_mnemonics;
6204
6205   /* It appears spurious focus in events can occur when
6206    *  the window is hidden. So we'll just check to see if
6207    *  the window is visible before actually handling the
6208    *  event
6209    */
6210   if (gtk_widget_get_visible (widget))
6211     {
6212       _gtk_window_set_has_toplevel_focus (window, TRUE);
6213       _gtk_window_set_is_active (window, TRUE);
6214
6215       g_object_get (gtk_widget_get_settings (widget),
6216                     "gtk-auto-mnemonics", &auto_mnemonics, NULL);
6217       if (auto_mnemonics)
6218         maybe_set_mnemonics_visible (window);
6219     }
6220
6221   return FALSE;
6222 }
6223
6224 static gint
6225 gtk_window_focus_out_event (GtkWidget     *widget,
6226                             GdkEventFocus *event)
6227 {
6228   GtkWindow *window = GTK_WINDOW (widget);
6229   gboolean auto_mnemonics;
6230
6231   _gtk_window_set_has_toplevel_focus (window, FALSE);
6232   _gtk_window_set_is_active (window, FALSE);
6233
6234   /* set the mnemonic-visible property to false */
6235   g_object_get (gtk_widget_get_settings (widget),
6236                 "gtk-auto-mnemonics", &auto_mnemonics, NULL);
6237   if (auto_mnemonics)
6238     gtk_window_set_mnemonics_visible (window, FALSE);
6239
6240   return FALSE;
6241 }
6242
6243 static void
6244 gtk_window_check_resize (GtkContainer *container)
6245 {
6246   /* If the window is not toplevel anymore than it's embedded somewhere,
6247    * so handle it like a normal window */
6248   if (!gtk_widget_is_toplevel (GTK_WIDGET (container)))
6249     GTK_CONTAINER_CLASS (gtk_window_parent_class)->check_resize (container);
6250   else if (gtk_widget_get_visible (GTK_WIDGET (container)))
6251     gtk_window_move_resize (GTK_WINDOW (container));
6252 }
6253
6254 static gboolean
6255 gtk_window_focus (GtkWidget        *widget,
6256                   GtkDirectionType  direction)
6257 {
6258   GtkWindowPrivate *priv;
6259   GtkBin *bin;
6260   GtkWindow *window;
6261   GtkContainer *container;
6262   GtkWidget *child;
6263   GtkWidget *old_focus_child;
6264   GtkWidget *parent;
6265
6266   if (!gtk_widget_is_toplevel (GTK_WIDGET (widget)))
6267     return GTK_WIDGET_CLASS (gtk_window_parent_class)->focus (widget, direction);
6268
6269   container = GTK_CONTAINER (widget);
6270   window = GTK_WINDOW (widget);
6271   priv = window->priv;
6272   bin = GTK_BIN (widget);
6273
6274   old_focus_child = gtk_container_get_focus_child (container);
6275   
6276   /* We need a special implementation here to deal properly with wrapping
6277    * around in the tab chain without the danger of going into an
6278    * infinite loop.
6279    */
6280   if (old_focus_child)
6281     {
6282       if (gtk_widget_child_focus (old_focus_child, direction))
6283         return TRUE;
6284     }
6285
6286   if (priv->focus_widget)
6287     {
6288       if (direction == GTK_DIR_LEFT ||
6289           direction == GTK_DIR_RIGHT ||
6290           direction == GTK_DIR_UP ||
6291           direction == GTK_DIR_DOWN)
6292         {
6293           return FALSE;
6294         }
6295       
6296       /* Wrapped off the end, clear the focus setting for the toplpevel */
6297       parent = gtk_widget_get_parent (priv->focus_widget);
6298       while (parent)
6299         {
6300           gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
6301           parent = gtk_widget_get_parent (parent);
6302         }
6303       
6304       gtk_window_set_focus (GTK_WINDOW (container), NULL);
6305     }
6306
6307   /* Now try to focus the first widget in the window */
6308   child = gtk_bin_get_child (bin);
6309   if (child)
6310     {
6311       if (gtk_widget_child_focus (child, direction))
6312         return TRUE;
6313     }
6314
6315   return FALSE;
6316 }
6317
6318 static void
6319 gtk_window_move_focus (GtkWidget       *widget,
6320                        GtkDirectionType dir)
6321 {
6322   if (!gtk_widget_is_toplevel (GTK_WIDGET (widget)))
6323     {
6324       GTK_WIDGET_CLASS (gtk_window_parent_class)->move_focus (widget, dir);
6325       return;
6326     }
6327
6328   gtk_widget_child_focus (widget, dir);
6329
6330   if (! gtk_container_get_focus_child (GTK_CONTAINER (widget)))
6331     gtk_window_set_focus (GTK_WINDOW (widget), NULL);
6332 }
6333
6334 static void
6335 gtk_window_real_set_focus (GtkWindow *window,
6336                            GtkWidget *focus)
6337 {
6338   GtkWindowPrivate *priv = window->priv;
6339   GtkWidget *old_focus = priv->focus_widget;
6340   gboolean had_default = FALSE;
6341   gboolean focus_had_default = FALSE;
6342   gboolean old_focus_had_default = FALSE;
6343
6344   if (old_focus)
6345     {
6346       g_object_ref (old_focus);
6347       g_object_freeze_notify (G_OBJECT (old_focus));
6348       old_focus_had_default = gtk_widget_has_default (old_focus);
6349     }
6350   if (focus)
6351     {
6352       g_object_ref (focus);
6353       g_object_freeze_notify (G_OBJECT (focus));
6354       focus_had_default = gtk_widget_has_default (focus);
6355     }
6356
6357   if (priv->default_widget)
6358     had_default = gtk_widget_has_default (priv->default_widget);
6359
6360   if (priv->focus_widget)
6361     {
6362       if (gtk_widget_get_receives_default (priv->focus_widget) &&
6363           (priv->focus_widget != priv->default_widget))
6364         {
6365           _gtk_widget_set_has_default (priv->focus_widget, FALSE);
6366           gtk_widget_queue_draw (priv->focus_widget);
6367
6368           if (priv->default_widget)
6369             _gtk_widget_set_has_default (priv->default_widget, TRUE);
6370         }
6371
6372       priv->focus_widget = NULL;
6373
6374       if (priv->has_focus)
6375         do_focus_change (old_focus, FALSE);
6376
6377       g_object_notify (G_OBJECT (old_focus), "is-focus");
6378     }
6379
6380   /* The above notifications may have set a new focus widget,
6381    * if so, we don't want to override it.
6382    */
6383   if (focus && !priv->focus_widget)
6384     {
6385       priv->focus_widget = focus;
6386
6387       if (gtk_widget_get_receives_default (priv->focus_widget) &&
6388           (priv->focus_widget != priv->default_widget))
6389         {
6390           if (gtk_widget_get_can_default (priv->focus_widget))
6391             _gtk_widget_set_has_default (priv->focus_widget, TRUE);
6392
6393           if (priv->default_widget)
6394             _gtk_widget_set_has_default (priv->default_widget, FALSE);
6395         }
6396
6397       if (priv->has_focus)
6398         do_focus_change (priv->focus_widget, TRUE);
6399
6400       g_object_notify (G_OBJECT (priv->focus_widget), "is-focus");
6401     }
6402
6403   /* If the default widget changed, a redraw will have been queued
6404    * on the old and new default widgets by gtk_window_set_default(), so
6405    * we only have to worry about the case where it didn't change.
6406    * We'll sometimes queue a draw twice on the new widget but that
6407    * is harmless.
6408    */
6409   if (priv->default_widget &&
6410       (had_default != gtk_widget_has_default (priv->default_widget)))
6411     gtk_widget_queue_draw (priv->default_widget);
6412   
6413   if (old_focus)
6414     {
6415       if (old_focus_had_default != gtk_widget_has_default (old_focus))
6416         gtk_widget_queue_draw (old_focus);
6417         
6418       g_object_thaw_notify (G_OBJECT (old_focus));
6419       g_object_unref (old_focus);
6420     }
6421   if (focus)
6422     {
6423       if (focus_had_default != gtk_widget_has_default (focus))
6424         gtk_widget_queue_draw (focus);
6425
6426       g_object_thaw_notify (G_OBJECT (focus));
6427       g_object_unref (focus);
6428     }
6429 }
6430
6431 /**
6432  * _gtk_window_unset_focus_and_default:
6433  * @window: a #GtkWindow
6434  * @widget: a widget inside of @window
6435  * 
6436  * Checks whether the focus and default widgets of @window are
6437  * @widget or a descendent of @widget, and if so, unset them.
6438  **/
6439 void
6440 _gtk_window_unset_focus_and_default (GtkWindow *window,
6441                                      GtkWidget *widget)
6442
6443 {
6444   GtkWindowPrivate *priv = window->priv;
6445   GtkWidget *child;
6446   GtkWidget *parent;
6447
6448   g_object_ref (window);
6449   g_object_ref (widget);
6450
6451   parent = gtk_widget_get_parent (widget);
6452   if (gtk_container_get_focus_child (GTK_CONTAINER (parent)) == widget)
6453     {
6454       child = priv->focus_widget;
6455       
6456       while (child && child != widget)
6457         child = gtk_widget_get_parent (child);
6458
6459       if (child == widget)
6460         gtk_window_set_focus (GTK_WINDOW (window), NULL);
6461     }
6462       
6463   child = priv->default_widget;
6464       
6465   while (child && child != widget)
6466     child = gtk_widget_get_parent (child);
6467
6468   if (child == widget)
6469     gtk_window_set_default (window, NULL);
6470   
6471   g_object_unref (widget);
6472   g_object_unref (window);
6473 }
6474
6475 /*********************************
6476  * Functions related to resizing *
6477  *********************************/
6478
6479 static void
6480 geometry_size_to_pixels (GdkGeometry *geometry,
6481                          guint        flags,
6482                          gint        *width,
6483                          gint        *height)
6484 {
6485   gint base_width = 0;
6486   gint base_height = 0;
6487   gint min_width = 0;
6488   gint min_height = 0;
6489   gint width_inc = 1;
6490   gint height_inc = 1;
6491
6492   if (flags & GDK_HINT_BASE_SIZE)
6493     {
6494       base_width = geometry->base_width;
6495       base_height = geometry->base_height;
6496     }
6497   if (flags & GDK_HINT_MIN_SIZE)
6498     {
6499       min_width = geometry->min_width;
6500       min_height = geometry->min_height;
6501     }
6502   if (flags & GDK_HINT_RESIZE_INC)
6503     {
6504       width_inc = geometry->width_inc;
6505       height_inc = geometry->height_inc;
6506     }
6507
6508   if (width)
6509     *width = MAX (*width * width_inc + base_width, min_width);
6510   if (height)
6511     *height = MAX (*height * height_inc + base_height, min_height);
6512 }
6513
6514 /* This function doesn't constrain to geometry hints */
6515 static void 
6516 gtk_window_compute_configure_request_size (GtkWindow   *window,
6517                                            GdkGeometry *geometry,
6518                                            guint        flags,
6519                                            gint        *width,
6520                                            gint        *height)
6521 {
6522   GtkWindowPrivate *priv = window->priv;
6523   GtkWindowGeometryInfo *info;
6524
6525   /* Preconditions:
6526    *  - we've done a size request
6527    */
6528   
6529   info = gtk_window_get_geometry_info (window, FALSE);
6530
6531   if (priv->need_default_size)
6532     {
6533       gtk_window_guess_default_size (window, width, height);
6534
6535       /* If window is empty so requests 0, default to random nonzero size */
6536        if (*width == 0 && *height == 0)
6537          {
6538            *width = 200;
6539            *height = 200;
6540          }
6541
6542        /* Override with default size */
6543
6544        if (info)
6545          {
6546            if (info->default_width > 0)
6547              *width = info->default_width;
6548            if (info->default_height > 0)
6549              *height = info->default_height;
6550
6551            if (info->default_is_geometry)
6552              geometry_size_to_pixels (geometry, flags,
6553                                       info->default_width > 0 ? width : NULL,
6554                                       info->default_height > 0 ? height : NULL);
6555          }
6556     }
6557   else
6558     {
6559       GtkAllocation allocation;
6560
6561       gtk_widget_get_allocation (GTK_WIDGET (window), &allocation);
6562
6563       /* Default to keeping current size */
6564       *width = allocation.width;
6565       *height = allocation.height;
6566     }
6567
6568   /* Override any size with gtk_window_resize() values */
6569   if (info)
6570     {
6571       if (info->resize_width > 0)
6572         *width = info->resize_width;
6573       if (info->resize_height > 0)
6574         *height = info->resize_height;
6575
6576       if (info->resize_is_geometry)
6577         geometry_size_to_pixels (geometry, flags,
6578                                  info->resize_width > 0 ? width : NULL,
6579                                  info->resize_height > 0 ? height : NULL);
6580     }
6581
6582   /* Don't ever request zero width or height, its not supported by
6583      gdk. The size allocation code will round it to 1 anyway but if
6584      we do it then the value returned from this function will is
6585      not comparable to the size allocation read from the GtkWindow. */
6586   *width = MAX (*width, 1);
6587   *height = MAX (*height, 1);
6588 }
6589
6590 static GtkWindowPosition
6591 get_effective_position (GtkWindow *window)
6592 {
6593   GtkWindowPrivate *priv = window->priv;
6594   GtkWindowPosition pos = priv->position;
6595
6596   if (pos == GTK_WIN_POS_CENTER_ON_PARENT &&
6597       (priv->transient_parent == NULL ||
6598        !gtk_widget_get_mapped (GTK_WIDGET (priv->transient_parent))))
6599     pos = GTK_WIN_POS_NONE;
6600
6601   return pos;
6602 }
6603
6604 static int
6605 get_center_monitor_of_window (GtkWindow *window)
6606 {
6607   /* We could try to sort out the relative positions of the monitors and
6608    * stuff, or we could just be losers and assume you have a row
6609    * or column of monitors.
6610    */
6611   return gdk_screen_get_n_monitors (gtk_window_check_screen (window)) / 2;
6612 }
6613
6614 static int
6615 get_monitor_containing_pointer (GtkWindow *window)
6616 {
6617   gint px, py;
6618   gint monitor_num;
6619   GdkScreen *window_screen;
6620   GdkScreen *pointer_screen;
6621   GdkDisplay *display;
6622   GdkDeviceManager *device_manager;
6623   GdkDevice *pointer;
6624
6625   window_screen = gtk_window_check_screen (window);
6626   display = gdk_screen_get_display (window_screen);
6627   device_manager = gdk_display_get_device_manager (display);
6628   pointer = gdk_device_manager_get_client_pointer (device_manager);
6629
6630   gdk_device_get_position (pointer,
6631                            &pointer_screen,
6632                            &px, &py);
6633
6634   if (pointer_screen == window_screen)
6635     monitor_num = gdk_screen_get_monitor_at_point (pointer_screen, px, py);
6636   else
6637     monitor_num = -1;
6638
6639   return monitor_num;
6640 }
6641
6642 static void
6643 center_window_on_monitor (GtkWindow *window,
6644                           gint       w,
6645                           gint       h,
6646                           gint      *x,
6647                           gint      *y)
6648 {
6649   GdkRectangle monitor;
6650   int monitor_num;
6651
6652   monitor_num = get_monitor_containing_pointer (window);
6653
6654   if (monitor_num == -1)
6655     monitor_num = get_center_monitor_of_window (window);
6656
6657   gdk_screen_get_monitor_workarea (gtk_window_check_screen (window),
6658                                     monitor_num, &monitor);
6659
6660   *x = (monitor.width - w) / 2 + monitor.x;
6661   *y = (monitor.height - h) / 2 + monitor.y;
6662
6663   /* Be sure we aren't off the monitor, ignoring _NET_WM_STRUT
6664    * and WM decorations.
6665    */
6666   if (*x < monitor.x)
6667     *x = monitor.x;
6668   if (*y < monitor.y)
6669     *y = monitor.y;
6670 }
6671
6672 static void
6673 clamp (gint *base,
6674        gint  extent,
6675        gint  clamp_base,
6676        gint  clamp_extent)
6677 {
6678   if (extent > clamp_extent)
6679     /* Center */
6680     *base = clamp_base + clamp_extent/2 - extent/2;
6681   else if (*base < clamp_base)
6682     *base = clamp_base;
6683   else if (*base + extent > clamp_base + clamp_extent)
6684     *base = clamp_base + clamp_extent - extent;
6685 }
6686
6687 static void
6688 clamp_window_to_rectangle (gint               *x,
6689                            gint               *y,
6690                            gint                w,
6691                            gint                h,
6692                            const GdkRectangle *rect)
6693 {
6694 #ifdef DEBUGGING_OUTPUT
6695   g_print ("%s: %+d%+d %dx%d: %+d%+d: %dx%d", G_STRFUNC, rect->x, rect->y, rect->width, rect->height, *x, *y, w, h);
6696 #endif
6697
6698   /* If it is too large, center it. If it fits on the monitor but is
6699    * partially outside, move it to the closest edge. Do this
6700    * separately in x and y directions.
6701    */
6702   clamp (x, w, rect->x, rect->width);
6703   clamp (y, h, rect->y, rect->height);
6704 #ifdef DEBUGGING_OUTPUT
6705   g_print (" ==> %+d%+d: %dx%d\n", *x, *y, w, h);
6706 #endif
6707 }
6708
6709
6710 static void
6711 gtk_window_compute_configure_request (GtkWindow    *window,
6712                                       GdkRectangle *request,
6713                                       GdkGeometry  *geometry,
6714                                       guint        *flags)
6715 {
6716   GtkWindowPrivate *priv = window->priv;
6717   GdkGeometry new_geometry;
6718   guint new_flags;
6719   int w, h;
6720   GtkWindowPosition pos;
6721   GtkWidget *parent_widget;
6722   GtkWindowGeometryInfo *info;
6723   GdkScreen *screen;
6724   int x, y;
6725
6726   screen = gtk_window_check_screen (window);
6727
6728   gtk_window_compute_hints (window, &new_geometry, &new_flags);
6729   gtk_window_compute_configure_request_size (window,
6730                                              &new_geometry, new_flags,
6731                                              &w, &h);
6732
6733   gtk_window_constrain_size (window,
6734                              &new_geometry, new_flags,
6735                              w, h,
6736                              &w, &h);
6737
6738   parent_widget = (GtkWidget*) priv->transient_parent;
6739
6740   pos = get_effective_position (window);
6741   info = gtk_window_get_geometry_info (window, FALSE);
6742
6743   /* by default, don't change position requested */
6744   if (info)
6745     {
6746       x = info->last.configure_request.x;
6747       y = info->last.configure_request.y;
6748     }
6749   else
6750     {
6751       x = 0;
6752       y = 0;
6753     }
6754
6755
6756   if (priv->need_default_position)
6757     {
6758
6759       /* FIXME this all interrelates with window gravity.
6760        * For most of them I think we want to set GRAVITY_CENTER.
6761        *
6762        * Not sure how to go about that.
6763        */
6764       switch (pos)
6765         {
6766           /* here we are only handling CENTER_ALWAYS
6767            * as it relates to default positioning,
6768            * where it's equivalent to simply CENTER
6769            */
6770         case GTK_WIN_POS_CENTER_ALWAYS:
6771         case GTK_WIN_POS_CENTER:
6772           center_window_on_monitor (window, w, h, &x, &y);
6773           break;
6774
6775         case GTK_WIN_POS_CENTER_ON_PARENT:
6776           {
6777             GtkAllocation allocation;
6778             GdkWindow *gdk_window;
6779             gint monitor_num;
6780             GdkRectangle monitor;
6781             gint ox, oy;
6782
6783             g_assert (gtk_widget_get_mapped (parent_widget)); /* established earlier */
6784
6785             gdk_window = gtk_widget_get_window (parent_widget);
6786
6787             if (gdk_window != NULL)
6788               monitor_num = gdk_screen_get_monitor_at_window (screen,
6789                                                               gdk_window);
6790             else
6791               monitor_num = -1;
6792
6793             gdk_window_get_origin (gdk_window,
6794                                    &ox, &oy);
6795
6796             gtk_widget_get_allocation (parent_widget, &allocation);
6797             x = ox + (allocation.width - w) / 2;
6798             y = oy + (allocation.height - h) / 2;
6799
6800             /* Clamp onto current monitor, ignoring _NET_WM_STRUT and
6801              * WM decorations. If parent wasn't on a monitor, just
6802              * give up.
6803              */
6804             if (monitor_num >= 0)
6805               {
6806                 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
6807                 clamp_window_to_rectangle (&x, &y, w, h, &monitor);
6808               }
6809           }
6810           break;
6811
6812         case GTK_WIN_POS_MOUSE:
6813           {
6814             gint screen_width = gdk_screen_get_width (screen);
6815             gint screen_height = gdk_screen_get_height (screen);
6816             gint monitor_num;
6817             GdkRectangle monitor;
6818             GdkDisplay *display;
6819             GdkDeviceManager *device_manager;
6820             GdkDevice *pointer;
6821             GdkScreen *pointer_screen;
6822             gint px, py;
6823
6824             display = gdk_screen_get_display (screen);
6825             device_manager = gdk_display_get_device_manager (display);
6826             pointer = gdk_device_manager_get_client_pointer (device_manager);
6827
6828             gdk_device_get_position (pointer,
6829                                      &pointer_screen,
6830                                      &px, &py);
6831
6832             if (pointer_screen == screen)
6833               monitor_num = gdk_screen_get_monitor_at_point (screen, px, py);
6834             else
6835               monitor_num = -1;
6836
6837             x = px - w / 2;
6838             y = py - h / 2;
6839             x = CLAMP (x, 0, screen_width - w);
6840             y = CLAMP (y, 0, screen_height - h);
6841
6842             /* Clamp onto current monitor, ignoring _NET_WM_STRUT and
6843              * WM decorations. Don't try to figure out what's going
6844              * on if the mouse wasn't inside a monitor.
6845              */
6846             if (monitor_num >= 0)
6847               {
6848                 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
6849                 clamp_window_to_rectangle (&x, &y, w, h, &monitor);
6850               }
6851           }
6852           break;
6853
6854         default:
6855           break;
6856         }
6857     } /* if (priv->need_default_position) */
6858
6859   if (priv->need_default_position && info &&
6860       info->initial_pos_set)
6861     {
6862       x = info->initial_x;
6863       y = info->initial_y;
6864       gtk_window_constrain_position (window, w, h, &x, &y);
6865     }
6866
6867   request->x = x;
6868   request->y = y;
6869   request->width = w;
6870   request->height = h;
6871
6872   if (geometry)
6873     *geometry = new_geometry;
6874   if (flags)
6875     *flags = new_flags;
6876 }
6877
6878 static void
6879 gtk_window_constrain_position (GtkWindow    *window,
6880                                gint          new_width,
6881                                gint          new_height,
6882                                gint         *x,
6883                                gint         *y)
6884 {
6885   GtkWindowPrivate *priv = window->priv;
6886
6887   /* See long comments in gtk_window_move_resize()
6888    * on when it's safe to call this function.
6889    */
6890   if (priv->position == GTK_WIN_POS_CENTER_ALWAYS)
6891     {
6892       gint center_x, center_y;
6893
6894       center_window_on_monitor (window, new_width, new_height, &center_x, &center_y);
6895       
6896       *x = center_x;
6897       *y = center_y;
6898     }
6899 }
6900
6901 static void
6902 gtk_window_move_resize (GtkWindow *window)
6903 {
6904   /* Overview:
6905    *
6906    * First we determine whether any information has changed that would
6907    * cause us to revise our last configure request.  If we would send
6908    * a different configure request from last time, then
6909    * configure_request_size_changed = TRUE or
6910    * configure_request_pos_changed = TRUE. configure_request_size_changed
6911    * may be true due to new hints, a gtk_window_resize(), or whatever.
6912    * configure_request_pos_changed may be true due to gtk_window_set_position()
6913    * or gtk_window_move().
6914    *
6915    * If the configure request has changed, we send off a new one.  To
6916    * ensure GTK+ invariants are maintained (resize queue does what it
6917    * should), we go ahead and size_allocate the requested size in this
6918    * function.
6919    *
6920    * If the configure request has not changed, we don't ever resend
6921    * it, because it could mean fighting the user or window manager.
6922    *
6923    * 
6924    *   To prepare the configure request, we come up with a base size/pos:
6925    *      - the one from gtk_window_move()/gtk_window_resize()
6926    *      - else default_width, default_height if we haven't ever
6927    *        been mapped
6928    *      - else the size request if we haven't ever been mapped,
6929    *        as a substitute default size
6930    *      - else the current size of the window, as received from
6931    *        configure notifies (i.e. the current allocation)
6932    *
6933    *   If GTK_WIN_POS_CENTER_ALWAYS is active, we constrain
6934    *   the position request to be centered.
6935    */
6936   GtkWindowPrivate *priv = window->priv;
6937   GtkAllocation allocation;
6938   GtkWidget *widget;
6939   GtkContainer *container;
6940   GtkWindowGeometryInfo *info;
6941   GdkGeometry new_geometry;
6942   GdkWindow *gdk_window;
6943   guint new_flags;
6944   GdkRectangle new_request;
6945   gboolean configure_request_size_changed;
6946   gboolean configure_request_pos_changed;
6947   gboolean hints_changed; /* do we need to send these again */
6948   GtkWindowLastGeometryInfo saved_last_info;
6949   
6950   widget = GTK_WIDGET (window);
6951
6952   gdk_window = gtk_widget_get_window (widget);
6953   container = GTK_CONTAINER (widget);
6954   info = gtk_window_get_geometry_info (window, TRUE);
6955   
6956   configure_request_size_changed = FALSE;
6957   configure_request_pos_changed = FALSE;
6958   
6959   gtk_window_compute_configure_request (window, &new_request,
6960                                         &new_geometry, &new_flags);  
6961   
6962   /* This check implies the invariant that we never set info->last
6963    * without setting the hints and sending off a configure request.
6964    *
6965    * If we change info->last without sending the request, we may
6966    * miss a request.
6967    */
6968   if (info->last.configure_request.x != new_request.x ||
6969       info->last.configure_request.y != new_request.y)
6970     configure_request_pos_changed = TRUE;
6971
6972   if ((info->last.configure_request.width != new_request.width ||
6973        info->last.configure_request.height != new_request.height))
6974     configure_request_size_changed = TRUE;
6975   
6976   hints_changed = FALSE;
6977   
6978   if (!gtk_window_compare_hints (&info->last.geometry, info->last.flags,
6979                                  &new_geometry, new_flags))
6980     {
6981       hints_changed = TRUE;
6982     }
6983   
6984   /* Position Constraints
6985    * ====================
6986    * 
6987    * POS_CENTER_ALWAYS is conceptually a constraint rather than
6988    * a default. The other POS_ values are used only when the
6989    * window is shown, not after that.
6990    * 
6991    * However, we can't implement a position constraint as
6992    * "anytime the window size changes, center the window"
6993    * because this may well end up fighting the WM or user.  In
6994    * fact it gets in an infinite loop with at least one WM.
6995    *
6996    * Basically, applications are in no way in a position to
6997    * constrain the position of a window, with one exception:
6998    * override redirect windows. (Really the intended purpose
6999    * of CENTER_ALWAYS anyhow, I would think.)
7000    *
7001    * So the way we implement this "constraint" is to say that when WE
7002    * cause a move or resize, i.e. we make a configure request changing
7003    * window size, we recompute the CENTER_ALWAYS position to reflect
7004    * the new window size, and include it in our request.  Also, if we
7005    * just turned on CENTER_ALWAYS we snap to center with a new
7006    * request.  Otherwise, if we are just NOTIFIED of a move or resize
7007    * done by someone else e.g. the window manager, we do NOT send a
7008    * new configure request.
7009    *
7010    * For override redirect windows, this works fine; all window
7011    * sizes are from our configure requests. For managed windows,
7012    * it is at least semi-sane, though who knows what the
7013    * app author is thinking.
7014    */
7015
7016   /* This condition should be kept in sync with the condition later on
7017    * that determines whether we send a configure request.  i.e. we
7018    * should do this position constraining anytime we were going to
7019    * send a configure request anyhow, plus when constraints have
7020    * changed.
7021    */
7022   if (configure_request_pos_changed ||
7023       configure_request_size_changed ||
7024       hints_changed ||
7025       info->position_constraints_changed)
7026     {
7027       /* We request the constrained position if:
7028        *  - we were changing position, and need to clamp
7029        *    the change to the constraint
7030        *  - we're changing the size anyway
7031        *  - set_position() was called to toggle CENTER_ALWAYS on
7032        */
7033
7034       gtk_window_constrain_position (window,
7035                                      new_request.width,
7036                                      new_request.height,
7037                                      &new_request.x,
7038                                      &new_request.y);
7039       
7040       /* Update whether we need to request a move */
7041       if (info->last.configure_request.x != new_request.x ||
7042           info->last.configure_request.y != new_request.y)
7043         configure_request_pos_changed = TRUE;
7044       else
7045         configure_request_pos_changed = FALSE;
7046     }
7047
7048 #if 0
7049   if (priv->type == GTK_WINDOW_TOPLEVEL)
7050     {
7051       int notify_x, notify_y;
7052
7053       /* this is the position from the last configure notify */
7054       gdk_window_get_position (widget->window, &notify_x, &notify_y);
7055     
7056       g_message ("--- %s ---\n"
7057                  "last  : %d,%d\t%d x %d\n"
7058                  "this  : %d,%d\t%d x %d\n"
7059                  "alloc : %d,%d\t%d x %d\n"
7060                  "req   :      \t%d x %d\n"
7061                  "resize:      \t%d x %d\n" 
7062                  "size_changed: %d pos_changed: %d hints_changed: %d\n"
7063                  "configure_notify_received: %d\n"
7064                  "configure_request_count: %d\n"
7065                  "position_constraints_changed: %d\n",
7066                  priv->title ? priv->title : "(no title)",
7067                  info->last.configure_request.x,
7068                  info->last.configure_request.y,
7069                  info->last.configure_request.width,
7070                  info->last.configure_request.height,
7071                  new_request.x,
7072                  new_request.y,
7073                  new_request.width,
7074                  new_request.height,
7075                  notify_x, notify_y,
7076                  widget->allocation.width,
7077                  widget->allocation.height,
7078                  widget->requisition.width,
7079                  widget->requisition.height,
7080                  info->resize_width,
7081                  info->resize_height,
7082                  configure_request_pos_changed,
7083                  configure_request_size_changed,
7084                  hints_changed,
7085                  priv->configure_notify_received,
7086                  priv->configure_request_count,
7087                  info->position_constraints_changed);
7088     }
7089 #endif
7090   
7091   saved_last_info = info->last;
7092   info->last.geometry = new_geometry;
7093   info->last.flags = new_flags;
7094   info->last.configure_request = new_request;
7095   
7096   /* need to set PPosition so the WM will look at our position,
7097    * but we don't want to count PPosition coming and going as a hints
7098    * change for future iterations. So we saved info->last prior to
7099    * this.
7100    */
7101   
7102   /* Also, if the initial position was explicitly set, then we always
7103    * toggle on PPosition. This makes gtk_window_move(window, 0, 0)
7104    * work.
7105    */
7106
7107   /* Also, we toggle on PPosition if GTK_WIN_POS_ is in use and
7108    * this is an initial map
7109    */
7110   
7111   if ((configure_request_pos_changed ||
7112        info->initial_pos_set ||
7113        (priv->need_default_position &&
7114         get_effective_position (window) != GTK_WIN_POS_NONE)) &&
7115       (new_flags & GDK_HINT_POS) == 0)
7116     {
7117       new_flags |= GDK_HINT_POS;
7118       hints_changed = TRUE;
7119     }
7120   
7121   /* Set hints if necessary
7122    */
7123   if (hints_changed)
7124     gdk_window_set_geometry_hints (gdk_window,
7125                                    &new_geometry,
7126                                    new_flags);
7127
7128   allocation.x = 0;
7129   allocation.y = 0;
7130   allocation.width = gdk_window_get_width (gdk_window);
7131   allocation.height = gdk_window_get_height (gdk_window);
7132
7133   /* handle resizing/moving and widget tree allocation
7134    */
7135   if (priv->configure_notify_received)
7136     { 
7137       /* If we have received a configure event since
7138        * the last time in this function, we need to
7139        * accept our new size and size_allocate child widgets.
7140        * (see gtk_window_configure_event() for more details).
7141        *
7142        * 1 or more configure notifies may have been received.
7143        * Also, configure_notify_received will only be TRUE
7144        * if all expected configure notifies have been received
7145        * (one per configure request), as an optimization.
7146        *
7147        */
7148       priv->configure_notify_received = FALSE;
7149
7150       /* gtk_window_configure_event() filled in widget->allocation */
7151       gtk_widget_size_allocate (widget, &allocation);
7152
7153       set_grip_position (window);
7154       update_grip_visibility (window);
7155
7156       gdk_window_process_updates (gdk_window, TRUE);
7157
7158       gdk_window_configure_finished (gdk_window);
7159
7160       /* If the configure request changed, it means that
7161        * we either:
7162        *   1) coincidentally changed hints or widget properties
7163        *      impacting the configure request before getting
7164        *      a configure notify, or
7165        *   2) some broken widget is changing its size request
7166        *      during size allocation, resulting in
7167        *      a false appearance of changed configure request.
7168        *
7169        * For 1), we could just go ahead and ask for the
7170        * new size right now, but doing that for 2)
7171        * might well be fighting the user (and can even
7172        * trigger a loop). Since we really don't want to
7173        * do that, we requeue a resize in hopes that
7174        * by the time it gets handled, the child has seen
7175        * the light and is willing to go along with the
7176        * new size. (this happens for the zvt widget, since
7177        * the size_allocate() above will have stored the
7178        * requisition corresponding to the new size in the
7179        * zvt widget)
7180        *
7181        * This doesn't buy us anything for 1), but it shouldn't
7182        * hurt us too badly, since it is what would have
7183        * happened if we had gotten the configure event before
7184        * the new size had been set.
7185        */
7186
7187       if (configure_request_size_changed ||
7188           configure_request_pos_changed)
7189         {
7190           /* Don't change the recorded last info after all, because we
7191            * haven't actually updated to the new info yet - we decided
7192            * to postpone our configure request until later.
7193            */
7194           info->last = saved_last_info;
7195           
7196           gtk_widget_queue_resize_no_redraw (widget); /* migth recurse for GTK_RESIZE_IMMEDIATE */
7197         }
7198
7199       return;                   /* Bail out, we didn't really process the move/resize */
7200     }
7201   else if ((configure_request_size_changed || hints_changed) &&
7202            (allocation.width != new_request.width || allocation.height != new_request.height))
7203
7204     {
7205       /* We are in one of the following situations:
7206        * A. configure_request_size_changed
7207        *    our requisition has changed and we need a different window size,
7208        *    so we request it from the window manager.
7209        * B. !configure_request_size_changed && hints_changed
7210        *    the window manager rejects our size, but we have just changed the
7211        *    window manager hints, so there's a chance our request will
7212        *    be honoured this time, so we try again.
7213        *
7214        * However, if the new requisition is the same as the current allocation,
7215        * we don't request it again, since we won't get a ConfigureNotify back from
7216        * the window manager unless it decides to change our requisition. If
7217        * we don't get the ConfigureNotify back, the resize queue will never be run.
7218        */
7219
7220       /* Now send the configure request */
7221       if (configure_request_pos_changed)
7222         {
7223           gdk_window_move_resize (gdk_window,
7224                                   new_request.x, new_request.y,
7225                                   new_request.width, new_request.height);
7226         }
7227       else  /* only size changed */
7228         {
7229           gdk_window_resize (gdk_window,
7230                              new_request.width, new_request.height);
7231         }
7232
7233       if (priv->type == GTK_WINDOW_POPUP)
7234         {
7235           GtkAllocation allocation;
7236
7237           /* Directly size allocate for override redirect (popup) windows. */
7238           allocation.x = 0;
7239           allocation.y = 0;
7240           allocation.width = new_request.width;
7241           allocation.height = new_request.height;
7242
7243           gtk_widget_size_allocate (widget, &allocation);
7244
7245           gdk_window_process_updates (gdk_window, TRUE);
7246
7247           if (gtk_container_get_resize_mode (container) == GTK_RESIZE_QUEUE)
7248             gtk_widget_queue_draw (widget);
7249         }
7250       else
7251         {
7252           /* Increment the number of have-not-yet-received-notify requests */
7253           priv->configure_request_count += 1;
7254           gdk_window_freeze_toplevel_updates_libgtk_only (gdk_window);
7255
7256           /* for GTK_RESIZE_QUEUE toplevels, we are now awaiting a new
7257            * configure event in response to our resizing request.
7258            * the configure event will cause a new resize with
7259            * ->configure_notify_received=TRUE.
7260            * until then, we want to
7261            * - discard expose events
7262            * - coalesce resizes for our children
7263            * - defer any window resizes until the configure event arrived
7264            * to achieve this, we queue a resize for the window, but remove its
7265            * resizing handler, so resizing will not be handled from the next
7266            * idle handler but when the configure event arrives.
7267            *
7268            * FIXME: we should also dequeue the pending redraws here, since
7269            * we handle those ourselves upon ->configure_notify_received==TRUE.
7270            */
7271           if (gtk_container_get_resize_mode (container) == GTK_RESIZE_QUEUE)
7272             {
7273               gtk_widget_queue_resize_no_redraw (widget);
7274               _gtk_container_dequeue_resize_handler (container);
7275             }
7276         }
7277     }
7278   else
7279     {
7280       /* Handle any position changes.
7281        */
7282       if (configure_request_pos_changed)
7283         {
7284           gdk_window_move (gdk_window,
7285                            new_request.x, new_request.y);
7286         }
7287
7288       /* And run the resize queue.
7289        */
7290       gtk_container_resize_children (container);
7291     }
7292   
7293   /* We have now processed a move/resize since the last position
7294    * constraint change, setting of the initial position, or resize.
7295    * (Not resetting these flags here can lead to infinite loops for
7296    * GTK_RESIZE_IMMEDIATE containers)
7297    */
7298   info->position_constraints_changed = FALSE;
7299   info->initial_pos_set = FALSE;
7300   info->resize_width = -1;
7301   info->resize_height = -1;
7302 }
7303
7304 /* Compare two sets of Geometry hints for equality.
7305  */
7306 static gboolean
7307 gtk_window_compare_hints (GdkGeometry *geometry_a,
7308                           guint        flags_a,
7309                           GdkGeometry *geometry_b,
7310                           guint        flags_b)
7311 {
7312   if (flags_a != flags_b)
7313     return FALSE;
7314   
7315   if ((flags_a & GDK_HINT_MIN_SIZE) &&
7316       (geometry_a->min_width != geometry_b->min_width ||
7317        geometry_a->min_height != geometry_b->min_height))
7318     return FALSE;
7319
7320   if ((flags_a & GDK_HINT_MAX_SIZE) &&
7321       (geometry_a->max_width != geometry_b->max_width ||
7322        geometry_a->max_height != geometry_b->max_height))
7323     return FALSE;
7324
7325   if ((flags_a & GDK_HINT_BASE_SIZE) &&
7326       (geometry_a->base_width != geometry_b->base_width ||
7327        geometry_a->base_height != geometry_b->base_height))
7328     return FALSE;
7329
7330   if ((flags_a & GDK_HINT_ASPECT) &&
7331       (geometry_a->min_aspect != geometry_b->min_aspect ||
7332        geometry_a->max_aspect != geometry_b->max_aspect))
7333     return FALSE;
7334
7335   if ((flags_a & GDK_HINT_RESIZE_INC) &&
7336       (geometry_a->width_inc != geometry_b->width_inc ||
7337        geometry_a->height_inc != geometry_b->height_inc))
7338     return FALSE;
7339
7340   if ((flags_a & GDK_HINT_WIN_GRAVITY) &&
7341       geometry_a->win_gravity != geometry_b->win_gravity)
7342     return FALSE;
7343
7344   return TRUE;
7345 }
7346
7347 void
7348 _gtk_window_constrain_size (GtkWindow   *window,
7349                             gint         width,
7350                             gint         height,
7351                             gint        *new_width,
7352                             gint        *new_height)
7353 {
7354   GtkWindowPrivate *priv;
7355   GtkWindowGeometryInfo *info;
7356
7357   g_return_if_fail (GTK_IS_WINDOW (window));
7358
7359   priv = window->priv;
7360
7361   info = priv->geometry_info;
7362   if (info)
7363     {
7364       GdkWindowHints flags = info->last.flags;
7365       GdkGeometry *geometry = &info->last.geometry;
7366       
7367       gtk_window_constrain_size (window,
7368                                  geometry,
7369                                  flags,
7370                                  width,
7371                                  height,
7372                                  new_width,
7373                                  new_height);
7374     }
7375 }
7376
7377 static void 
7378 gtk_window_constrain_size (GtkWindow   *window,
7379                            GdkGeometry *geometry,
7380                            guint        flags,
7381                            gint         width,
7382                            gint         height,
7383                            gint        *new_width,
7384                            gint        *new_height)
7385 {
7386   gdk_window_constrain_size (geometry, flags, width, height,
7387                              new_width, new_height);
7388 }
7389
7390 /* Compute the set of geometry hints and flags for a window
7391  * based on the application set geometry, and requisition
7392  * of the window. gtk_widget_get_preferred_size() must have been
7393  * called first.
7394  */
7395 static void
7396 gtk_window_compute_hints (GtkWindow   *window,
7397                           GdkGeometry *new_geometry,
7398                           guint       *new_flags)
7399 {
7400   GtkWindowPrivate *priv = window->priv;
7401   GtkWidget *widget;
7402   gint extra_width = 0;
7403   gint extra_height = 0;
7404   GtkWindowGeometryInfo *geometry_info;
7405   GtkRequisition requisition;
7406
7407   widget = GTK_WIDGET (window);
7408
7409   gtk_widget_get_preferred_size (widget, &requisition, NULL);
7410   geometry_info = gtk_window_get_geometry_info (GTK_WINDOW (widget), FALSE);
7411
7412   if (geometry_info)
7413     {
7414       *new_flags = geometry_info->mask;
7415       *new_geometry = geometry_info->geometry;
7416     }
7417   else
7418     {
7419       *new_flags = 0;
7420     }
7421   
7422   if (geometry_info && geometry_info->widget)
7423     {
7424       /* If the geometry widget is set, then the hints really apply to that
7425        * widget. This is pretty much meaningless unless the window layout
7426        * is such that the rest of the window adds fixed size borders to
7427        * the geometry widget. Our job is to figure the size of the borders;
7428        * We do that by asking how big the toplevel would be if the
7429        * geometry widget was *really big*.
7430        *
7431        *  +----------+
7432        *  |AAAAAAAAA | At small sizes, the minimum sizes of widgets
7433        *  |GGGGG    B| in the border can confuse things
7434        *  |GGGGG    B|
7435        *  |         B|
7436        *  +----------+
7437        *
7438        *  +-----------+
7439        *  |AAAAAAAAA  | When the geometry widget is large, things are
7440        *  |GGGGGGGGGGB| clearer.
7441        *  |GGGGGGGGGGB|
7442        *  |GGGGGGGGGG |
7443        *  +-----------+
7444        */
7445 #define TEMPORARY_SIZE 10000 /* 10,000 pixels should be bigger than real widget sizes */
7446       GtkRequisition requisition;
7447       int current_width, current_height;
7448
7449       _gtk_widget_override_size_request (geometry_info->widget,
7450                                          TEMPORARY_SIZE, TEMPORARY_SIZE,
7451                                          &current_width, &current_height);
7452       gtk_widget_get_preferred_size (widget,
7453                                      &requisition, NULL);
7454       _gtk_widget_restore_size_request (geometry_info->widget,
7455                                         current_width, current_height);
7456
7457       extra_width = requisition.width - TEMPORARY_SIZE;
7458       extra_height = requisition.height - TEMPORARY_SIZE;
7459
7460       if (extra_width < 0 || extra_height < 0)
7461         {
7462           g_warning("Toplevel size doesn't seem to directly depend on the "
7463                     "size of the geometry widget from gtk_window_set_geometry_hints(). "
7464                     "The geometry widget might not be in the window, or it might not "
7465                     "be packed into the window appropriately");
7466           extra_width = MAX(extra_width, 0);
7467           extra_height = MAX(extra_height, 0);
7468         }
7469 #undef TEMPORARY_SIZE
7470     }
7471
7472   /* We don't want to set GDK_HINT_POS in here, we just set it
7473    * in gtk_window_move_resize() when we want the position
7474    * honored.
7475    */
7476   
7477   if (*new_flags & GDK_HINT_BASE_SIZE)
7478     {
7479       new_geometry->base_width += extra_width;
7480       new_geometry->base_height += extra_height;
7481     }
7482   else
7483     {
7484       /* For simplicity, we always set the base hint, even when we
7485        * don't expect it to have any visible effect.
7486        * (Note: geometry_size_to_pixels() depends on this.)
7487        */
7488       *new_flags |= GDK_HINT_BASE_SIZE;
7489
7490       new_geometry->base_width = extra_width;
7491       new_geometry->base_height = extra_height;
7492
7493       /* As for X, if BASE_SIZE is not set but MIN_SIZE is set, then the
7494        * base size is the minimum size */
7495       if (*new_flags & GDK_HINT_MIN_SIZE)
7496         {
7497           if (new_geometry->min_width > 0)
7498             new_geometry->base_width += new_geometry->min_width;
7499           if (new_geometry->min_height > 0)
7500             new_geometry->base_height += new_geometry->min_height;
7501         }
7502     }
7503
7504   /* Please use a good size for unresizable widgets, not the minimum one. */
7505   if (!priv->resizable)
7506     gtk_window_guess_default_size (window, &requisition.width, &requisition.height);
7507
7508   if (*new_flags & GDK_HINT_MIN_SIZE)
7509     {
7510       if (new_geometry->min_width < 0)
7511         new_geometry->min_width = requisition.width;
7512       else
7513         new_geometry->min_width = MAX (requisition.width, new_geometry->min_width + extra_width);
7514
7515       if (new_geometry->min_height < 0)
7516         new_geometry->min_height = requisition.height;
7517       else
7518         new_geometry->min_height = MAX (requisition.height, new_geometry->min_height + extra_height);
7519     }
7520   else
7521     {
7522       *new_flags |= GDK_HINT_MIN_SIZE;
7523       
7524       new_geometry->min_width = requisition.width;
7525       new_geometry->min_height = requisition.height;
7526     }
7527   
7528   if (*new_flags & GDK_HINT_MAX_SIZE)
7529     {
7530       if (new_geometry->max_width < 0)
7531         new_geometry->max_width = requisition.width;
7532       else
7533         new_geometry->max_width += extra_width;
7534
7535       if (new_geometry->max_height < 0)
7536         new_geometry->max_height = requisition.height;
7537       else
7538         new_geometry->max_height += extra_height;
7539     }
7540   else if (!priv->resizable)
7541     {
7542       *new_flags |= GDK_HINT_MAX_SIZE;
7543       
7544       new_geometry->max_width = requisition.width;
7545       new_geometry->max_height = requisition.height;
7546     }
7547
7548   *new_flags |= GDK_HINT_WIN_GRAVITY;
7549   new_geometry->win_gravity = priv->gravity;
7550 }
7551
7552 /***********************
7553  * Redrawing functions *
7554  ***********************/
7555
7556 static gboolean
7557 gtk_window_draw (GtkWidget *widget,
7558                  cairo_t   *cr)
7559 {
7560   GtkWindowPrivate *priv = GTK_WINDOW (widget)->priv;
7561   GtkStyleContext *context;
7562   gboolean ret = FALSE;
7563
7564   context = gtk_widget_get_style_context (widget);
7565
7566   if (!gtk_widget_get_app_paintable (widget) &&
7567       gtk_cairo_should_draw_window (cr, gtk_widget_get_window (widget)))
7568     {
7569       gtk_render_background (context, cr, 0, 0,
7570                              gtk_widget_get_allocated_width (widget),
7571                              gtk_widget_get_allocated_height (widget));
7572     }
7573
7574   if (GTK_WIDGET_CLASS (gtk_window_parent_class)->draw)
7575     ret = GTK_WIDGET_CLASS (gtk_window_parent_class)->draw (widget, cr);
7576
7577   if (priv->grip_window &&
7578       gtk_cairo_should_draw_window (cr, priv->grip_window))
7579     {
7580       GdkRectangle rect;
7581
7582       gtk_style_context_save (context);
7583       cairo_save (cr);
7584
7585       gtk_cairo_transform_to_window (cr, widget, priv->grip_window);
7586       gtk_window_get_resize_grip_area (GTK_WINDOW (widget), &rect);
7587
7588       gtk_style_context_remove_class (context, GTK_STYLE_CLASS_BACKGROUND);
7589       gtk_style_context_add_class (context, GTK_STYLE_CLASS_GRIP);
7590       gtk_style_context_set_junction_sides (context, get_grip_junction (widget));
7591       gtk_render_handle (context, cr, 0, 0, rect.width, rect.height);
7592
7593       cairo_restore (cr);
7594       gtk_style_context_restore (context);
7595     }
7596
7597   return ret;
7598 }
7599
7600 /**
7601  * gtk_window_present:
7602  * @window: a #GtkWindow
7603  *
7604  * Presents a window to the user. This may mean raising the window
7605  * in the stacking order, deiconifying it, moving it to the current
7606  * desktop, and/or giving it the keyboard focus, possibly dependent
7607  * on the user's platform, window manager, and preferences.
7608  *
7609  * If @window is hidden, this function calls gtk_widget_show()
7610  * as well.
7611  * 
7612  * This function should be used when the user tries to open a window
7613  * that's already open. Say for example the preferences dialog is
7614  * currently open, and the user chooses Preferences from the menu
7615  * a second time; use gtk_window_present() to move the already-open dialog
7616  * where the user can see it.
7617  *
7618  * If you are calling this function in response to a user interaction,
7619  * it is preferable to use gtk_window_present_with_time().
7620  * 
7621  **/
7622 void
7623 gtk_window_present (GtkWindow *window)
7624 {
7625   gtk_window_present_with_time (window, GDK_CURRENT_TIME);
7626 }
7627
7628 /**
7629  * gtk_window_present_with_time:
7630  * @window: a #GtkWindow
7631  * @timestamp: the timestamp of the user interaction (typically a 
7632  *   button or key press event) which triggered this call
7633  *
7634  * Presents a window to the user in response to a user interaction.
7635  * If you need to present a window without a timestamp, use 
7636  * gtk_window_present(). See gtk_window_present() for details. 
7637  * 
7638  * Since: 2.8
7639  **/
7640 void
7641 gtk_window_present_with_time (GtkWindow *window,
7642                               guint32    timestamp)
7643 {
7644   GtkWindowPrivate *priv;
7645   GtkWidget *widget;
7646   GdkWindow *gdk_window;
7647
7648   g_return_if_fail (GTK_IS_WINDOW (window));
7649
7650   priv = window->priv;
7651   widget = GTK_WIDGET (window);
7652
7653   if (gtk_widget_get_visible (widget))
7654     {
7655       gdk_window = gtk_widget_get_window (widget);
7656
7657       g_assert (gdk_window != NULL);
7658
7659       gdk_window_show (gdk_window);
7660
7661       /* Translate a timestamp of GDK_CURRENT_TIME appropriately */
7662       if (timestamp == GDK_CURRENT_TIME)
7663         {
7664 #ifdef GDK_WINDOWING_X11
7665           if (GDK_IS_X11_WINDOW(gdk_window))
7666             {
7667               GdkDisplay *display;
7668
7669               display = gtk_widget_get_display (GTK_WIDGET (window));
7670               timestamp = gdk_x11_display_get_user_time (display);
7671             }
7672           else
7673 #endif
7674             timestamp = gtk_get_current_event_time ();
7675         }
7676
7677       gdk_window_focus (gdk_window, timestamp);
7678     }
7679   else
7680     {
7681       priv->initial_timestamp = timestamp;
7682       gtk_widget_show (widget);
7683     }
7684 }
7685
7686 /**
7687  * gtk_window_iconify:
7688  * @window: a #GtkWindow
7689  *
7690  * Asks to iconify (i.e. minimize) the specified @window. Note that
7691  * you shouldn't assume the window is definitely iconified afterward,
7692  * because other entities (e.g. the user or <link
7693  * linkend="gtk-X11-arch">window manager</link>) could deiconify it
7694  * again, or there may not be a window manager in which case
7695  * iconification isn't possible, etc. But normally the window will end
7696  * up iconified. Just don't write code that crashes if not.
7697  *
7698  * It's permitted to call this function before showing a window,
7699  * in which case the window will be iconified before it ever appears
7700  * onscreen.
7701  *
7702  * You can track iconification via the "window-state-event" signal
7703  * on #GtkWidget.
7704  * 
7705  **/
7706 void
7707 gtk_window_iconify (GtkWindow *window)
7708 {
7709   GtkWindowPrivate *priv;
7710   GtkWidget *widget;
7711   GdkWindow *toplevel;
7712   
7713   g_return_if_fail (GTK_IS_WINDOW (window));
7714
7715   priv = window->priv;
7716   widget = GTK_WIDGET (window);
7717
7718   priv->iconify_initially = TRUE;
7719
7720   toplevel = gtk_widget_get_window (widget);
7721
7722   if (toplevel != NULL)
7723     gdk_window_iconify (toplevel);
7724 }
7725
7726 /**
7727  * gtk_window_deiconify:
7728  * @window: a #GtkWindow
7729  *
7730  * Asks to deiconify (i.e. unminimize) the specified @window. Note
7731  * that you shouldn't assume the window is definitely deiconified
7732  * afterward, because other entities (e.g. the user or <link
7733  * linkend="gtk-X11-arch">window manager</link>) could iconify it
7734  * again before your code which assumes deiconification gets to run.
7735  *
7736  * You can track iconification via the "window-state-event" signal
7737  * on #GtkWidget.
7738  **/
7739 void
7740 gtk_window_deiconify (GtkWindow *window)
7741 {
7742   GtkWindowPrivate *priv;
7743   GtkWidget *widget;
7744   GdkWindow *toplevel;
7745   
7746   g_return_if_fail (GTK_IS_WINDOW (window));
7747
7748   priv = window->priv;
7749   widget = GTK_WIDGET (window);
7750
7751   priv->iconify_initially = FALSE;
7752
7753   toplevel = gtk_widget_get_window (widget);
7754
7755   if (toplevel != NULL)
7756     gdk_window_deiconify (toplevel);
7757 }
7758
7759 /**
7760  * gtk_window_stick:
7761  * @window: a #GtkWindow
7762  *
7763  * Asks to stick @window, which means that it will appear on all user
7764  * desktops. Note that you shouldn't assume the window is definitely
7765  * stuck afterward, because other entities (e.g. the user or <link
7766  * linkend="gtk-X11-arch">window manager</link>) could unstick it
7767  * again, and some window managers do not support sticking
7768  * windows. But normally the window will end up stuck. Just don't
7769  * write code that crashes if not.
7770  *
7771  * It's permitted to call this function before showing a window.
7772  *
7773  * You can track stickiness via the "window-state-event" signal
7774  * on #GtkWidget.
7775  * 
7776  **/
7777 void
7778 gtk_window_stick (GtkWindow *window)
7779 {
7780   GtkWindowPrivate *priv;
7781   GtkWidget *widget;
7782   GdkWindow *toplevel;
7783   
7784   g_return_if_fail (GTK_IS_WINDOW (window));
7785
7786   priv = window->priv;
7787   widget = GTK_WIDGET (window);
7788
7789   priv->stick_initially = TRUE;
7790
7791   toplevel = gtk_widget_get_window (widget);
7792
7793   if (toplevel != NULL)
7794     gdk_window_stick (toplevel);
7795 }
7796
7797 /**
7798  * gtk_window_unstick:
7799  * @window: a #GtkWindow
7800  *
7801  * Asks to unstick @window, which means that it will appear on only
7802  * one of the user's desktops. Note that you shouldn't assume the
7803  * window is definitely unstuck afterward, because other entities
7804  * (e.g. the user or <link linkend="gtk-X11-arch">window
7805  * manager</link>) could stick it again. But normally the window will
7806  * end up stuck. Just don't write code that crashes if not.
7807  *
7808  * You can track stickiness via the "window-state-event" signal
7809  * on #GtkWidget.
7810  * 
7811  **/
7812 void
7813 gtk_window_unstick (GtkWindow *window)
7814 {
7815   GtkWindowPrivate *priv;
7816   GtkWidget *widget;
7817   GdkWindow *toplevel;
7818   
7819   g_return_if_fail (GTK_IS_WINDOW (window));
7820
7821   priv = window->priv;
7822   widget = GTK_WIDGET (window);
7823
7824   priv->stick_initially = FALSE;
7825
7826   toplevel = gtk_widget_get_window (widget);
7827
7828   if (toplevel != NULL)
7829     gdk_window_unstick (toplevel);
7830 }
7831
7832 /**
7833  * gtk_window_maximize:
7834  * @window: a #GtkWindow
7835  *
7836  * Asks to maximize @window, so that it becomes full-screen. Note that
7837  * you shouldn't assume the window is definitely maximized afterward,
7838  * because other entities (e.g. the user or <link
7839  * linkend="gtk-X11-arch">window manager</link>) could unmaximize it
7840  * again, and not all window managers support maximization. But
7841  * normally the window will end up maximized. Just don't write code
7842  * that crashes if not.
7843  *
7844  * It's permitted to call this function before showing a window,
7845  * in which case the window will be maximized when it appears onscreen
7846  * initially.
7847  *
7848  * You can track maximization via the "window-state-event" signal
7849  * on #GtkWidget.
7850  * 
7851  **/
7852 void
7853 gtk_window_maximize (GtkWindow *window)
7854 {
7855   GtkWindowPrivate *priv;
7856   GtkWidget *widget;
7857   GdkWindow *toplevel;
7858   
7859   g_return_if_fail (GTK_IS_WINDOW (window));
7860
7861   priv = window->priv;
7862   widget = GTK_WIDGET (window);
7863
7864   priv->maximize_initially = TRUE;
7865
7866   toplevel = gtk_widget_get_window (widget);
7867
7868   if (toplevel != NULL)
7869     gdk_window_maximize (toplevel);
7870 }
7871
7872 /**
7873  * gtk_window_unmaximize:
7874  * @window: a #GtkWindow
7875  *
7876  * Asks to unmaximize @window. Note that you shouldn't assume the
7877  * window is definitely unmaximized afterward, because other entities
7878  * (e.g. the user or <link linkend="gtk-X11-arch">window
7879  * manager</link>) could maximize it again, and not all window
7880  * managers honor requests to unmaximize. But normally the window will
7881  * end up unmaximized. Just don't write code that crashes if not.
7882  *
7883  * You can track maximization via the "window-state-event" signal
7884  * on #GtkWidget.
7885  * 
7886  **/
7887 void
7888 gtk_window_unmaximize (GtkWindow *window)
7889 {
7890   GtkWindowPrivate *priv;
7891   GtkWidget *widget;
7892   GdkWindow *toplevel;
7893   
7894   g_return_if_fail (GTK_IS_WINDOW (window));
7895
7896   priv = window->priv;
7897   widget = GTK_WIDGET (window);
7898
7899   priv->maximize_initially = FALSE;
7900
7901   toplevel = gtk_widget_get_window (widget);
7902
7903   if (toplevel != NULL)
7904     gdk_window_unmaximize (toplevel);
7905 }
7906
7907 /**
7908  * gtk_window_fullscreen:
7909  * @window: a #GtkWindow
7910  *
7911  * Asks to place @window in the fullscreen state. Note that you
7912  * shouldn't assume the window is definitely full screen afterward,
7913  * because other entities (e.g. the user or <link
7914  * linkend="gtk-X11-arch">window manager</link>) could unfullscreen it
7915  * again, and not all window managers honor requests to fullscreen
7916  * windows. But normally the window will end up fullscreen. Just
7917  * don't write code that crashes if not.
7918  *
7919  * You can track the fullscreen state via the "window-state-event" signal
7920  * on #GtkWidget.
7921  * 
7922  * Since: 2.2
7923  **/
7924 void
7925 gtk_window_fullscreen (GtkWindow *window)
7926 {
7927   GtkWindowPrivate *priv;
7928   GtkWidget *widget;
7929   GdkWindow *toplevel;
7930
7931   g_return_if_fail (GTK_IS_WINDOW (window));
7932
7933   priv = window->priv;
7934   widget = GTK_WIDGET (window);
7935
7936   priv->fullscreen_initially = TRUE;
7937
7938   toplevel = gtk_widget_get_window (widget);
7939
7940   if (toplevel != NULL)
7941     gdk_window_fullscreen (toplevel);
7942 }
7943
7944 /**
7945  * gtk_window_unfullscreen:
7946  * @window: a #GtkWindow
7947  *
7948  * Asks to toggle off the fullscreen state for @window. Note that you
7949  * shouldn't assume the window is definitely not full screen
7950  * afterward, because other entities (e.g. the user or <link
7951  * linkend="gtk-X11-arch">window manager</link>) could fullscreen it
7952  * again, and not all window managers honor requests to unfullscreen
7953  * windows. But normally the window will end up restored to its normal
7954  * state. Just don't write code that crashes if not.
7955  *
7956  * You can track the fullscreen state via the "window-state-event" signal
7957  * on #GtkWidget.
7958  * 
7959  * Since: 2.2
7960  **/
7961 void
7962 gtk_window_unfullscreen (GtkWindow *window)
7963 {
7964   GtkWidget *widget;
7965   GdkWindow *toplevel;
7966   GtkWindowPrivate *priv;
7967
7968   g_return_if_fail (GTK_IS_WINDOW (window));
7969
7970   priv = window->priv;
7971   widget = GTK_WIDGET (window);
7972
7973   priv->fullscreen_initially = FALSE;
7974
7975   toplevel = gtk_widget_get_window (widget);
7976
7977   if (toplevel != NULL)
7978     gdk_window_unfullscreen (toplevel);
7979 }
7980
7981 /**
7982  * gtk_window_set_keep_above:
7983  * @window: a #GtkWindow
7984  * @setting: whether to keep @window above other windows
7985  *
7986  * Asks to keep @window above, so that it stays on top. Note that
7987  * you shouldn't assume the window is definitely above afterward,
7988  * because other entities (e.g. the user or <link
7989  * linkend="gtk-X11-arch">window manager</link>) could not keep it above,
7990  * and not all window managers support keeping windows above. But
7991  * normally the window will end kept above. Just don't write code
7992  * that crashes if not.
7993  *
7994  * It's permitted to call this function before showing a window,
7995  * in which case the window will be kept above when it appears onscreen
7996  * initially.
7997  *
7998  * You can track the above state via the "window-state-event" signal
7999  * on #GtkWidget.
8000  *
8001  * Note that, according to the <ulink 
8002  * url="http://www.freedesktop.org/Standards/wm-spec">Extended Window 
8003  * Manager Hints</ulink> specification, the above state is mainly meant 
8004  * for user preferences and should not be used by applications e.g. for 
8005  * drawing attention to their dialogs.
8006  *
8007  * Since: 2.4
8008  **/
8009 void
8010 gtk_window_set_keep_above (GtkWindow *window,
8011                            gboolean   setting)
8012 {
8013   GtkWidget *widget;
8014   GtkWindowPrivate *priv;
8015   GdkWindow *toplevel;
8016
8017   g_return_if_fail (GTK_IS_WINDOW (window));
8018
8019   priv = window->priv;
8020   widget = GTK_WIDGET (window);
8021
8022   priv->above_initially = setting != FALSE;
8023   if (setting)
8024     priv->below_initially = FALSE;
8025
8026   toplevel = gtk_widget_get_window (widget);
8027
8028   if (toplevel != NULL)
8029     gdk_window_set_keep_above (toplevel, setting);
8030 }
8031
8032 /**
8033  * gtk_window_set_keep_below:
8034  * @window: a #GtkWindow
8035  * @setting: whether to keep @window below other windows
8036  *
8037  * Asks to keep @window below, so that it stays in bottom. Note that
8038  * you shouldn't assume the window is definitely below afterward,
8039  * because other entities (e.g. the user or <link
8040  * linkend="gtk-X11-arch">window manager</link>) could not keep it below,
8041  * and not all window managers support putting windows below. But
8042  * normally the window will be kept below. Just don't write code
8043  * that crashes if not.
8044  *
8045  * It's permitted to call this function before showing a window,
8046  * in which case the window will be kept below when it appears onscreen
8047  * initially.
8048  *
8049  * You can track the below state via the "window-state-event" signal
8050  * on #GtkWidget.
8051  *
8052  * Note that, according to the <ulink 
8053  * url="http://www.freedesktop.org/Standards/wm-spec">Extended Window 
8054  * Manager Hints</ulink> specification, the above state is mainly meant 
8055  * for user preferences and should not be used by applications e.g. for 
8056  * drawing attention to their dialogs.
8057  *
8058  * Since: 2.4
8059  **/
8060 void
8061 gtk_window_set_keep_below (GtkWindow *window,
8062                            gboolean   setting)
8063 {
8064   GtkWidget *widget;
8065   GtkWindowPrivate *priv;
8066   GdkWindow *toplevel;
8067
8068   g_return_if_fail (GTK_IS_WINDOW (window));
8069
8070   priv = window->priv;
8071   widget = GTK_WIDGET (window);
8072
8073   priv->below_initially = setting != FALSE;
8074   if (setting)
8075     priv->above_initially = FALSE;
8076
8077   toplevel = gtk_widget_get_window (widget);
8078
8079   if (toplevel != NULL)
8080     gdk_window_set_keep_below (toplevel, setting);
8081 }
8082
8083 /**
8084  * gtk_window_set_resizable:
8085  * @window: a #GtkWindow
8086  * @resizable: %TRUE if the user can resize this window
8087  *
8088  * Sets whether the user can resize a window. Windows are user resizable
8089  * by default.
8090  **/
8091 void
8092 gtk_window_set_resizable (GtkWindow *window,
8093                           gboolean   resizable)
8094 {
8095   GtkWindowPrivate *priv;
8096
8097   g_return_if_fail (GTK_IS_WINDOW (window));
8098
8099   priv = window->priv;
8100
8101   resizable = (resizable != FALSE);
8102
8103   if (priv->resizable != resizable)
8104     {
8105       priv->resizable = resizable;
8106
8107       update_grip_visibility (window);
8108
8109       gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window));
8110
8111       g_object_notify (G_OBJECT (window), "resizable");
8112     }
8113 }
8114
8115 /**
8116  * gtk_window_get_resizable:
8117  * @window: a #GtkWindow
8118  *
8119  * Gets the value set by gtk_window_set_resizable().
8120  *
8121  * Return value: %TRUE if the user can resize the window
8122  **/
8123 gboolean
8124 gtk_window_get_resizable (GtkWindow *window)
8125 {
8126   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
8127
8128   return window->priv->resizable;
8129 }
8130
8131 /**
8132  * gtk_window_set_gravity:
8133  * @window: a #GtkWindow
8134  * @gravity: window gravity
8135  *
8136  * Window gravity defines the meaning of coordinates passed to
8137  * gtk_window_move(). See gtk_window_move() and #GdkGravity for
8138  * more details.
8139  *
8140  * The default window gravity is #GDK_GRAVITY_NORTH_WEST which will
8141  * typically "do what you mean."
8142  *
8143  **/
8144 void
8145 gtk_window_set_gravity (GtkWindow *window,
8146                         GdkGravity gravity)
8147 {
8148   GtkWindowPrivate *priv;
8149
8150   g_return_if_fail (GTK_IS_WINDOW (window));
8151
8152   priv = window->priv;
8153
8154   if (gravity != priv->gravity)
8155     {
8156       priv->gravity = gravity;
8157
8158       /* gtk_window_move_resize() will adapt gravity
8159        */
8160       gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window));
8161
8162       g_object_notify (G_OBJECT (window), "gravity");
8163     }
8164 }
8165
8166 /**
8167  * gtk_window_get_gravity:
8168  * @window: a #GtkWindow
8169  *
8170  * Gets the value set by gtk_window_set_gravity().
8171  *
8172  * Return value: (transfer none): window gravity
8173  **/
8174 GdkGravity
8175 gtk_window_get_gravity (GtkWindow *window)
8176 {
8177   g_return_val_if_fail (GTK_IS_WINDOW (window), 0);
8178
8179   return window->priv->gravity;
8180 }
8181
8182 /**
8183  * gtk_window_begin_resize_drag:
8184  * @window: a #GtkWindow
8185  * @button: mouse button that initiated the drag
8186  * @edge: position of the resize control
8187  * @root_x: X position where the user clicked to initiate the drag, in root window coordinates
8188  * @root_y: Y position where the user clicked to initiate the drag
8189  * @timestamp: timestamp from the click event that initiated the drag
8190  *
8191  * Starts resizing a window. This function is used if an application
8192  * has window resizing controls. When GDK can support it, the resize
8193  * will be done using the standard mechanism for the <link
8194  * linkend="gtk-X11-arch">window manager</link> or windowing
8195  * system. Otherwise, GDK will try to emulate window resizing,
8196  * potentially not all that well, depending on the windowing system.
8197  * 
8198  **/
8199 void
8200 gtk_window_begin_resize_drag  (GtkWindow    *window,
8201                                GdkWindowEdge edge,
8202                                gint          button,
8203                                gint          root_x,
8204                                gint          root_y,
8205                                guint32       timestamp)
8206 {
8207   GtkWidget *widget;
8208   GdkWindow *toplevel;
8209
8210   g_return_if_fail (GTK_IS_WINDOW (window));
8211   widget = GTK_WIDGET (window);
8212   g_return_if_fail (gtk_widget_get_visible (widget));
8213
8214   toplevel = gtk_widget_get_window (widget);
8215
8216   gdk_window_begin_resize_drag (toplevel,
8217                                 edge, button,
8218                                 root_x, root_y,
8219                                 timestamp);
8220 }
8221
8222 /**
8223  * gtk_window_begin_move_drag:
8224  * @window: a #GtkWindow
8225  * @button: mouse button that initiated the drag
8226  * @root_x: X position where the user clicked to initiate the drag, in root window coordinates
8227  * @root_y: Y position where the user clicked to initiate the drag
8228  * @timestamp: timestamp from the click event that initiated the drag
8229  *
8230  * Starts moving a window. This function is used if an application has
8231  * window movement grips. When GDK can support it, the window movement
8232  * will be done using the standard mechanism for the <link
8233  * linkend="gtk-X11-arch">window manager</link> or windowing
8234  * system. Otherwise, GDK will try to emulate window movement,
8235  * potentially not all that well, depending on the windowing system.
8236  * 
8237  **/
8238 void
8239 gtk_window_begin_move_drag  (GtkWindow *window,
8240                              gint       button,
8241                              gint       root_x,
8242                              gint       root_y,
8243                              guint32    timestamp)
8244 {
8245   GtkWidget *widget;
8246   GdkWindow *toplevel;
8247
8248   g_return_if_fail (GTK_IS_WINDOW (window));
8249   widget = GTK_WIDGET (window);
8250   g_return_if_fail (gtk_widget_get_visible (widget));
8251
8252   toplevel = gtk_widget_get_window (widget);
8253
8254   gdk_window_begin_move_drag (toplevel,
8255                               button,
8256                               root_x, root_y,
8257                               timestamp);
8258 }
8259
8260 /**
8261  * gtk_window_set_screen:
8262  * @window: a #GtkWindow.
8263  * @screen: a #GdkScreen.
8264  *
8265  * Sets the #GdkScreen where the @window is displayed; if
8266  * the window is already mapped, it will be unmapped, and
8267  * then remapped on the new screen.
8268  *
8269  * Since: 2.2
8270  */
8271 void
8272 gtk_window_set_screen (GtkWindow *window,
8273                        GdkScreen *screen)
8274 {
8275   GtkWindowPrivate *priv;
8276   GtkWidget *widget;
8277   GdkScreen *previous_screen;
8278   gboolean was_mapped;
8279
8280   g_return_if_fail (GTK_IS_WINDOW (window));
8281   g_return_if_fail (GDK_IS_SCREEN (screen));
8282
8283   priv = window->priv;
8284
8285   if (screen == priv->screen)
8286     return;
8287
8288   widget = GTK_WIDGET (window);
8289
8290   previous_screen = priv->screen;
8291   was_mapped = gtk_widget_get_mapped (widget);
8292
8293   if (was_mapped)
8294     gtk_widget_unmap (widget);
8295   if (gtk_widget_get_realized (widget))
8296     gtk_widget_unrealize (widget);
8297
8298   gtk_window_free_key_hash (window);
8299   priv->screen = screen;
8300   gtk_widget_reset_rc_styles (widget);
8301   if (screen != previous_screen)
8302     {
8303       if (previous_screen)
8304         {
8305           g_signal_handlers_disconnect_by_func (previous_screen,
8306                                                 gtk_window_on_composited_changed, window);
8307 #ifdef GDK_WINDOWING_X11
8308           g_signal_handlers_disconnect_by_func (gtk_settings_get_for_screen (previous_screen),
8309                                                 gtk_window_on_theme_variant_changed, window);
8310 #endif
8311         }
8312       g_signal_connect (screen, "composited-changed",
8313                         G_CALLBACK (gtk_window_on_composited_changed), window);
8314 #ifdef GDK_WINDOWING_X11
8315       g_signal_connect (gtk_settings_get_for_screen (screen),
8316                         "notify::gtk-application-prefer-dark-theme",
8317                         G_CALLBACK (gtk_window_on_theme_variant_changed), window);
8318 #endif
8319
8320       _gtk_widget_propagate_screen_changed (widget, previous_screen);
8321       _gtk_widget_propagate_composited_changed (widget);
8322     }
8323   g_object_notify (G_OBJECT (window), "screen");
8324
8325   if (was_mapped)
8326     gtk_widget_map (widget);
8327 }
8328
8329 static void
8330 gtk_window_set_theme_variant (GtkWindow *window)
8331 {
8332 #ifdef GDK_WINDOWING_X11
8333   GdkWindow *gdk_window;
8334   gboolean   dark_theme_requested;
8335
8336   g_object_get (gtk_settings_get_for_screen (window->priv->screen),
8337                 "gtk-application-prefer-dark-theme", &dark_theme_requested,
8338                 NULL);
8339
8340   gdk_window = gtk_widget_get_window (GTK_WIDGET (window));
8341
8342   if (GDK_IS_X11_WINDOW (gdk_window))
8343     gdk_x11_window_set_theme_variant (gdk_window,
8344                                       dark_theme_requested ? "dark" : NULL);
8345 #endif
8346 }
8347
8348 static void
8349 gtk_window_on_theme_variant_changed (GtkSettings *settings,
8350                                      GParamSpec  *pspec,
8351                                      GtkWindow   *window)
8352 {
8353   if (window->priv->type == GTK_WINDOW_TOPLEVEL)
8354     gtk_window_set_theme_variant (window);
8355 }
8356
8357 static void
8358 gtk_window_on_composited_changed (GdkScreen *screen,
8359                                   GtkWindow *window)
8360 {
8361   gtk_widget_queue_draw (GTK_WIDGET (window));
8362   
8363   _gtk_widget_propagate_composited_changed (GTK_WIDGET (window));
8364 }
8365
8366 static GdkScreen *
8367 gtk_window_check_screen (GtkWindow *window)
8368 {
8369   GtkWindowPrivate *priv = window->priv;
8370
8371   if (priv->screen)
8372     return priv->screen;
8373   else
8374     {
8375       g_warning ("Screen for GtkWindow not set; you must always set\n"
8376                  "a screen for a GtkWindow before using the window");
8377       return NULL;
8378     }
8379 }
8380
8381 /**
8382  * gtk_window_get_screen:
8383  * @window: a #GtkWindow.
8384  *
8385  * Returns the #GdkScreen associated with @window.
8386  *
8387  * Return value: (transfer none): a #GdkScreen.
8388  *
8389  * Since: 2.2
8390  */
8391 GdkScreen*
8392 gtk_window_get_screen (GtkWindow *window)
8393 {
8394   g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
8395
8396   return window->priv->screen;
8397 }
8398
8399 /**
8400  * gtk_window_is_active:
8401  * @window: a #GtkWindow
8402  * 
8403  * Returns whether the window is part of the current active toplevel.
8404  * (That is, the toplevel window receiving keystrokes.)
8405  * The return value is %TRUE if the window is active toplevel
8406  * itself, but also if it is, say, a #GtkPlug embedded in the active toplevel.
8407  * You might use this function if you wanted to draw a widget
8408  * differently in an active window from a widget in an inactive window.
8409  * See gtk_window_has_toplevel_focus()
8410  * 
8411  * Return value: %TRUE if the window part of the current active window.
8412  *
8413  * Since: 2.4
8414  **/
8415 gboolean
8416 gtk_window_is_active (GtkWindow *window)
8417 {
8418   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
8419
8420   return window->priv->is_active;
8421 }
8422
8423 /**
8424  * gtk_window_has_toplevel_focus:
8425  * @window: a #GtkWindow
8426  * 
8427  * Returns whether the input focus is within this GtkWindow.
8428  * For real toplevel windows, this is identical to gtk_window_is_active(),
8429  * but for embedded windows, like #GtkPlug, the results will differ.
8430  * 
8431  * Return value: %TRUE if the input focus is within this GtkWindow
8432  *
8433  * Since: 2.4
8434  **/
8435 gboolean
8436 gtk_window_has_toplevel_focus (GtkWindow *window)
8437 {
8438   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
8439
8440   return window->priv->has_toplevel_focus;
8441 }
8442
8443
8444 /**
8445  * SECTION:gtkwindowgroup
8446  * @Short_description: Limit the effect of grabs
8447  * @Title: GtkWindowGroup
8448  *
8449  * #GtkWindowGroup objects are referenced by each window in the group,
8450  * so once you have added all windows to a #GtkWindowGroup, you can drop
8451  * the initial reference to the window group with g_object_unref(). If the
8452  * windows in the window group are subsequently destroyed, then they will
8453  * be removed from the window group and drop their references on the window
8454  * group; when all window have been removed, the window group will be
8455  * freed.
8456  */
8457
8458 G_DEFINE_TYPE (GtkWindowGroup, gtk_window_group, G_TYPE_OBJECT)
8459
8460 static void
8461 gtk_window_group_init (GtkWindowGroup *group)
8462 {
8463   group->priv = G_TYPE_INSTANCE_GET_PRIVATE (group,
8464                                              GTK_TYPE_WINDOW_GROUP,
8465                                              GtkWindowGroupPrivate);
8466 }
8467
8468 static void
8469 gtk_window_group_class_init (GtkWindowGroupClass *klass)
8470 {
8471   g_type_class_add_private (klass, sizeof (GtkWindowGroupPrivate));
8472 }
8473
8474 /**
8475  * gtk_window_group_new:
8476  * 
8477  * Creates a new #GtkWindowGroup object. Grabs added with
8478  * gtk_grab_add() only affect windows within the same #GtkWindowGroup.
8479  * 
8480  * Return value: a new #GtkWindowGroup. 
8481  **/
8482 GtkWindowGroup *
8483 gtk_window_group_new (void)
8484 {
8485   return g_object_new (GTK_TYPE_WINDOW_GROUP, NULL);
8486 }
8487
8488 static void
8489 window_group_cleanup_grabs (GtkWindowGroup *group,
8490                             GtkWindow      *window)
8491 {
8492   GtkWindowGroupPrivate *priv;
8493   GtkDeviceGrabInfo *info;
8494   GSList *tmp_list;
8495   GSList *to_remove = NULL;
8496
8497   priv = group->priv;
8498
8499   tmp_list = priv->grabs;
8500   while (tmp_list)
8501     {
8502       if (gtk_widget_get_toplevel (tmp_list->data) == (GtkWidget*) window)
8503         to_remove = g_slist_prepend (to_remove, g_object_ref (tmp_list->data));
8504       tmp_list = tmp_list->next;
8505     }
8506
8507   while (to_remove)
8508     {
8509       gtk_grab_remove (to_remove->data);
8510       g_object_unref (to_remove->data);
8511       to_remove = g_slist_delete_link (to_remove, to_remove);
8512     }
8513
8514   tmp_list = priv->device_grabs;
8515
8516   while (tmp_list)
8517     {
8518       info = tmp_list->data;
8519
8520       if (gtk_widget_get_toplevel (info->widget) == (GtkWidget *) window)
8521         to_remove = g_slist_prepend (to_remove, info);
8522
8523       tmp_list = tmp_list->next;
8524     }
8525
8526   while (to_remove)
8527     {
8528       info = to_remove->data;
8529
8530       gtk_device_grab_remove (info->widget, info->device);
8531       to_remove = g_slist_delete_link (to_remove, to_remove);
8532     }
8533 }
8534
8535 /**
8536  * gtk_window_group_add_window:
8537  * @window_group: a #GtkWindowGroup
8538  * @window: the #GtkWindow to add
8539  * 
8540  * Adds a window to a #GtkWindowGroup. 
8541  **/
8542 void
8543 gtk_window_group_add_window (GtkWindowGroup *window_group,
8544                              GtkWindow      *window)
8545 {
8546   GtkWindowPrivate *priv;
8547
8548   g_return_if_fail (GTK_IS_WINDOW_GROUP (window_group));
8549   g_return_if_fail (GTK_IS_WINDOW (window));
8550
8551   priv = window->priv;
8552
8553   if (priv->group != window_group)
8554     {
8555       g_object_ref (window);
8556       g_object_ref (window_group);
8557
8558       if (priv->group)
8559         gtk_window_group_remove_window (priv->group, window);
8560       else
8561         window_group_cleanup_grabs (gtk_window_get_group (NULL), window);
8562
8563       priv->group = window_group;
8564
8565       g_object_unref (window);
8566     }
8567 }
8568
8569 /**
8570  * gtk_window_group_remove_window:
8571  * @window_group: a #GtkWindowGroup
8572  * @window: the #GtkWindow to remove
8573  * 
8574  * Removes a window from a #GtkWindowGroup.
8575  **/
8576 void
8577 gtk_window_group_remove_window (GtkWindowGroup *window_group,
8578                                 GtkWindow      *window)
8579 {
8580   GtkWindowPrivate *priv;
8581
8582   g_return_if_fail (GTK_IS_WINDOW_GROUP (window_group));
8583   g_return_if_fail (GTK_IS_WINDOW (window));
8584   priv = window->priv;
8585   g_return_if_fail (priv->group == window_group);
8586
8587   g_object_ref (window);
8588
8589   window_group_cleanup_grabs (window_group, window);
8590   priv->group = NULL;
8591
8592   g_object_unref (window_group);
8593   g_object_unref (window);
8594 }
8595
8596 /**
8597  * gtk_window_group_list_windows:
8598  * @window_group: a #GtkWindowGroup
8599  *
8600  * Returns a list of the #GtkWindows that belong to @window_group.
8601  *
8602  * Returns: (element-type GtkWindow) (transfer container): A
8603  *   newly-allocated list of windows inside the group.
8604  *
8605  * Since: 2.14
8606  **/
8607 GList *
8608 gtk_window_group_list_windows (GtkWindowGroup *window_group)
8609 {
8610   GList *toplevels, *toplevel, *group_windows;
8611
8612   g_return_val_if_fail (GTK_IS_WINDOW_GROUP (window_group), NULL);
8613
8614   group_windows = NULL;
8615   toplevels = gtk_window_list_toplevels ();
8616
8617   for (toplevel = toplevels; toplevel; toplevel = toplevel->next)
8618     {
8619       GtkWindow *window = toplevel->data;
8620
8621       if (window_group == window->priv->group)
8622         group_windows = g_list_prepend (group_windows, window);
8623     }
8624
8625   g_list_free (toplevels);
8626
8627   return g_list_reverse (group_windows);
8628 }
8629
8630 /**
8631  * gtk_window_get_group:
8632  * @window: (allow-none): a #GtkWindow, or %NULL
8633  *
8634  * Returns the group for @window or the default group, if
8635  * @window is %NULL or if @window does not have an explicit
8636  * window group.
8637  *
8638  * Returns: (transfer none): the #GtkWindowGroup for a window or the default group
8639  *
8640  * Since: 2.10
8641  */
8642 GtkWindowGroup *
8643 gtk_window_get_group (GtkWindow *window)
8644 {
8645   if (window && window->priv->group)
8646     return window->priv->group;
8647   else
8648     {
8649       static GtkWindowGroup *default_group = NULL;
8650
8651       if (!default_group)
8652         default_group = gtk_window_group_new ();
8653
8654       return default_group;
8655     }
8656 }
8657
8658 /**
8659  * gtk_window_has_group:
8660  * @window: a #GtkWindow
8661  *
8662  * Returns whether @window has an explicit window group.
8663  *
8664  * Return value: %TRUE if @window has an explicit window group.
8665  *
8666  * Since 2.22
8667  **/
8668 gboolean
8669 gtk_window_has_group (GtkWindow *window)
8670 {
8671   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
8672
8673   return window->priv->group != NULL;
8674 }
8675
8676 /**
8677  * gtk_window_group_get_current_grab:
8678  * @window_group: a #GtkWindowGroup
8679  *
8680  * Gets the current grab widget of the given group,
8681  * see gtk_grab_add().
8682  *
8683  * Returns: (transfer none): the current grab widget of the group
8684  *
8685  * Since: 2.22
8686  */
8687 GtkWidget *
8688 gtk_window_group_get_current_grab (GtkWindowGroup *window_group)
8689 {
8690   g_return_val_if_fail (GTK_IS_WINDOW_GROUP (window_group), NULL);
8691
8692   if (window_group->priv->grabs)
8693     return GTK_WIDGET (window_group->priv->grabs->data);
8694   return NULL;
8695 }
8696
8697 void
8698 _gtk_window_group_add_grab (GtkWindowGroup *window_group,
8699                             GtkWidget      *widget)
8700 {
8701   GtkWindowGroupPrivate *priv;
8702
8703   priv = window_group->priv;
8704   priv->grabs = g_slist_prepend (priv->grabs, widget);
8705 }
8706
8707 void
8708 _gtk_window_group_remove_grab (GtkWindowGroup *window_group,
8709                                GtkWidget      *widget)
8710 {
8711   GtkWindowGroupPrivate *priv;
8712
8713   priv = window_group->priv;
8714   priv->grabs = g_slist_remove (priv->grabs, widget);
8715 }
8716
8717
8718 void
8719 _gtk_window_group_add_device_grab (GtkWindowGroup *window_group,
8720                                    GtkWidget      *widget,
8721                                    GdkDevice      *device,
8722                                    gboolean        block_others)
8723 {
8724   GtkWindowGroupPrivate *priv;
8725   GtkDeviceGrabInfo *info;
8726
8727   priv = window_group->priv;
8728
8729   info = g_slice_new0 (GtkDeviceGrabInfo);
8730   info->widget = widget;
8731   info->device = device;
8732   info->block_others = block_others;
8733
8734   priv->device_grabs = g_slist_prepend (priv->device_grabs, info);
8735 }
8736
8737 void
8738 _gtk_window_group_remove_device_grab (GtkWindowGroup *window_group,
8739                                       GtkWidget      *widget,
8740                                       GdkDevice      *device)
8741 {
8742   GtkWindowGroupPrivate *priv;
8743   GtkDeviceGrabInfo *info;
8744   GSList *list, *node = NULL;
8745   GdkDevice *other_device;
8746
8747   priv = window_group->priv;
8748   other_device = gdk_device_get_associated_device (device);
8749   list = priv->device_grabs;
8750
8751   while (list)
8752     {
8753       info = list->data;
8754
8755       if (info->widget == widget &&
8756           (info->device == device ||
8757            info->device == other_device))
8758         {
8759           node = list;
8760           break;
8761         }
8762
8763       list = list->next;
8764     }
8765
8766   if (node)
8767     {
8768       info = node->data;
8769
8770       priv->device_grabs = g_slist_delete_link (priv->device_grabs, node);
8771       g_slice_free (GtkDeviceGrabInfo, info);
8772     }
8773 }
8774
8775 /**
8776  * gtk_window_group_get_current_device_grab:
8777  * @window_group: a #GtkWindowGroup
8778  * @device: a #GdkDevice
8779  *
8780  * Returns the current grab widget for @device, or %NULL if none.
8781  *
8782  * Returns: (transfer none): The grab widget, or %NULL
8783  *
8784  * Since: 3.0
8785  */
8786 GtkWidget *
8787 gtk_window_group_get_current_device_grab (GtkWindowGroup *window_group,
8788                                           GdkDevice      *device)
8789 {
8790   GtkWindowGroupPrivate *priv;
8791   GtkDeviceGrabInfo *info;
8792   GdkDevice *other_device;
8793   GSList *list;
8794
8795   g_return_val_if_fail (GTK_IS_WINDOW_GROUP (window_group), NULL);
8796   g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
8797
8798   priv = window_group->priv;
8799   list = priv->device_grabs;
8800   other_device = gdk_device_get_associated_device (device);
8801
8802   while (list)
8803     {
8804       info = list->data;
8805       list = list->next;
8806
8807       if (info->device == device ||
8808           info->device == other_device)
8809         return info->widget;
8810     }
8811
8812   return NULL;
8813 }
8814
8815 gboolean
8816 _gtk_window_group_widget_is_blocked_for_device (GtkWindowGroup *window_group,
8817                                                 GtkWidget      *widget,
8818                                                 GdkDevice      *device)
8819 {
8820   GtkWindowGroupPrivate *priv;
8821   GtkDeviceGrabInfo *info;
8822   GdkDevice *other_device;
8823   GSList *list;
8824
8825   priv = window_group->priv;
8826   other_device = gdk_device_get_associated_device (device);
8827   list = priv->device_grabs;
8828
8829   while (list)
8830     {
8831       info = list->data;
8832       list = list->next;
8833
8834       /* Look for blocking grabs on other device pairs
8835        * that have the passed widget within the GTK+ grab.
8836        */
8837       if (info->block_others &&
8838           info->device != device &&
8839           info->device != other_device &&
8840           (info->widget == widget ||
8841            gtk_widget_is_ancestor (widget, info->widget)))
8842         return TRUE;
8843     }
8844
8845   return FALSE;
8846 }
8847
8848 /*
8849   Derived from XParseGeometry() in XFree86  
8850
8851   Copyright 1985, 1986, 1987,1998  The Open Group
8852
8853   All Rights Reserved.
8854
8855   The above copyright notice and this permission notice shall be included
8856   in all copies or substantial portions of the Software.
8857
8858   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
8859   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
8860   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
8861   IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
8862   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
8863   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
8864   OTHER DEALINGS IN THE SOFTWARE.
8865
8866   Except as contained in this notice, the name of The Open Group shall
8867   not be used in advertising or otherwise to promote the sale, use or
8868   other dealings in this Software without prior written authorization
8869   from The Open Group.
8870 */
8871
8872
8873 /*
8874  *    XParseGeometry parses strings of the form
8875  *   "=<width>x<height>{+-}<xoffset>{+-}<yoffset>", where
8876  *   width, height, xoffset, and yoffset are unsigned integers.
8877  *   Example:  "=80x24+300-49"
8878  *   The equal sign is optional.
8879  *   It returns a bitmask that indicates which of the four values
8880  *   were actually found in the string.  For each value found,
8881  *   the corresponding argument is updated;  for each value
8882  *   not found, the corresponding argument is left unchanged. 
8883  */
8884
8885 /* The following code is from Xlib, and is minimally modified, so we
8886  * can track any upstream changes if required.  Don't change this
8887  * code. Or if you do, put in a huge comment marking which thing
8888  * changed.
8889  */
8890
8891 static int
8892 read_int (gchar   *string,
8893           gchar  **next)
8894 {
8895   int result = 0;
8896   int sign = 1;
8897   
8898   if (*string == '+')
8899     string++;
8900   else if (*string == '-')
8901     {
8902       string++;
8903       sign = -1;
8904     }
8905
8906   for (; (*string >= '0') && (*string <= '9'); string++)
8907     {
8908       result = (result * 10) + (*string - '0');
8909     }
8910
8911   *next = string;
8912
8913   if (sign >= 0)
8914     return (result);
8915   else
8916     return (-result);
8917 }
8918
8919 /* 
8920  * Bitmask returned by XParseGeometry().  Each bit tells if the corresponding
8921  * value (x, y, width, height) was found in the parsed string.
8922  */
8923 #define NoValue         0x0000
8924 #define XValue          0x0001
8925 #define YValue          0x0002
8926 #define WidthValue      0x0004
8927 #define HeightValue     0x0008
8928 #define AllValues       0x000F
8929 #define XNegative       0x0010
8930 #define YNegative       0x0020
8931
8932 /* Try not to reformat/modify, so we can compare/sync with X sources */
8933 static int
8934 gtk_XParseGeometry (const char   *string,
8935                     int          *x,
8936                     int          *y,
8937                     unsigned int *width,   
8938                     unsigned int *height)  
8939 {
8940   int mask = NoValue;
8941   char *strind;
8942   unsigned int tempWidth, tempHeight;
8943   int tempX, tempY;
8944   char *nextCharacter;
8945
8946   /* These initializations are just to silence gcc */
8947   tempWidth = 0;
8948   tempHeight = 0;
8949   tempX = 0;
8950   tempY = 0;
8951   
8952   if ( (string == NULL) || (*string == '\0')) return(mask);
8953   if (*string == '=')
8954     string++;  /* ignore possible '=' at beg of geometry spec */
8955
8956   strind = (char *)string;
8957   if (*strind != '+' && *strind != '-' && *strind != 'x') {
8958     tempWidth = read_int(strind, &nextCharacter);
8959     if (strind == nextCharacter) 
8960       return (0);
8961     strind = nextCharacter;
8962     mask |= WidthValue;
8963   }
8964
8965   if (*strind == 'x' || *strind == 'X') {       
8966     strind++;
8967     tempHeight = read_int(strind, &nextCharacter);
8968     if (strind == nextCharacter)
8969       return (0);
8970     strind = nextCharacter;
8971     mask |= HeightValue;
8972   }
8973
8974   if ((*strind == '+') || (*strind == '-')) {
8975     if (*strind == '-') {
8976       strind++;
8977       tempX = -read_int(strind, &nextCharacter);
8978       if (strind == nextCharacter)
8979         return (0);
8980       strind = nextCharacter;
8981       mask |= XNegative;
8982
8983     }
8984     else
8985       { strind++;
8986       tempX = read_int(strind, &nextCharacter);
8987       if (strind == nextCharacter)
8988         return(0);
8989       strind = nextCharacter;
8990       }
8991     mask |= XValue;
8992     if ((*strind == '+') || (*strind == '-')) {
8993       if (*strind == '-') {
8994         strind++;
8995         tempY = -read_int(strind, &nextCharacter);
8996         if (strind == nextCharacter)
8997           return(0);
8998         strind = nextCharacter;
8999         mask |= YNegative;
9000
9001       }
9002       else
9003         {
9004           strind++;
9005           tempY = read_int(strind, &nextCharacter);
9006           if (strind == nextCharacter)
9007             return(0);
9008           strind = nextCharacter;
9009         }
9010       mask |= YValue;
9011     }
9012   }
9013         
9014   /* If strind isn't at the end of the string the it's an invalid
9015                 geometry specification. */
9016
9017   if (*strind != '\0') return (0);
9018
9019   if (mask & XValue)
9020     *x = tempX;
9021   if (mask & YValue)
9022     *y = tempY;
9023   if (mask & WidthValue)
9024     *width = tempWidth;
9025   if (mask & HeightValue)
9026     *height = tempHeight;
9027   return (mask);
9028 }
9029
9030 /**
9031  * gtk_window_parse_geometry:
9032  * @window: a #GtkWindow
9033  * @geometry: geometry string
9034  * 
9035  * Parses a standard X Window System geometry string - see the
9036  * manual page for X (type 'man X') for details on this.
9037  * gtk_window_parse_geometry() does work on all GTK+ ports
9038  * including Win32 but is primarily intended for an X environment.
9039  *
9040  * If either a size or a position can be extracted from the
9041  * geometry string, gtk_window_parse_geometry() returns %TRUE
9042  * and calls gtk_window_set_default_size() and/or gtk_window_move()
9043  * to resize/move the window.
9044  *
9045  * If gtk_window_parse_geometry() returns %TRUE, it will also
9046  * set the #GDK_HINT_USER_POS and/or #GDK_HINT_USER_SIZE hints
9047  * indicating to the window manager that the size/position of
9048  * the window was user-specified. This causes most window
9049  * managers to honor the geometry.
9050  *
9051  * Note that for gtk_window_parse_geometry() to work as expected, it has
9052  * to be called when the window has its "final" size, i.e. after calling
9053  * gtk_widget_show_all() on the contents and gtk_window_set_geometry_hints()
9054  * on the window.
9055  * |[
9056  * #include <gtk/gtk.h>
9057  *    
9058  * static void
9059  * fill_with_content (GtkWidget *vbox)
9060  * {
9061  *   /&ast; fill with content... &ast;/
9062  * }
9063  *    
9064  * int
9065  * main (int argc, char *argv[])
9066  * {
9067  *   GtkWidget *window, *vbox;
9068  *   GdkGeometry size_hints = {
9069  *     100, 50, 0, 0, 100, 50, 10, 10, 0.0, 0.0, GDK_GRAVITY_NORTH_WEST  
9070  *   };
9071  *    
9072  *   gtk_init (&argc, &argv);
9073  *   
9074  *   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
9075  *   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0);
9076  *   
9077  *   gtk_container_add (GTK_CONTAINER (window), vbox);
9078  *   fill_with_content (vbox);
9079  *   gtk_widget_show_all (vbox);
9080  *   
9081  *   gtk_window_set_geometry_hints (GTK_WINDOW (window),
9082  *                                  window,
9083  *                                  &size_hints,
9084  *                                  GDK_HINT_MIN_SIZE | 
9085  *                                  GDK_HINT_BASE_SIZE | 
9086  *                                  GDK_HINT_RESIZE_INC);
9087  *   
9088  *   if (argc &gt; 1)
9089  *     {
9090  *       if (!gtk_window_parse_geometry (GTK_WINDOW (window), argv[1]))
9091  *         fprintf (stderr, "Failed to parse '%s'\n", argv[1]);
9092  *     }
9093  *    
9094  *   gtk_widget_show_all (window);
9095  *   gtk_main ();
9096  *    
9097  *   return 0;
9098  * }
9099  * ]|
9100  *
9101  * Return value: %TRUE if string was parsed successfully
9102  **/
9103 gboolean
9104 gtk_window_parse_geometry (GtkWindow   *window,
9105                            const gchar *geometry)
9106 {
9107   gint result, x = 0, y = 0;
9108   guint w, h;
9109   GtkWidget *child;
9110   GdkGravity grav;
9111   gboolean size_set, pos_set;
9112   GdkScreen *screen;
9113   
9114   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
9115   g_return_val_if_fail (geometry != NULL, FALSE);
9116
9117   child = gtk_bin_get_child (GTK_BIN (window));
9118   if (!child || !gtk_widget_get_visible (child))
9119     g_warning ("gtk_window_parse_geometry() called on a window with no "
9120                "visible children; the window should be set up before "
9121                "gtk_window_parse_geometry() is called.");
9122
9123   screen = gtk_window_check_screen (window);
9124   
9125   result = gtk_XParseGeometry (geometry, &x, &y, &w, &h);
9126
9127   size_set = FALSE;
9128   if ((result & WidthValue) || (result & HeightValue))
9129     {
9130       gtk_window_set_default_size_internal (window, 
9131                                             TRUE, result & WidthValue ? w : -1,
9132                                             TRUE, result & HeightValue ? h : -1, 
9133                                             TRUE);
9134       size_set = TRUE;
9135     }
9136
9137   gtk_window_get_size (window, (gint *)&w, (gint *)&h);
9138   
9139   grav = GDK_GRAVITY_NORTH_WEST;
9140
9141   if ((result & XNegative) && (result & YNegative))
9142     grav = GDK_GRAVITY_SOUTH_EAST;
9143   else if (result & XNegative)
9144     grav = GDK_GRAVITY_NORTH_EAST;
9145   else if (result & YNegative)
9146     grav = GDK_GRAVITY_SOUTH_WEST;
9147
9148   if ((result & XValue) == 0)
9149     x = 0;
9150
9151   if ((result & YValue) == 0)
9152     y = 0;
9153
9154   if (grav == GDK_GRAVITY_SOUTH_WEST ||
9155       grav == GDK_GRAVITY_SOUTH_EAST)
9156     y = gdk_screen_get_height (screen) - h + y;
9157
9158   if (grav == GDK_GRAVITY_SOUTH_EAST ||
9159       grav == GDK_GRAVITY_NORTH_EAST)
9160     x = gdk_screen_get_width (screen) - w + x;
9161
9162   /* we don't let you put a window offscreen; maybe some people would
9163    * prefer to be able to, but it's kind of a bogus thing to do.
9164    */
9165   if (y < 0)
9166     y = 0;
9167
9168   if (x < 0)
9169     x = 0;
9170
9171   pos_set = FALSE;
9172   if ((result & XValue) || (result & YValue))
9173     {
9174       gtk_window_set_gravity (window, grav);
9175       gtk_window_move (window, x, y);
9176       pos_set = TRUE;
9177     }
9178
9179   if (size_set || pos_set)
9180     {
9181       /* Set USSize, USPosition hints */
9182       GtkWindowGeometryInfo *info;
9183
9184       info = gtk_window_get_geometry_info (window, TRUE);
9185
9186       if (pos_set)
9187         info->mask |= GDK_HINT_USER_POS;
9188       if (size_set)
9189         info->mask |= GDK_HINT_USER_SIZE;
9190     }
9191   
9192   return result != 0;
9193 }
9194
9195 static void
9196 gtk_window_mnemonic_hash_foreach (guint      keyval,
9197                                   GSList    *targets,
9198                                   gpointer   data)
9199 {
9200   struct {
9201     GtkWindow *window;
9202     GtkWindowKeysForeachFunc func;
9203     gpointer func_data;
9204   } *info = data;
9205
9206   (*info->func) (info->window, keyval, info->window->priv->mnemonic_modifier, TRUE, info->func_data);
9207 }
9208
9209 void
9210 _gtk_window_keys_foreach (GtkWindow                *window,
9211                           GtkWindowKeysForeachFunc func,
9212                           gpointer                 func_data)
9213 {
9214   GSList *groups;
9215   GtkMnemonicHash *mnemonic_hash;
9216
9217   struct {
9218     GtkWindow *window;
9219     GtkWindowKeysForeachFunc func;
9220     gpointer func_data;
9221   } info;
9222
9223   info.window = window;
9224   info.func = func;
9225   info.func_data = func_data;
9226
9227   mnemonic_hash = gtk_window_get_mnemonic_hash (window, FALSE);
9228   if (mnemonic_hash)
9229     _gtk_mnemonic_hash_foreach (mnemonic_hash,
9230                                 gtk_window_mnemonic_hash_foreach, &info);
9231
9232   groups = gtk_accel_groups_from_object (G_OBJECT (window));
9233   while (groups)
9234     {
9235       GtkAccelGroup *group = groups->data;
9236       gint i;
9237
9238       for (i = 0; i < group->priv->n_accels; i++)
9239         {
9240           GtkAccelKey *key = &group->priv->priv_accels[i].key;
9241           
9242           if (key->accel_key)
9243             (*func) (window, key->accel_key, key->accel_mods, FALSE, func_data);
9244         }
9245       
9246       groups = groups->next;
9247     }
9248 }
9249
9250 static void
9251 gtk_window_keys_changed (GtkWindow *window)
9252 {
9253   gtk_window_free_key_hash (window);
9254   gtk_window_get_key_hash (window);
9255 }
9256
9257 typedef struct _GtkWindowKeyEntry GtkWindowKeyEntry;
9258
9259 struct _GtkWindowKeyEntry
9260 {
9261   guint keyval;
9262   guint modifiers;
9263   guint is_mnemonic : 1;
9264 };
9265
9266 static void 
9267 window_key_entry_destroy (gpointer data)
9268 {
9269   g_slice_free (GtkWindowKeyEntry, data);
9270 }
9271
9272 static void
9273 add_to_key_hash (GtkWindow      *window,
9274                  guint           keyval,
9275                  GdkModifierType modifiers,
9276                  gboolean        is_mnemonic,
9277                  gpointer        data)
9278 {
9279   GtkKeyHash *key_hash = data;
9280
9281   GtkWindowKeyEntry *entry = g_slice_new (GtkWindowKeyEntry);
9282
9283   entry->keyval = keyval;
9284   entry->modifiers = modifiers;
9285   entry->is_mnemonic = is_mnemonic;
9286
9287   /* GtkAccelGroup stores lowercased accelerators. To deal
9288    * with this, if <Shift> was specified, uppercase.
9289    */
9290   if (modifiers & GDK_SHIFT_MASK)
9291     {
9292       if (keyval == GDK_KEY_Tab)
9293         keyval = GDK_KEY_ISO_Left_Tab;
9294       else
9295         keyval = gdk_keyval_to_upper (keyval);
9296     }
9297   
9298   _gtk_key_hash_add_entry (key_hash, keyval, entry->modifiers, entry);
9299 }
9300
9301 static GtkKeyHash *
9302 gtk_window_get_key_hash (GtkWindow *window)
9303 {
9304   GdkScreen *screen = gtk_window_check_screen (window);
9305   GtkKeyHash *key_hash = g_object_get_qdata (G_OBJECT (window), quark_gtk_window_key_hash);
9306   
9307   if (key_hash)
9308     return key_hash;
9309   
9310   key_hash = _gtk_key_hash_new (gdk_keymap_get_for_display (gdk_screen_get_display (screen)),
9311                                 (GDestroyNotify)window_key_entry_destroy);
9312   _gtk_window_keys_foreach (window, add_to_key_hash, key_hash);
9313   g_object_set_qdata (G_OBJECT (window), quark_gtk_window_key_hash, key_hash);
9314
9315   return key_hash;
9316 }
9317
9318 static void
9319 gtk_window_free_key_hash (GtkWindow *window)
9320 {
9321   GtkKeyHash *key_hash = g_object_get_qdata (G_OBJECT (window), quark_gtk_window_key_hash);
9322   if (key_hash)
9323     {
9324       _gtk_key_hash_free (key_hash);
9325       g_object_set_qdata (G_OBJECT (window), quark_gtk_window_key_hash, NULL);
9326     }
9327 }
9328
9329 /**
9330  * gtk_window_activate_key:
9331  * @window:  a #GtkWindow
9332  * @event:   a #GdkEventKey
9333  *
9334  * Activates mnemonics and accelerators for this #GtkWindow. This is normally
9335  * called by the default ::key_press_event handler for toplevel windows,
9336  * however in some cases it may be useful to call this directly when
9337  * overriding the standard key handling for a toplevel window.
9338  *
9339  * Return value: %TRUE if a mnemonic or accelerator was found and activated.
9340  *
9341  * Since: 2.4
9342  */
9343 gboolean
9344 gtk_window_activate_key (GtkWindow   *window,
9345                          GdkEventKey *event)
9346 {
9347   GtkKeyHash *key_hash;
9348   GtkWindowKeyEntry *found_entry = NULL;
9349   gboolean enable_mnemonics;
9350   gboolean enable_accels;
9351
9352   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
9353   g_return_val_if_fail (event != NULL, FALSE);
9354
9355   key_hash = gtk_window_get_key_hash (window);
9356
9357   if (key_hash)
9358     {
9359       GSList *tmp_list;
9360       GSList *entries = _gtk_key_hash_lookup (key_hash,
9361                                               event->hardware_keycode,
9362                                               event->state,
9363                                               gtk_accelerator_get_default_mod_mask (),
9364                                               event->group);
9365
9366       g_object_get (gtk_widget_get_settings (GTK_WIDGET (window)),
9367                     "gtk-enable-mnemonics", &enable_mnemonics,
9368                     "gtk-enable-accels", &enable_accels,
9369                     NULL);
9370
9371       for (tmp_list = entries; tmp_list; tmp_list = tmp_list->next)
9372         {
9373           GtkWindowKeyEntry *entry = tmp_list->data;
9374           if (entry->is_mnemonic)
9375             {
9376               if (enable_mnemonics)
9377                 {
9378                   found_entry = entry;
9379                   break;
9380                 }
9381             }
9382           else 
9383             {
9384               if (enable_accels && !found_entry)
9385                 {
9386                   found_entry = entry;
9387                 }
9388             }
9389         }
9390
9391       g_slist_free (entries);
9392     }
9393
9394   if (found_entry)
9395     {
9396       if (found_entry->is_mnemonic)
9397         {
9398           if (enable_mnemonics)
9399             return gtk_window_mnemonic_activate (window, found_entry->keyval,
9400                                                  found_entry->modifiers);
9401         }
9402       else
9403         {
9404           if (enable_accels)
9405             return gtk_accel_groups_activate (G_OBJECT (window), found_entry->keyval,
9406                                               found_entry->modifiers);
9407         }
9408     }
9409
9410   return FALSE;
9411 }
9412
9413 static void
9414 window_update_has_focus (GtkWindow *window)
9415 {
9416   GtkWindowPrivate *priv = window->priv;
9417   GtkWidget *widget = GTK_WIDGET (window);
9418   gboolean has_focus = priv->has_toplevel_focus && priv->is_active;
9419
9420   if (has_focus != priv->has_focus)
9421     {
9422       priv->has_focus = has_focus;
9423
9424       if (has_focus)
9425         {
9426           if (priv->focus_widget &&
9427               priv->focus_widget != widget &&
9428               !gtk_widget_has_focus (priv->focus_widget))
9429             do_focus_change (priv->focus_widget, TRUE);
9430         }
9431       else
9432         {
9433           if (priv->focus_widget &&
9434               priv->focus_widget != widget &&
9435               gtk_widget_has_focus (priv->focus_widget))
9436             do_focus_change (priv->focus_widget, FALSE);
9437         }
9438     }
9439 }
9440
9441 /**
9442  * _gtk_window_set_is_active:
9443  * @window: a #GtkWindow
9444  * @is_active: %TRUE if the window is in the currently active toplevel
9445  * 
9446  * Internal function that sets whether the #GtkWindow is part
9447  * of the currently active toplevel window (taking into account inter-process
9448  * embedding.)
9449  **/
9450 void
9451 _gtk_window_set_is_active (GtkWindow *window,
9452                            gboolean   is_active)
9453 {
9454   GtkWindowPrivate *priv;
9455
9456   g_return_if_fail (GTK_IS_WINDOW (window));
9457
9458   priv = window->priv;
9459
9460   is_active = is_active != FALSE;
9461
9462   if (is_active != priv->is_active)
9463     {
9464       priv->is_active = is_active;
9465       window_update_has_focus (window);
9466
9467       g_object_notify (G_OBJECT (window), "is-active");
9468     }
9469 }
9470
9471 /**
9472  * _gtk_window_set_is_toplevel:
9473  * @window: a #GtkWindow
9474  * @is_toplevel: %TRUE if the window is still a real toplevel (nominally a
9475  * child of the root window); %FALSE if it is not (for example, for an
9476  * in-process, parented GtkPlug)
9477  *
9478  * Internal function used by #GtkPlug when it gets parented/unparented by a
9479  * #GtkSocket.  This keeps the @window's #GTK_WINDOW_TOPLEVEL flag in sync
9480  * with the global list of toplevel windows.
9481  */
9482 void
9483 _gtk_window_set_is_toplevel (GtkWindow *window,
9484                              gboolean   is_toplevel)
9485 {
9486   GtkWidget *widget;
9487   GtkWidget *toplevel;
9488
9489   widget = GTK_WIDGET (window);
9490
9491   if (gtk_widget_is_toplevel (widget))
9492     g_assert (g_slist_find (toplevel_list, window) != NULL);
9493   else
9494     g_assert (g_slist_find (toplevel_list, window) == NULL);
9495
9496   if (is_toplevel == gtk_widget_is_toplevel (widget))
9497     return;
9498
9499   if (is_toplevel)
9500     {
9501       /* Pass through regular pathways of an embedded toplevel
9502        * to go through unmapping and hiding the widget before
9503        * becomming a toplevel again.
9504        *
9505        * We remain hidden after becomming toplevel in order to
9506        * avoid problems during an embedded toplevel's dispose cycle
9507        * (When a toplevel window is shown it tries to grab focus again,
9508        * this causes problems while disposing).
9509        */
9510       gtk_widget_hide (widget);
9511
9512       /* Save the toplevel this widget was previously anchored into before
9513        * propagating a hierarchy-changed.
9514        *
9515        * Usually this happens by way of gtk_widget_unparent() and we are
9516        * already unanchored at this point, just adding this clause incase
9517        * things happen differently.
9518        */
9519       toplevel = gtk_widget_get_toplevel (widget);
9520       if (!gtk_widget_is_toplevel (toplevel))
9521         toplevel = NULL;
9522
9523       _gtk_widget_set_is_toplevel (widget, TRUE);
9524
9525       /* When a window becomes toplevel after being embedded and anchored
9526        * into another window we need to unset its anchored flag so that
9527        * the hierarchy changed signal kicks in properly.
9528        */
9529       _gtk_widget_set_anchored (widget, FALSE);
9530       _gtk_widget_propagate_hierarchy_changed (widget, toplevel);
9531
9532       toplevel_list = g_slist_prepend (toplevel_list, window);
9533     }
9534   else
9535     {
9536       _gtk_widget_set_is_toplevel (widget, FALSE);
9537       toplevel_list = g_slist_remove (toplevel_list, window);
9538
9539       _gtk_widget_propagate_hierarchy_changed (widget, widget);
9540     }
9541 }
9542
9543 /**
9544  * _gtk_window_set_has_toplevel_focus:
9545  * @window: a #GtkWindow
9546  * @has_toplevel_focus: %TRUE if the in
9547  * 
9548  * Internal function that sets whether the keyboard focus for the
9549  * toplevel window (taking into account inter-process embedding.)
9550  **/
9551 void
9552 _gtk_window_set_has_toplevel_focus (GtkWindow *window,
9553                                    gboolean   has_toplevel_focus)
9554 {
9555   GtkWindowPrivate *priv;
9556
9557   g_return_if_fail (GTK_IS_WINDOW (window));
9558
9559   priv = window->priv;
9560
9561   has_toplevel_focus = has_toplevel_focus != FALSE;
9562
9563   if (has_toplevel_focus != priv->has_toplevel_focus)
9564     {
9565       priv->has_toplevel_focus = has_toplevel_focus;
9566       window_update_has_focus (window);
9567
9568       g_object_notify (G_OBJECT (window), "has-toplevel-focus");
9569     }
9570 }
9571
9572 /**
9573  * gtk_window_set_auto_startup_notification:
9574  * @setting: %TRUE to automatically do startup notification
9575  *
9576  * By default, after showing the first #GtkWindow, GTK+ calls 
9577  * gdk_notify_startup_complete().  Call this function to disable 
9578  * the automatic startup notification. You might do this if your 
9579  * first window is a splash screen, and you want to delay notification 
9580  * until after your real main window has been shown, for example.
9581  *
9582  * In that example, you would disable startup notification
9583  * temporarily, show your splash screen, then re-enable it so that
9584  * showing the main window would automatically result in notification.
9585  * 
9586  * Since: 2.2
9587  **/
9588 void
9589 gtk_window_set_auto_startup_notification (gboolean setting)
9590 {
9591   disable_startup_notification = !setting;
9592 }
9593
9594 /**
9595  * gtk_window_get_window_type:
9596  * @window: a #GtkWindow
9597  *
9598  * Gets the type of the window. See #GtkWindowType.
9599  *
9600  * Return value: the type of the window
9601  *
9602  * Since: 2.20
9603  **/
9604 GtkWindowType
9605 gtk_window_get_window_type (GtkWindow *window)
9606 {
9607   g_return_val_if_fail (GTK_IS_WINDOW (window), GTK_WINDOW_TOPLEVEL);
9608
9609   return window->priv->type;
9610 }
9611
9612 /**
9613  * gtk_window_get_mnemonics_visible:
9614  * @window: a #GtkWindow
9615  *
9616  * Gets the value of the #GtkWindow:mnemonics-visible property.
9617  *
9618  * Returns: %TRUE if mnemonics are supposed to be visible
9619  * in this window.
9620  *
9621  * Since: 2.20
9622  */
9623 gboolean
9624 gtk_window_get_mnemonics_visible (GtkWindow *window)
9625 {
9626   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
9627
9628   return window->priv->mnemonics_visible;
9629 }
9630
9631 /**
9632  * gtk_window_set_mnemonics_visible:
9633  * @window: a #GtkWindow
9634  * @setting: the new value
9635  *
9636  * Sets the #GtkWindow:mnemonics-visible property.
9637  *
9638  * Since: 2.20
9639  */
9640 void
9641 gtk_window_set_mnemonics_visible (GtkWindow *window,
9642                                   gboolean   setting)
9643 {
9644   GtkWindowPrivate *priv;
9645
9646   g_return_if_fail (GTK_IS_WINDOW (window));
9647
9648   priv = window->priv;
9649
9650   setting = setting != FALSE;
9651
9652   if (priv->mnemonics_visible != setting)
9653     {
9654       priv->mnemonics_visible = setting;
9655       g_object_notify (G_OBJECT (window), "mnemonics-visible");
9656     }
9657
9658   if (priv->auto_mnemonics_timeout_id)
9659     {
9660       g_source_remove (priv->auto_mnemonics_timeout_id);
9661       priv->auto_mnemonics_timeout_id = 0;
9662     }
9663
9664   priv->mnemonics_visible_set = TRUE;
9665 }
9666
9667 static gboolean
9668 set_auto_mnemonics_visible_cb (gpointer data)
9669 {
9670   GtkWindow *window = data;
9671
9672   gtk_window_set_mnemonics_visible (window, TRUE);
9673
9674   window->priv->auto_mnemonics_timeout_id = 0;
9675
9676   return FALSE;
9677 }
9678
9679 void
9680 _gtk_window_set_auto_mnemonics_visible (GtkWindow *window)
9681 {
9682   g_return_if_fail (GTK_IS_WINDOW (window));
9683
9684   if (window->priv->auto_mnemonics_timeout_id)
9685     return;
9686
9687   window->priv->auto_mnemonics_timeout_id =
9688     gdk_threads_add_timeout (AUTO_MNEMONICS_DELAY, set_auto_mnemonics_visible_cb, window);
9689 }
9690
9691 /**
9692  * gtk_window_get_focus_visible:
9693  * @window: a #GtkWindow
9694  *
9695  * Gets the value of the #GtkWindow:focus-visible property.
9696  *
9697  * Returns: %TRUE if 'focus rectangles' are supposed to be visible
9698  *     in this window.
9699  *
9700  * Since: 3.2
9701  */
9702 gboolean
9703 gtk_window_get_focus_visible (GtkWindow *window)
9704 {
9705   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
9706
9707   return window->priv->focus_visible;
9708 }
9709
9710 /**
9711  * gtk_window_set_focus_visible:
9712  * @window: a #GtkWindow
9713  * @setting: the new value
9714  *
9715  * Sets the #GtkWindow:focus-visible property.
9716  *
9717  * Since: 3.2
9718  */
9719 void
9720 gtk_window_set_focus_visible (GtkWindow *window,
9721                               gboolean   setting)
9722 {
9723   GtkWindowPrivate *priv;
9724
9725   g_return_if_fail (GTK_IS_WINDOW (window));
9726
9727   priv = window->priv;
9728
9729   setting = setting != FALSE;
9730
9731   if (priv->focus_visible != setting)
9732     {
9733       priv->focus_visible = setting;
9734       g_object_notify (G_OBJECT (window), "focus-visible");
9735     }
9736 }
9737
9738 void
9739 _gtk_window_get_wmclass (GtkWindow  *window,
9740                          gchar     **wmclass_name,
9741                          gchar     **wmclass_class)
9742 {
9743   GtkWindowPrivate *priv = window->priv;
9744
9745   *wmclass_name = priv->wmclass_name;
9746   *wmclass_class = priv->wmclass_class;
9747 }
9748
9749 /**
9750  * gtk_window_set_has_user_ref_count:
9751  * @window: a #GtkWindow
9752  * @setting: the new value
9753  *
9754  * Tells GTK+ whether to drop its extra reference to the window
9755  * when gtk_widget_destroy() is called.
9756  *
9757  * This function is only exported for the benefit of language
9758  * bindings which may need to keep the window alive until their
9759  * wrapper object is garbage collected. There is no justification
9760  * for ever calling this function in an application.
9761  *
9762  * Since: 3.0
9763  */
9764 void
9765 gtk_window_set_has_user_ref_count (GtkWindow *window,
9766                                    gboolean   setting)
9767 {
9768   g_return_if_fail (GTK_IS_WINDOW (window));
9769
9770   window->priv->has_user_ref_count = setting;
9771 }
9772
9773 static void
9774 ensure_state_flag_backdrop (GtkWidget *widget)
9775 {
9776   GdkWindow *window;
9777   gboolean window_focused = TRUE;
9778
9779   window = gtk_widget_get_window (widget);
9780
9781   window_focused = gdk_window_get_state (window) & GDK_WINDOW_STATE_FOCUSED;
9782
9783   if (!window_focused)
9784     gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_BACKDROP, FALSE);
9785   else
9786     gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_BACKDROP);
9787
9788   gtk_widget_queue_draw (widget);
9789 }