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