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