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