]> Pileus Git - ~andy/gtk/blob - gtk/gtkwindow.c
Always chain up in ::style-updated
[~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   GTK_WIDGET_CLASS (gtk_window_parent_class)->style_updated (widget);
5345
5346   if (priv->grip_window != NULL && gtk_window_get_resize_grip_area (window, &rect))
5347     {
5348       gdk_window_move_resize (priv->grip_window,
5349                               rect.x, rect.y,
5350                               rect.width, rect.height);
5351
5352       set_grip_shape (window);
5353       gtk_widget_queue_resize (widget);
5354     }
5355 }
5356
5357 static void
5358 resize_grip_create_window (GtkWindow *window)
5359 {
5360   GtkWidget *widget;
5361   GtkWindowPrivate *priv;
5362   GdkWindowAttr attributes;
5363   gint attributes_mask;
5364   GdkRectangle rect;
5365
5366   priv = window->priv;
5367   widget = GTK_WIDGET (window);
5368
5369   g_return_if_fail (gtk_widget_get_realized (widget));
5370   g_return_if_fail (priv->grip_window == NULL);
5371
5372   gtk_window_get_resize_grip_area (window, &rect);
5373
5374   attributes.x = rect.x;
5375   attributes.y = rect.y;
5376   attributes.width = rect.width;
5377   attributes.height = rect.height;
5378   attributes.window_type = GDK_WINDOW_CHILD;
5379   attributes.wclass = GDK_INPUT_OUTPUT;
5380   attributes.event_mask = gtk_widget_get_events (widget) |
5381                           GDK_EXPOSURE_MASK |
5382                           GDK_BUTTON_PRESS_MASK;
5383
5384   attributes_mask = GDK_WA_X | GDK_WA_Y;
5385
5386   priv->grip_window = gdk_window_new (gtk_widget_get_window (widget),
5387                                       &attributes,
5388                                       attributes_mask);
5389
5390   gdk_window_set_user_data (priv->grip_window, widget);
5391
5392   gdk_window_raise (priv->grip_window);
5393
5394   set_grip_shape (window);
5395   update_grip_visibility (window);
5396 }
5397
5398 static void
5399 resize_grip_destroy_window (GtkWindow *window)
5400 {
5401   GtkWindowPrivate *priv = window->priv;
5402
5403   gdk_window_set_user_data (priv->grip_window, NULL);
5404   gdk_window_destroy (priv->grip_window);
5405   priv->grip_window = NULL;
5406   update_grip_visibility (window);
5407 }
5408
5409 /**
5410  * gtk_window_set_has_resize_grip:
5411  * @window: a #GtkWindow
5412  * @value: %TRUE to allow a resize grip
5413  *
5414  * Sets whether @window has a corner resize grip.
5415  *
5416  * Note that the resize grip is only shown if the window
5417  * is actually resizable and not maximized. Use
5418  * gtk_window_resize_grip_is_visible() to find out if the
5419  * resize grip is currently shown.
5420  *
5421  * Since: 3.0
5422  */
5423 void
5424 gtk_window_set_has_resize_grip (GtkWindow *window,
5425                                 gboolean   value)
5426 {
5427   GtkWidget *widget = GTK_WIDGET (window);
5428   GtkWindowPrivate *priv = window->priv;
5429
5430   value = value != FALSE;
5431
5432   if (value != priv->has_resize_grip)
5433     {
5434       priv->has_resize_grip = value;
5435       gtk_widget_queue_draw (widget);
5436
5437       if (gtk_widget_get_realized (widget) && 
5438           gtk_widget_is_toplevel (GTK_WIDGET (widget)))
5439         {
5440           if (priv->has_resize_grip && priv->grip_window == NULL)
5441             resize_grip_create_window (window);
5442           else if (!priv->has_resize_grip && priv->grip_window != NULL)
5443             resize_grip_destroy_window (window);
5444         }
5445
5446       g_object_notify (G_OBJECT (window), "has-resize-grip");
5447     }
5448 }
5449
5450 static void
5451 update_grip_visibility (GtkWindow *window)
5452 {
5453   GtkWindowPrivate *priv = window->priv;
5454   gboolean val;
5455
5456   val = gtk_window_resize_grip_is_visible (window);
5457
5458   if (priv->grip_window != NULL)
5459     {
5460       if (val)
5461         {
5462           gdk_window_show (priv->grip_window);
5463           set_grip_cursor (window);
5464         }
5465       else
5466         {
5467           gdk_window_hide (priv->grip_window);
5468         }
5469     }
5470
5471   if (priv->resize_grip_visible != val)
5472     {
5473       priv->resize_grip_visible = val;
5474
5475       g_object_notify (G_OBJECT (window), "resize-grip-visible");
5476     }
5477 }
5478
5479 /**
5480  * gtk_window_resize_grip_is_visible:
5481  * @window: a #GtkWindow
5482  *
5483  * Determines whether a resize grip is visible for the specified window.
5484  *
5485  * Returns: %TRUE if a resize grip exists and is visible
5486  *
5487  * Since: 3.0
5488  */
5489 gboolean
5490 gtk_window_resize_grip_is_visible (GtkWindow *window)
5491 {
5492   GtkWidget *widget;
5493   GtkWindowPrivate *priv;
5494   GdkWindowEdge edge;
5495
5496   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
5497
5498   priv = window->priv;
5499   widget = GTK_WIDGET (window);
5500
5501   if (priv->type == GTK_WINDOW_POPUP)
5502     return FALSE;
5503
5504   if (!priv->resizable)
5505     return FALSE;
5506
5507   if (!gtk_widget_is_toplevel (GTK_WIDGET (widget)))
5508     return FALSE;
5509
5510   if (gtk_widget_get_realized (widget))
5511     {
5512       GdkWindowState state;
5513
5514       state = gdk_window_get_state (gtk_widget_get_window (widget));
5515
5516       if (state & GDK_WINDOW_STATE_MAXIMIZED || state & GDK_WINDOW_STATE_FULLSCREEN)
5517         return FALSE;
5518     }
5519
5520   if (!get_drag_edge (widget, &edge))
5521     return FALSE;
5522
5523   return window->priv->has_resize_grip;
5524 }
5525
5526 /**
5527  * gtk_window_get_has_resize_grip:
5528  * @window: a #GtkWindow
5529  *
5530  * Determines whether the window may have a resize grip.
5531  *
5532  * Returns: %TRUE if the window has a resize grip
5533  *
5534  * Since: 3.0
5535  */
5536 gboolean
5537 gtk_window_get_has_resize_grip (GtkWindow *window)
5538 {
5539   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
5540
5541   return window->priv->has_resize_grip;
5542 }
5543
5544 /**
5545  * gtk_window_get_resize_grip_area:
5546  * @window: a #GtkWindow
5547  * @rect: (out): a pointer to a #GdkRectangle which we should store
5548  *     the resize grip area
5549  *
5550  * If a window has a resize grip, this will retrieve the grip
5551  * position, width and height into the specified #GdkRectangle.
5552  *
5553  * Returns: %TRUE if the resize grip's area was retrieved
5554  *
5555  * Since: 3.0
5556  */
5557 gboolean
5558 gtk_window_get_resize_grip_area (GtkWindow *window,
5559                                  GdkRectangle *rect)
5560 {
5561   GtkWidget *widget = GTK_WIDGET (window);
5562   GtkAllocation allocation;
5563   gint grip_width;
5564   gint grip_height;
5565
5566   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
5567
5568   if (!window->priv->has_resize_grip)
5569     return FALSE;
5570
5571   gtk_widget_get_allocation (widget, &allocation);
5572
5573   gtk_widget_style_get (widget,
5574                         "resize-grip-width", &grip_width,
5575                         "resize-grip-height", &grip_height,
5576                         NULL);
5577
5578   if (grip_width > allocation.width)
5579     grip_width = allocation.width;
5580
5581   if (grip_height > allocation.height)
5582     grip_height = allocation.height;
5583
5584   rect->width = grip_width;
5585   rect->height = grip_height;
5586   rect->y = allocation.y + allocation.height - grip_height;
5587
5588   if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
5589     rect->x = allocation.x + allocation.width - grip_width;
5590   else
5591     rect->x = allocation.x;
5592
5593   return TRUE;
5594 }
5595
5596 /* the accel_key and accel_mods fields of the key have to be setup
5597  * upon calling this function. it'll then return whether that key
5598  * is at all used as accelerator, and if so will OR in the
5599  * accel_flags member of the key.
5600  */
5601 gboolean
5602 _gtk_window_query_nonaccels (GtkWindow      *window,
5603                              guint           accel_key,
5604                              GdkModifierType accel_mods)
5605 {
5606   GtkWindowPrivate *priv;
5607
5608   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
5609
5610   priv = window->priv;
5611
5612   /* movement keys are considered locked accels */
5613   if (!accel_mods)
5614     {
5615       static const guint bindings[] = {
5616         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,
5617         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,
5618       };
5619       guint i;
5620       
5621       for (i = 0; i < G_N_ELEMENTS (bindings); i++)
5622         if (bindings[i] == accel_key)
5623           return TRUE;
5624     }
5625
5626   /* mnemonics are considered locked accels */
5627   if (accel_mods == priv->mnemonic_modifier)
5628     {
5629       GtkMnemonicHash *mnemonic_hash = gtk_window_get_mnemonic_hash (window, FALSE);
5630       if (mnemonic_hash && _gtk_mnemonic_hash_lookup (mnemonic_hash, accel_key))
5631         return TRUE;
5632     }
5633
5634   return FALSE;
5635 }
5636
5637 /**
5638  * gtk_window_propagate_key_event:
5639  * @window:  a #GtkWindow
5640  * @event:   a #GdkEventKey
5641  *
5642  * Propagate a key press or release event to the focus widget and
5643  * up the focus container chain until a widget handles @event.
5644  * This is normally called by the default ::key_press_event and
5645  * ::key_release_event handlers for toplevel windows,
5646  * however in some cases it may be useful to call this directly when
5647  * overriding the standard key handling for a toplevel window.
5648  *
5649  * Return value: %TRUE if a widget in the focus chain handled the event.
5650  *
5651  * Since: 2.4
5652  */
5653 gboolean
5654 gtk_window_propagate_key_event (GtkWindow        *window,
5655                                 GdkEventKey      *event)
5656 {
5657   GtkWindowPrivate *priv;
5658   gboolean handled = FALSE;
5659   GtkWidget *widget, *focus;
5660
5661   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
5662
5663   priv = window->priv;
5664   widget = GTK_WIDGET (window);
5665
5666   focus = priv->focus_widget;
5667   if (focus)
5668     g_object_ref (focus);
5669   
5670   while (!handled &&
5671          focus && focus != widget &&
5672          gtk_widget_get_toplevel (focus) == widget)
5673     {
5674       GtkWidget *parent;
5675       
5676       if (gtk_widget_is_sensitive (focus))
5677         handled = gtk_widget_event (focus, (GdkEvent*) event);
5678
5679       parent = gtk_widget_get_parent (focus);
5680       if (parent)
5681         g_object_ref (parent);
5682       
5683       g_object_unref (focus);
5684       
5685       focus = parent;
5686     }
5687   
5688   if (focus)
5689     g_object_unref (focus);
5690
5691   return handled;
5692 }
5693
5694 static gint
5695 gtk_window_key_press_event (GtkWidget   *widget,
5696                             GdkEventKey *event)
5697 {
5698   GtkWindow *window = GTK_WINDOW (widget);
5699   gboolean handled = FALSE;
5700
5701   /* handle mnemonics and accelerators */
5702   if (!handled)
5703     handled = gtk_window_activate_key (window, event);
5704
5705   /* handle focus widget key events */
5706   if (!handled)
5707     handled = gtk_window_propagate_key_event (window, event);
5708
5709   /* Chain up, invokes binding set */
5710   if (!handled)
5711     handled = GTK_WIDGET_CLASS (gtk_window_parent_class)->key_press_event (widget, event);
5712
5713   return handled;
5714 }
5715
5716 static gint
5717 gtk_window_key_release_event (GtkWidget   *widget,
5718                               GdkEventKey *event)
5719 {
5720   GtkWindow *window = GTK_WINDOW (widget);
5721   gboolean handled = FALSE;
5722
5723   /* handle focus widget key events */
5724   if (!handled)
5725     handled = gtk_window_propagate_key_event (window, event);
5726
5727   /* Chain up, invokes binding set */
5728   if (!handled)
5729     handled = GTK_WIDGET_CLASS (gtk_window_parent_class)->key_release_event (widget, event);
5730
5731   return handled;
5732 }
5733
5734 static gint
5735 gtk_window_button_press_event (GtkWidget *widget,
5736                                GdkEventButton *event)
5737 {
5738   GtkWindowPrivate *priv = GTK_WINDOW (widget)->priv;
5739   GdkWindowEdge edge;
5740
5741   if (event->window == priv->grip_window)
5742     {
5743       if (get_drag_edge (widget, &edge))
5744         gtk_window_begin_resize_drag (GTK_WINDOW (widget),
5745                                       edge,
5746                                       event->button,
5747                                       event->x_root,
5748                                       event->y_root,
5749                                       event->time);
5750
5751       return TRUE;
5752     }
5753
5754   return FALSE;
5755 }
5756
5757 static void
5758 gtk_window_real_activate_default (GtkWindow *window)
5759 {
5760   gtk_window_activate_default (window);
5761 }
5762
5763 static void
5764 gtk_window_real_activate_focus (GtkWindow *window)
5765 {
5766   gtk_window_activate_focus (window);
5767 }
5768
5769 static gint
5770 gtk_window_enter_notify_event (GtkWidget        *widget,
5771                                GdkEventCrossing *event)
5772 {
5773   return FALSE;
5774 }
5775
5776 static gint
5777 gtk_window_leave_notify_event (GtkWidget        *widget,
5778                                GdkEventCrossing *event)
5779 {
5780   return FALSE;
5781 }
5782
5783 static void
5784 do_focus_change (GtkWidget *widget,
5785                  gboolean   in)
5786 {
5787   GdkWindow *window;
5788   GdkDeviceManager *device_manager;
5789   GList *devices, *d;
5790
5791   g_object_ref (widget);
5792
5793   device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
5794   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
5795   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
5796   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
5797
5798   for (d = devices; d; d = d->next)
5799     {
5800       GdkDevice *dev = d->data;
5801       GdkEvent *fevent;
5802
5803       if (gdk_device_get_source (dev) != GDK_SOURCE_KEYBOARD)
5804         continue;
5805
5806       /* Skip non-master keyboards that haven't
5807        * selected for events from this window
5808        */
5809       window = gtk_widget_get_window (widget);
5810       if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
5811           window && !gdk_window_get_device_events (window, dev))
5812         continue;
5813
5814       fevent = gdk_event_new (GDK_FOCUS_CHANGE);
5815
5816       fevent->focus_change.type = GDK_FOCUS_CHANGE;
5817       fevent->focus_change.window = window;
5818       if (window)
5819         g_object_ref (window);
5820       fevent->focus_change.in = in;
5821       gdk_event_set_device (fevent, dev);
5822
5823       gtk_widget_send_focus_change (widget, fevent);
5824
5825       gdk_event_free (fevent);
5826     }
5827
5828   g_list_free (devices);
5829   g_object_unref (widget);
5830 }
5831
5832 static gint
5833 gtk_window_focus_in_event (GtkWidget     *widget,
5834                            GdkEventFocus *event)
5835 {
5836   GtkWindow *window = GTK_WINDOW (widget);
5837
5838   /* It appears spurious focus in events can occur when
5839    *  the window is hidden. So we'll just check to see if
5840    *  the window is visible before actually handling the
5841    *  event
5842    */
5843   if (gtk_widget_get_visible (widget))
5844     {
5845       _gtk_window_set_has_toplevel_focus (window, TRUE);
5846       _gtk_window_set_is_active (window, TRUE);
5847     }
5848       
5849   return FALSE;
5850 }
5851
5852 static gint
5853 gtk_window_focus_out_event (GtkWidget     *widget,
5854                             GdkEventFocus *event)
5855 {
5856   GtkWindow *window = GTK_WINDOW (widget);
5857   gboolean auto_mnemonics;
5858
5859   _gtk_window_set_has_toplevel_focus (window, FALSE);
5860   _gtk_window_set_is_active (window, FALSE);
5861
5862   /* set the mnemonic-visible property to false */
5863   g_object_get (gtk_widget_get_settings (widget),
5864                 "gtk-auto-mnemonics", &auto_mnemonics, NULL);
5865   if (auto_mnemonics)
5866     gtk_window_set_mnemonics_visible (window, FALSE);
5867
5868   return FALSE;
5869 }
5870
5871 static void
5872 gtk_window_check_resize (GtkContainer *container)
5873 {
5874   /* If the window is not toplevel anymore than it's embedded somewhere,
5875    * so handle it like a normal window */
5876   if (!gtk_widget_is_toplevel (GTK_WIDGET (container)))
5877     GTK_CONTAINER_CLASS (gtk_window_parent_class)->check_resize (container);
5878   else if (gtk_widget_get_visible (GTK_WIDGET (container)))
5879     gtk_window_move_resize (GTK_WINDOW (container));
5880 }
5881
5882 static gboolean
5883 gtk_window_focus (GtkWidget        *widget,
5884                   GtkDirectionType  direction)
5885 {
5886   GtkWindowPrivate *priv;
5887   GtkBin *bin;
5888   GtkWindow *window;
5889   GtkContainer *container;
5890   GtkWidget *child;
5891   GtkWidget *old_focus_child;
5892   GtkWidget *parent;
5893
5894   if (!gtk_widget_is_toplevel (GTK_WIDGET (widget)))
5895     return GTK_WIDGET_CLASS (gtk_window_parent_class)->focus (widget, direction);
5896
5897   container = GTK_CONTAINER (widget);
5898   window = GTK_WINDOW (widget);
5899   priv = window->priv;
5900   bin = GTK_BIN (widget);
5901
5902   old_focus_child = gtk_container_get_focus_child (container);
5903   
5904   /* We need a special implementation here to deal properly with wrapping
5905    * around in the tab chain without the danger of going into an
5906    * infinite loop.
5907    */
5908   if (old_focus_child)
5909     {
5910       if (gtk_widget_child_focus (old_focus_child, direction))
5911         return TRUE;
5912     }
5913
5914   if (priv->focus_widget)
5915     {
5916       if (direction == GTK_DIR_LEFT ||
5917           direction == GTK_DIR_RIGHT ||
5918           direction == GTK_DIR_UP ||
5919           direction == GTK_DIR_DOWN)
5920         {
5921           return FALSE;
5922         }
5923       
5924       /* Wrapped off the end, clear the focus setting for the toplpevel */
5925       parent = gtk_widget_get_parent (priv->focus_widget);
5926       while (parent)
5927         {
5928           gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
5929           parent = gtk_widget_get_parent (parent);
5930         }
5931       
5932       gtk_window_set_focus (GTK_WINDOW (container), NULL);
5933     }
5934
5935   /* Now try to focus the first widget in the window */
5936   child = gtk_bin_get_child (bin);
5937   if (child)
5938     {
5939       if (gtk_widget_child_focus (child, direction))
5940         return TRUE;
5941     }
5942
5943   return FALSE;
5944 }
5945
5946 static void
5947 gtk_window_move_focus (GtkWidget       *widget,
5948                        GtkDirectionType dir)
5949 {
5950   if (!gtk_widget_is_toplevel (GTK_WIDGET (widget)))
5951     {
5952       GTK_WIDGET_CLASS (gtk_window_parent_class)->move_focus (widget, dir);
5953       return;
5954     }
5955
5956   gtk_widget_child_focus (widget, dir);
5957
5958   if (! gtk_container_get_focus_child (GTK_CONTAINER (widget)))
5959     gtk_window_set_focus (GTK_WINDOW (widget), NULL);
5960 }
5961
5962 static void
5963 gtk_window_real_set_focus (GtkWindow *window,
5964                            GtkWidget *focus)
5965 {
5966   GtkWindowPrivate *priv = window->priv;
5967   GtkWidget *old_focus = priv->focus_widget;
5968   gboolean had_default = FALSE;
5969   gboolean focus_had_default = FALSE;
5970   gboolean old_focus_had_default = FALSE;
5971
5972   if (old_focus)
5973     {
5974       g_object_ref (old_focus);
5975       g_object_freeze_notify (G_OBJECT (old_focus));
5976       old_focus_had_default = gtk_widget_has_default (old_focus);
5977     }
5978   if (focus)
5979     {
5980       g_object_ref (focus);
5981       g_object_freeze_notify (G_OBJECT (focus));
5982       focus_had_default = gtk_widget_has_default (focus);
5983     }
5984
5985   if (priv->default_widget)
5986     had_default = gtk_widget_has_default (priv->default_widget);
5987
5988   if (priv->focus_widget)
5989     {
5990       if (gtk_widget_get_receives_default (priv->focus_widget) &&
5991           (priv->focus_widget != priv->default_widget))
5992         {
5993           _gtk_widget_set_has_default (priv->focus_widget, FALSE);
5994           gtk_widget_queue_draw (priv->focus_widget);
5995
5996           if (priv->default_widget)
5997             _gtk_widget_set_has_default (priv->default_widget, TRUE);
5998         }
5999
6000       priv->focus_widget = NULL;
6001
6002       if (priv->has_focus)
6003         do_focus_change (old_focus, FALSE);
6004
6005       g_object_notify (G_OBJECT (old_focus), "is-focus");
6006     }
6007
6008   /* The above notifications may have set a new focus widget,
6009    * if so, we don't want to override it.
6010    */
6011   if (focus && !priv->focus_widget)
6012     {
6013       priv->focus_widget = focus;
6014
6015       if (gtk_widget_get_receives_default (priv->focus_widget) &&
6016           (priv->focus_widget != priv->default_widget))
6017         {
6018           if (gtk_widget_get_can_default (priv->focus_widget))
6019             _gtk_widget_set_has_default (priv->focus_widget, TRUE);
6020
6021           if (priv->default_widget)
6022             _gtk_widget_set_has_default (priv->default_widget, FALSE);
6023         }
6024
6025       if (priv->has_focus)
6026         do_focus_change (priv->focus_widget, TRUE);
6027
6028       g_object_notify (G_OBJECT (priv->focus_widget), "is-focus");
6029     }
6030
6031   /* If the default widget changed, a redraw will have been queued
6032    * on the old and new default widgets by gtk_window_set_default(), so
6033    * we only have to worry about the case where it didn't change.
6034    * We'll sometimes queue a draw twice on the new widget but that
6035    * is harmless.
6036    */
6037   if (priv->default_widget &&
6038       (had_default != gtk_widget_has_default (priv->default_widget)))
6039     gtk_widget_queue_draw (priv->default_widget);
6040   
6041   if (old_focus)
6042     {
6043       if (old_focus_had_default != gtk_widget_has_default (old_focus))
6044         gtk_widget_queue_draw (old_focus);
6045         
6046       g_object_thaw_notify (G_OBJECT (old_focus));
6047       g_object_unref (old_focus);
6048     }
6049   if (focus)
6050     {
6051       if (focus_had_default != gtk_widget_has_default (focus))
6052         gtk_widget_queue_draw (focus);
6053
6054       g_object_thaw_notify (G_OBJECT (focus));
6055       g_object_unref (focus);
6056     }
6057 }
6058
6059
6060 static void 
6061 gtk_window_get_preferred_width (GtkWidget *widget,
6062                                 gint      *minimum_size,
6063                                 gint      *natural_size)
6064 {
6065   GtkWindow *window;
6066   GtkWidget *child;
6067   guint border_width;
6068
6069   window = GTK_WINDOW (widget);
6070   child  = gtk_bin_get_child (GTK_BIN (window));
6071
6072   border_width = gtk_container_get_border_width (GTK_CONTAINER (window));
6073   *minimum_size = border_width * 2;
6074   *natural_size = border_width * 2;
6075
6076   if (child && gtk_widget_get_visible (child))
6077     {
6078       gint child_min, child_nat;
6079       gtk_widget_get_preferred_width (child, &child_min, &child_nat);
6080
6081       *minimum_size += child_min;
6082       *natural_size += child_nat;
6083     }
6084 }
6085
6086 static void 
6087 gtk_window_get_preferred_height (GtkWidget *widget,
6088                                  gint      *minimum_size,
6089                                  gint      *natural_size)
6090 {
6091   GtkWindow *window;
6092   GtkWidget *child;
6093   guint border_width;
6094
6095   window = GTK_WINDOW (widget);
6096   child  = gtk_bin_get_child (GTK_BIN (window));
6097
6098   border_width = gtk_container_get_border_width (GTK_CONTAINER (window));
6099   *minimum_size = border_width * 2;
6100   *natural_size = border_width * 2;
6101
6102   if (child && gtk_widget_get_visible (child))
6103     {
6104       gint child_min, child_nat;
6105       gtk_widget_get_preferred_height (child, &child_min, &child_nat);
6106
6107       *minimum_size += child_min;
6108       *natural_size += child_nat;
6109     }
6110 }
6111
6112
6113 /**
6114  * _gtk_window_unset_focus_and_default:
6115  * @window: a #GtkWindow
6116  * @widget: a widget inside of @window
6117  * 
6118  * Checks whether the focus and default widgets of @window are
6119  * @widget or a descendent of @widget, and if so, unset them.
6120  **/
6121 void
6122 _gtk_window_unset_focus_and_default (GtkWindow *window,
6123                                      GtkWidget *widget)
6124
6125 {
6126   GtkWindowPrivate *priv = window->priv;
6127   GtkWidget *child;
6128   GtkWidget *parent;
6129
6130   g_object_ref (window);
6131   g_object_ref (widget);
6132
6133   parent = gtk_widget_get_parent (widget);
6134   if (gtk_container_get_focus_child (GTK_CONTAINER (parent)) == widget)
6135     {
6136       child = priv->focus_widget;
6137       
6138       while (child && child != widget)
6139         child = gtk_widget_get_parent (child);
6140
6141       if (child == widget)
6142         gtk_window_set_focus (GTK_WINDOW (window), NULL);
6143     }
6144       
6145   child = priv->default_widget;
6146       
6147   while (child && child != widget)
6148     child = gtk_widget_get_parent (child);
6149
6150   if (child == widget)
6151     gtk_window_set_default (window, NULL);
6152   
6153   g_object_unref (widget);
6154   g_object_unref (window);
6155 }
6156
6157 /*********************************
6158  * Functions related to resizing *
6159  *********************************/
6160
6161 static void
6162 geometry_size_to_pixels (GdkGeometry *geometry,
6163                          guint        flags,
6164                          guint       *width,
6165                          guint       *height)
6166 {
6167   gint base_width = 0;
6168   gint base_height = 0;
6169   gint min_width = 0;
6170   gint min_height = 0;
6171   gint width_inc = 1;
6172   gint height_inc = 1;
6173
6174   if (flags & GDK_HINT_BASE_SIZE)
6175     {
6176       base_width = geometry->base_width;
6177       base_height = geometry->base_height;
6178     }
6179   if (flags & GDK_HINT_MIN_SIZE)
6180     {
6181       min_width = geometry->min_width;
6182       min_height = geometry->min_height;
6183     }
6184   if (flags & GDK_HINT_RESIZE_INC)
6185     {
6186       width_inc = geometry->width_inc;
6187       height_inc = geometry->height_inc;
6188     }
6189
6190   if (width)
6191     *width = MAX (*width * width_inc + base_width, min_width);
6192   if (height)
6193     *height = MAX (*height * height_inc + base_height, min_height);
6194 }
6195
6196 /* This function doesn't constrain to geometry hints */
6197 static void 
6198 gtk_window_compute_configure_request_size (GtkWindow   *window,
6199                                            GdkGeometry *geometry,
6200                                            guint        flags,
6201                                            guint       *width,
6202                                            guint       *height)
6203 {
6204   GtkWindowPrivate *priv = window->priv;
6205   GtkRequisition requisition;
6206   GtkWindowGeometryInfo *info;
6207   GtkWidget *widget;
6208
6209   /* Preconditions:
6210    *  - we've done a size request
6211    */
6212   
6213   widget = GTK_WIDGET (window);
6214
6215   info = gtk_window_get_geometry_info (window, FALSE);
6216
6217   if (priv->need_default_size)
6218     {
6219       gtk_widget_get_preferred_size (widget, &requisition, NULL);
6220
6221       /* Default to requisition */
6222       *width = requisition.width;
6223       *height = requisition.height;
6224
6225       /* If window is empty so requests 0, default to random nonzero size */
6226        if (*width == 0 && *height == 0)
6227          {
6228            *width = 200;
6229            *height = 200;
6230          }
6231
6232        /* Override requisition with default size */
6233
6234        if (info)
6235          {
6236            if (info->default_width > 0)
6237              *width = info->default_width;
6238            if (info->default_height > 0)
6239              *height = info->default_height;
6240
6241            if (info->default_is_geometry)
6242              geometry_size_to_pixels (geometry, flags,
6243                                       info->default_width > 0 ? width : NULL,
6244                                       info->default_height > 0 ? height : NULL);
6245          }
6246     }
6247   else
6248     {
6249       GtkAllocation allocation;
6250
6251       gtk_widget_get_allocation (widget, &allocation);
6252
6253       /* Default to keeping current size */
6254       *width = allocation.width;
6255       *height = allocation.height;
6256     }
6257
6258   /* Override any size with gtk_window_resize() values */
6259   if (info)
6260     {
6261       if (info->resize_width > 0)
6262         *width = info->resize_width;
6263       if (info->resize_height > 0)
6264         *height = info->resize_height;
6265
6266       if (info->resize_is_geometry)
6267         geometry_size_to_pixels (geometry, flags,
6268                                  info->resize_width > 0 ? width : NULL,
6269                                  info->resize_height > 0 ? height : NULL);
6270     }
6271
6272   /* Don't ever request zero width or height, its not supported by
6273      gdk. The size allocation code will round it to 1 anyway but if
6274      we do it then the value returned from this function will is
6275      not comparable to the size allocation read from the GtkWindow. */
6276   *width = MAX (*width, 1);
6277   *height = MAX (*height, 1);
6278 }
6279
6280 static GtkWindowPosition
6281 get_effective_position (GtkWindow *window)
6282 {
6283   GtkWindowPrivate *priv = window->priv;
6284   GtkWindowPosition pos = priv->position;
6285
6286   if (pos == GTK_WIN_POS_CENTER_ON_PARENT &&
6287       (priv->transient_parent == NULL ||
6288        !gtk_widget_get_mapped (GTK_WIDGET (priv->transient_parent))))
6289     pos = GTK_WIN_POS_NONE;
6290
6291   return pos;
6292 }
6293
6294 static int
6295 get_center_monitor_of_window (GtkWindow *window)
6296 {
6297   /* We could try to sort out the relative positions of the monitors and
6298    * stuff, or we could just be losers and assume you have a row
6299    * or column of monitors.
6300    */
6301   return gdk_screen_get_n_monitors (gtk_window_check_screen (window)) / 2;
6302 }
6303
6304 static int
6305 get_monitor_containing_pointer (GtkWindow *window)
6306 {
6307   gint px, py;
6308   gint monitor_num;
6309   GdkScreen *window_screen;
6310   GdkScreen *pointer_screen;
6311   GdkDisplay *display;
6312   GdkDeviceManager *device_manager;
6313   GdkDevice *pointer;
6314
6315   window_screen = gtk_window_check_screen (window);
6316   display = gdk_screen_get_display (window_screen);
6317   device_manager = gdk_display_get_device_manager (display);
6318   pointer = gdk_device_manager_get_client_pointer (device_manager);
6319
6320   gdk_device_get_position (pointer,
6321                            &pointer_screen,
6322                            &px, &py);
6323
6324   if (pointer_screen == window_screen)
6325     monitor_num = gdk_screen_get_monitor_at_point (pointer_screen, px, py);
6326   else
6327     monitor_num = -1;
6328
6329   return monitor_num;
6330 }
6331
6332 static void
6333 center_window_on_monitor (GtkWindow *window,
6334                           gint       w,
6335                           gint       h,
6336                           gint      *x,
6337                           gint      *y)
6338 {
6339   GdkRectangle monitor;
6340   int monitor_num;
6341
6342   monitor_num = get_monitor_containing_pointer (window);
6343   
6344   if (monitor_num == -1)
6345     monitor_num = get_center_monitor_of_window (window);
6346
6347   gdk_screen_get_monitor_geometry (gtk_window_check_screen (window),
6348                                    monitor_num, &monitor);
6349   
6350   *x = (monitor.width - w) / 2 + monitor.x;
6351   *y = (monitor.height - h) / 2 + monitor.y;
6352
6353   /* Be sure we aren't off the monitor, ignoring _NET_WM_STRUT
6354    * and WM decorations.
6355    */
6356   if (*x < monitor.x)
6357     *x = monitor.x;
6358   if (*y < monitor.y)
6359     *y = monitor.y;
6360 }
6361
6362 static void
6363 clamp (gint *base,
6364        gint  extent,
6365        gint  clamp_base,
6366        gint  clamp_extent)
6367 {
6368   if (extent > clamp_extent)
6369     /* Center */
6370     *base = clamp_base + clamp_extent/2 - extent/2;
6371   else if (*base < clamp_base)
6372     *base = clamp_base;
6373   else if (*base + extent > clamp_base + clamp_extent)
6374     *base = clamp_base + clamp_extent - extent;
6375 }
6376
6377 static void
6378 clamp_window_to_rectangle (gint               *x,
6379                            gint               *y,
6380                            gint                w,
6381                            gint                h,
6382                            const GdkRectangle *rect)
6383 {
6384 #ifdef DEBUGGING_OUTPUT
6385   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);
6386 #endif
6387
6388   /* If it is too large, center it. If it fits on the monitor but is
6389    * partially outside, move it to the closest edge. Do this
6390    * separately in x and y directions.
6391    */
6392   clamp (x, w, rect->x, rect->width);
6393   clamp (y, h, rect->y, rect->height);
6394 #ifdef DEBUGGING_OUTPUT
6395   g_print (" ==> %+d%+d: %dx%d\n", *x, *y, w, h);
6396 #endif
6397 }
6398
6399
6400 static void
6401 gtk_window_compute_configure_request (GtkWindow    *window,
6402                                       GdkRectangle *request,
6403                                       GdkGeometry  *geometry,
6404                                       guint        *flags)
6405 {
6406   GtkWindowPrivate *priv = window->priv;
6407   GdkGeometry new_geometry;
6408   guint new_flags;
6409   int w, h;
6410   GtkWindowPosition pos;
6411   GtkWidget *parent_widget;
6412   GtkWindowGeometryInfo *info;
6413   GdkScreen *screen;
6414   int x, y;
6415
6416   screen = gtk_window_check_screen (window);
6417
6418   gtk_window_compute_hints (window, &new_geometry, &new_flags);
6419   gtk_window_compute_configure_request_size (window,
6420                                              &new_geometry, new_flags,
6421                                              (guint *)&w, (guint *)&h);
6422
6423   gtk_window_constrain_size (window,
6424                              &new_geometry, new_flags,
6425                              w, h,
6426                              &w, &h);
6427
6428   parent_widget = (GtkWidget*) priv->transient_parent;
6429
6430   pos = get_effective_position (window);
6431   info = gtk_window_get_geometry_info (window, FALSE);
6432
6433   /* by default, don't change position requested */
6434   if (info)
6435     {
6436       x = info->last.configure_request.x;
6437       y = info->last.configure_request.y;
6438     }
6439   else
6440     {
6441       x = 0;
6442       y = 0;
6443     }
6444
6445
6446   if (priv->need_default_position)
6447     {
6448
6449       /* FIXME this all interrelates with window gravity.
6450        * For most of them I think we want to set GRAVITY_CENTER.
6451        *
6452        * Not sure how to go about that.
6453        */
6454       switch (pos)
6455         {
6456           /* here we are only handling CENTER_ALWAYS
6457            * as it relates to default positioning,
6458            * where it's equivalent to simply CENTER
6459            */
6460         case GTK_WIN_POS_CENTER_ALWAYS:
6461         case GTK_WIN_POS_CENTER:
6462           center_window_on_monitor (window, w, h, &x, &y);
6463           break;
6464
6465         case GTK_WIN_POS_CENTER_ON_PARENT:
6466           {
6467             GtkAllocation allocation;
6468             GdkWindow *gdk_window;
6469             gint monitor_num;
6470             GdkRectangle monitor;
6471             gint ox, oy;
6472
6473             g_assert (gtk_widget_get_mapped (parent_widget)); /* established earlier */
6474
6475             gdk_window = gtk_widget_get_window (parent_widget);
6476
6477             if (gdk_window != NULL)
6478               monitor_num = gdk_screen_get_monitor_at_window (screen,
6479                                                               gdk_window);
6480             else
6481               monitor_num = -1;
6482
6483             gdk_window_get_origin (gdk_window,
6484                                    &ox, &oy);
6485
6486             gtk_widget_get_allocation (parent_widget, &allocation);
6487             x = ox + (allocation.width - w) / 2;
6488             y = oy + (allocation.height - h) / 2;
6489
6490             /* Clamp onto current monitor, ignoring _NET_WM_STRUT and
6491              * WM decorations. If parent wasn't on a monitor, just
6492              * give up.
6493              */
6494             if (monitor_num >= 0)
6495               {
6496                 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
6497                 clamp_window_to_rectangle (&x, &y, w, h, &monitor);
6498               }
6499           }
6500           break;
6501
6502         case GTK_WIN_POS_MOUSE:
6503           {
6504             gint screen_width = gdk_screen_get_width (screen);
6505             gint screen_height = gdk_screen_get_height (screen);
6506             gint monitor_num;
6507             GdkRectangle monitor;
6508             GdkDisplay *display;
6509             GdkDeviceManager *device_manager;
6510             GdkDevice *pointer;
6511             GdkScreen *pointer_screen;
6512             gint px, py;
6513
6514             display = gdk_screen_get_display (screen);
6515             device_manager = gdk_display_get_device_manager (display);
6516             pointer = gdk_device_manager_get_client_pointer (device_manager);
6517
6518             gdk_device_get_position (pointer,
6519                                      &pointer_screen,
6520                                      &px, &py);
6521
6522             if (pointer_screen == screen)
6523               monitor_num = gdk_screen_get_monitor_at_point (screen, px, py);
6524             else
6525               monitor_num = -1;
6526
6527             x = px - w / 2;
6528             y = py - h / 2;
6529             x = CLAMP (x, 0, screen_width - w);
6530             y = CLAMP (y, 0, screen_height - h);
6531
6532             /* Clamp onto current monitor, ignoring _NET_WM_STRUT and
6533              * WM decorations. Don't try to figure out what's going
6534              * on if the mouse wasn't inside a monitor.
6535              */
6536             if (monitor_num >= 0)
6537               {
6538                 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
6539                 clamp_window_to_rectangle (&x, &y, w, h, &monitor);
6540               }
6541           }
6542           break;
6543
6544         default:
6545           break;
6546         }
6547     } /* if (priv->need_default_position) */
6548
6549   if (priv->need_default_position && info &&
6550       info->initial_pos_set)
6551     {
6552       x = info->initial_x;
6553       y = info->initial_y;
6554       gtk_window_constrain_position (window, w, h, &x, &y);
6555     }
6556
6557   request->x = x;
6558   request->y = y;
6559   request->width = w;
6560   request->height = h;
6561
6562   if (geometry)
6563     *geometry = new_geometry;
6564   if (flags)
6565     *flags = new_flags;
6566 }
6567
6568 static void
6569 gtk_window_constrain_position (GtkWindow    *window,
6570                                gint          new_width,
6571                                gint          new_height,
6572                                gint         *x,
6573                                gint         *y)
6574 {
6575   GtkWindowPrivate *priv = window->priv;
6576
6577   /* See long comments in gtk_window_move_resize()
6578    * on when it's safe to call this function.
6579    */
6580   if (priv->position == GTK_WIN_POS_CENTER_ALWAYS)
6581     {
6582       gint center_x, center_y;
6583
6584       center_window_on_monitor (window, new_width, new_height, &center_x, &center_y);
6585       
6586       *x = center_x;
6587       *y = center_y;
6588     }
6589 }
6590
6591 static void
6592 gtk_window_move_resize (GtkWindow *window)
6593 {
6594   /* Overview:
6595    *
6596    * First we determine whether any information has changed that would
6597    * cause us to revise our last configure request.  If we would send
6598    * a different configure request from last time, then
6599    * configure_request_size_changed = TRUE or
6600    * configure_request_pos_changed = TRUE. configure_request_size_changed
6601    * may be true due to new hints, a gtk_window_resize(), or whatever.
6602    * configure_request_pos_changed may be true due to gtk_window_set_position()
6603    * or gtk_window_move().
6604    *
6605    * If the configure request has changed, we send off a new one.  To
6606    * ensure GTK+ invariants are maintained (resize queue does what it
6607    * should), we go ahead and size_allocate the requested size in this
6608    * function.
6609    *
6610    * If the configure request has not changed, we don't ever resend
6611    * it, because it could mean fighting the user or window manager.
6612    *
6613    * 
6614    *   To prepare the configure request, we come up with a base size/pos:
6615    *      - the one from gtk_window_move()/gtk_window_resize()
6616    *      - else default_width, default_height if we haven't ever
6617    *        been mapped
6618    *      - else the size request if we haven't ever been mapped,
6619    *        as a substitute default size
6620    *      - else the current size of the window, as received from
6621    *        configure notifies (i.e. the current allocation)
6622    *
6623    *   If GTK_WIN_POS_CENTER_ALWAYS is active, we constrain
6624    *   the position request to be centered.
6625    */
6626   GtkWindowPrivate *priv = window->priv;
6627   GtkAllocation allocation;
6628   GtkWidget *widget;
6629   GtkContainer *container;
6630   GtkWindowGeometryInfo *info;
6631   GdkGeometry new_geometry;
6632   GdkWindow *gdk_window;
6633   guint new_flags;
6634   GdkRectangle new_request;
6635   gboolean configure_request_size_changed;
6636   gboolean configure_request_pos_changed;
6637   gboolean hints_changed; /* do we need to send these again */
6638   GtkWindowLastGeometryInfo saved_last_info;
6639   
6640   widget = GTK_WIDGET (window);
6641
6642   gdk_window = gtk_widget_get_window (widget);
6643   container = GTK_CONTAINER (widget);
6644   info = gtk_window_get_geometry_info (window, TRUE);
6645   
6646   configure_request_size_changed = FALSE;
6647   configure_request_pos_changed = FALSE;
6648   
6649   gtk_window_compute_configure_request (window, &new_request,
6650                                         &new_geometry, &new_flags);  
6651   
6652   /* This check implies the invariant that we never set info->last
6653    * without setting the hints and sending off a configure request.
6654    *
6655    * If we change info->last without sending the request, we may
6656    * miss a request.
6657    */
6658   if (info->last.configure_request.x != new_request.x ||
6659       info->last.configure_request.y != new_request.y)
6660     configure_request_pos_changed = TRUE;
6661
6662   if ((info->last.configure_request.width != new_request.width ||
6663        info->last.configure_request.height != new_request.height))
6664     configure_request_size_changed = TRUE;
6665   
6666   hints_changed = FALSE;
6667   
6668   if (!gtk_window_compare_hints (&info->last.geometry, info->last.flags,
6669                                  &new_geometry, new_flags))
6670     {
6671       hints_changed = TRUE;
6672     }
6673   
6674   /* Position Constraints
6675    * ====================
6676    * 
6677    * POS_CENTER_ALWAYS is conceptually a constraint rather than
6678    * a default. The other POS_ values are used only when the
6679    * window is shown, not after that.
6680    * 
6681    * However, we can't implement a position constraint as
6682    * "anytime the window size changes, center the window"
6683    * because this may well end up fighting the WM or user.  In
6684    * fact it gets in an infinite loop with at least one WM.
6685    *
6686    * Basically, applications are in no way in a position to
6687    * constrain the position of a window, with one exception:
6688    * override redirect windows. (Really the intended purpose
6689    * of CENTER_ALWAYS anyhow, I would think.)
6690    *
6691    * So the way we implement this "constraint" is to say that when WE
6692    * cause a move or resize, i.e. we make a configure request changing
6693    * window size, we recompute the CENTER_ALWAYS position to reflect
6694    * the new window size, and include it in our request.  Also, if we
6695    * just turned on CENTER_ALWAYS we snap to center with a new
6696    * request.  Otherwise, if we are just NOTIFIED of a move or resize
6697    * done by someone else e.g. the window manager, we do NOT send a
6698    * new configure request.
6699    *
6700    * For override redirect windows, this works fine; all window
6701    * sizes are from our configure requests. For managed windows,
6702    * it is at least semi-sane, though who knows what the
6703    * app author is thinking.
6704    */
6705
6706   /* This condition should be kept in sync with the condition later on
6707    * that determines whether we send a configure request.  i.e. we
6708    * should do this position constraining anytime we were going to
6709    * send a configure request anyhow, plus when constraints have
6710    * changed.
6711    */
6712   if (configure_request_pos_changed ||
6713       configure_request_size_changed ||
6714       hints_changed ||
6715       info->position_constraints_changed)
6716     {
6717       /* We request the constrained position if:
6718        *  - we were changing position, and need to clamp
6719        *    the change to the constraint
6720        *  - we're changing the size anyway
6721        *  - set_position() was called to toggle CENTER_ALWAYS on
6722        */
6723
6724       gtk_window_constrain_position (window,
6725                                      new_request.width,
6726                                      new_request.height,
6727                                      &new_request.x,
6728                                      &new_request.y);
6729       
6730       /* Update whether we need to request a move */
6731       if (info->last.configure_request.x != new_request.x ||
6732           info->last.configure_request.y != new_request.y)
6733         configure_request_pos_changed = TRUE;
6734       else
6735         configure_request_pos_changed = FALSE;
6736     }
6737
6738 #if 0
6739   if (priv->type == GTK_WINDOW_TOPLEVEL)
6740     {
6741       int notify_x, notify_y;
6742
6743       /* this is the position from the last configure notify */
6744       gdk_window_get_position (widget->window, &notify_x, &notify_y);
6745     
6746       g_message ("--- %s ---\n"
6747                  "last  : %d,%d\t%d x %d\n"
6748                  "this  : %d,%d\t%d x %d\n"
6749                  "alloc : %d,%d\t%d x %d\n"
6750                  "req   :      \t%d x %d\n"
6751                  "resize:      \t%d x %d\n" 
6752                  "size_changed: %d pos_changed: %d hints_changed: %d\n"
6753                  "configure_notify_received: %d\n"
6754                  "configure_request_count: %d\n"
6755                  "position_constraints_changed: %d\n",
6756                  priv->title ? priv->title : "(no title)",
6757                  info->last.configure_request.x,
6758                  info->last.configure_request.y,
6759                  info->last.configure_request.width,
6760                  info->last.configure_request.height,
6761                  new_request.x,
6762                  new_request.y,
6763                  new_request.width,
6764                  new_request.height,
6765                  notify_x, notify_y,
6766                  widget->allocation.width,
6767                  widget->allocation.height,
6768                  widget->requisition.width,
6769                  widget->requisition.height,
6770                  info->resize_width,
6771                  info->resize_height,
6772                  configure_request_pos_changed,
6773                  configure_request_size_changed,
6774                  hints_changed,
6775                  priv->configure_notify_received,
6776                  priv->configure_request_count,
6777                  info->position_constraints_changed);
6778     }
6779 #endif
6780   
6781   saved_last_info = info->last;
6782   info->last.geometry = new_geometry;
6783   info->last.flags = new_flags;
6784   info->last.configure_request = new_request;
6785   
6786   /* need to set PPosition so the WM will look at our position,
6787    * but we don't want to count PPosition coming and going as a hints
6788    * change for future iterations. So we saved info->last prior to
6789    * this.
6790    */
6791   
6792   /* Also, if the initial position was explicitly set, then we always
6793    * toggle on PPosition. This makes gtk_window_move(window, 0, 0)
6794    * work.
6795    */
6796
6797   /* Also, we toggle on PPosition if GTK_WIN_POS_ is in use and
6798    * this is an initial map
6799    */
6800   
6801   if ((configure_request_pos_changed ||
6802        info->initial_pos_set ||
6803        (priv->need_default_position &&
6804         get_effective_position (window) != GTK_WIN_POS_NONE)) &&
6805       (new_flags & GDK_HINT_POS) == 0)
6806     {
6807       new_flags |= GDK_HINT_POS;
6808       hints_changed = TRUE;
6809     }
6810   
6811   /* Set hints if necessary
6812    */
6813   if (hints_changed)
6814     gdk_window_set_geometry_hints (gdk_window,
6815                                    &new_geometry,
6816                                    new_flags);
6817
6818   gtk_widget_get_allocation (widget, &allocation);
6819
6820   /* handle resizing/moving and widget tree allocation
6821    */
6822   if (priv->configure_notify_received)
6823     { 
6824       /* If we have received a configure event since
6825        * the last time in this function, we need to
6826        * accept our new size and size_allocate child widgets.
6827        * (see gtk_window_configure_event() for more details).
6828        *
6829        * 1 or more configure notifies may have been received.
6830        * Also, configure_notify_received will only be TRUE
6831        * if all expected configure notifies have been received
6832        * (one per configure request), as an optimization.
6833        *
6834        */
6835       priv->configure_notify_received = FALSE;
6836
6837       /* gtk_window_configure_event() filled in widget->allocation */
6838       gtk_widget_size_allocate (widget, &allocation);
6839
6840       set_grip_position (window);
6841       update_grip_visibility (window);
6842
6843       gdk_window_process_updates (gdk_window, TRUE);
6844
6845       gdk_window_configure_finished (gdk_window);
6846
6847       /* If the configure request changed, it means that
6848        * we either:
6849        *   1) coincidentally changed hints or widget properties
6850        *      impacting the configure request before getting
6851        *      a configure notify, or
6852        *   2) some broken widget is changing its size request
6853        *      during size allocation, resulting in
6854        *      a false appearance of changed configure request.
6855        *
6856        * For 1), we could just go ahead and ask for the
6857        * new size right now, but doing that for 2)
6858        * might well be fighting the user (and can even
6859        * trigger a loop). Since we really don't want to
6860        * do that, we requeue a resize in hopes that
6861        * by the time it gets handled, the child has seen
6862        * the light and is willing to go along with the
6863        * new size. (this happens for the zvt widget, since
6864        * the size_allocate() above will have stored the
6865        * requisition corresponding to the new size in the
6866        * zvt widget)
6867        *
6868        * This doesn't buy us anything for 1), but it shouldn't
6869        * hurt us too badly, since it is what would have
6870        * happened if we had gotten the configure event before
6871        * the new size had been set.
6872        */
6873
6874       if (configure_request_size_changed ||
6875           configure_request_pos_changed)
6876         {
6877           /* Don't change the recorded last info after all, because we
6878            * haven't actually updated to the new info yet - we decided
6879            * to postpone our configure request until later.
6880            */
6881           info->last = saved_last_info;
6882           
6883           gtk_widget_queue_resize_no_redraw (widget); /* migth recurse for GTK_RESIZE_IMMEDIATE */
6884         }
6885
6886       return;                   /* Bail out, we didn't really process the move/resize */
6887     }
6888   else if ((configure_request_size_changed || hints_changed) &&
6889            (allocation.width != new_request.width || allocation.height != new_request.height))
6890
6891     {
6892       /* We are in one of the following situations:
6893        * A. configure_request_size_changed
6894        *    our requisition has changed and we need a different window size,
6895        *    so we request it from the window manager.
6896        * B. !configure_request_size_changed && hints_changed
6897        *    the window manager rejects our size, but we have just changed the
6898        *    window manager hints, so there's a chance our request will
6899        *    be honoured this time, so we try again.
6900        *
6901        * However, if the new requisition is the same as the current allocation,
6902        * we don't request it again, since we won't get a ConfigureNotify back from
6903        * the window manager unless it decides to change our requisition. If
6904        * we don't get the ConfigureNotify back, the resize queue will never be run.
6905        */
6906
6907       /* Now send the configure request */
6908       if (configure_request_pos_changed)
6909         {
6910           gdk_window_move_resize (gdk_window,
6911                                   new_request.x, new_request.y,
6912                                   new_request.width, new_request.height);
6913         }
6914       else  /* only size changed */
6915         {
6916           gdk_window_resize (gdk_window,
6917                              new_request.width, new_request.height);
6918         }
6919
6920       if (priv->type == GTK_WINDOW_POPUP)
6921         {
6922           GtkAllocation allocation;
6923
6924           /* Directly size allocate for override redirect (popup) windows. */
6925           allocation.x = 0;
6926           allocation.y = 0;
6927           allocation.width = new_request.width;
6928           allocation.height = new_request.height;
6929
6930           gtk_widget_size_allocate (widget, &allocation);
6931
6932           gdk_window_process_updates (gdk_window, TRUE);
6933
6934           if (gtk_container_get_resize_mode (container) == GTK_RESIZE_QUEUE)
6935             gtk_widget_queue_draw (widget);
6936         }
6937       else
6938         {
6939           /* Increment the number of have-not-yet-received-notify requests */
6940           priv->configure_request_count += 1;
6941           gdk_window_freeze_toplevel_updates_libgtk_only (gdk_window);
6942
6943           /* for GTK_RESIZE_QUEUE toplevels, we are now awaiting a new
6944            * configure event in response to our resizing request.
6945            * the configure event will cause a new resize with
6946            * ->configure_notify_received=TRUE.
6947            * until then, we want to
6948            * - discard expose events
6949            * - coalesce resizes for our children
6950            * - defer any window resizes until the configure event arrived
6951            * to achieve this, we queue a resize for the window, but remove its
6952            * resizing handler, so resizing will not be handled from the next
6953            * idle handler but when the configure event arrives.
6954            *
6955            * FIXME: we should also dequeue the pending redraws here, since
6956            * we handle those ourselves upon ->configure_notify_received==TRUE.
6957            */
6958           if (gtk_container_get_resize_mode (container) == GTK_RESIZE_QUEUE)
6959             {
6960               gtk_widget_queue_resize_no_redraw (widget);
6961               _gtk_container_dequeue_resize_handler (container);
6962             }
6963         }
6964     }
6965   else
6966     {
6967       /* Handle any position changes.
6968        */
6969       if (configure_request_pos_changed)
6970         {
6971           gdk_window_move (gdk_window,
6972                            new_request.x, new_request.y);
6973         }
6974
6975       /* And run the resize queue.
6976        */
6977       gtk_container_resize_children (container);
6978     }
6979   
6980   /* We have now processed a move/resize since the last position
6981    * constraint change, setting of the initial position, or resize.
6982    * (Not resetting these flags here can lead to infinite loops for
6983    * GTK_RESIZE_IMMEDIATE containers)
6984    */
6985   info->position_constraints_changed = FALSE;
6986   info->initial_pos_set = FALSE;
6987   info->resize_width = -1;
6988   info->resize_height = -1;
6989 }
6990
6991 /* Compare two sets of Geometry hints for equality.
6992  */
6993 static gboolean
6994 gtk_window_compare_hints (GdkGeometry *geometry_a,
6995                           guint        flags_a,
6996                           GdkGeometry *geometry_b,
6997                           guint        flags_b)
6998 {
6999   if (flags_a != flags_b)
7000     return FALSE;
7001   
7002   if ((flags_a & GDK_HINT_MIN_SIZE) &&
7003       (geometry_a->min_width != geometry_b->min_width ||
7004        geometry_a->min_height != geometry_b->min_height))
7005     return FALSE;
7006
7007   if ((flags_a & GDK_HINT_MAX_SIZE) &&
7008       (geometry_a->max_width != geometry_b->max_width ||
7009        geometry_a->max_height != geometry_b->max_height))
7010     return FALSE;
7011
7012   if ((flags_a & GDK_HINT_BASE_SIZE) &&
7013       (geometry_a->base_width != geometry_b->base_width ||
7014        geometry_a->base_height != geometry_b->base_height))
7015     return FALSE;
7016
7017   if ((flags_a & GDK_HINT_ASPECT) &&
7018       (geometry_a->min_aspect != geometry_b->min_aspect ||
7019        geometry_a->max_aspect != geometry_b->max_aspect))
7020     return FALSE;
7021
7022   if ((flags_a & GDK_HINT_RESIZE_INC) &&
7023       (geometry_a->width_inc != geometry_b->width_inc ||
7024        geometry_a->height_inc != geometry_b->height_inc))
7025     return FALSE;
7026
7027   if ((flags_a & GDK_HINT_WIN_GRAVITY) &&
7028       geometry_a->win_gravity != geometry_b->win_gravity)
7029     return FALSE;
7030
7031   return TRUE;
7032 }
7033
7034 void
7035 _gtk_window_constrain_size (GtkWindow   *window,
7036                             gint         width,
7037                             gint         height,
7038                             gint        *new_width,
7039                             gint        *new_height)
7040 {
7041   GtkWindowPrivate *priv;
7042   GtkWindowGeometryInfo *info;
7043
7044   g_return_if_fail (GTK_IS_WINDOW (window));
7045
7046   priv = window->priv;
7047
7048   info = priv->geometry_info;
7049   if (info)
7050     {
7051       GdkWindowHints flags = info->last.flags;
7052       GdkGeometry *geometry = &info->last.geometry;
7053       
7054       gtk_window_constrain_size (window,
7055                                  geometry,
7056                                  flags,
7057                                  width,
7058                                  height,
7059                                  new_width,
7060                                  new_height);
7061     }
7062 }
7063
7064 static void 
7065 gtk_window_constrain_size (GtkWindow   *window,
7066                            GdkGeometry *geometry,
7067                            guint        flags,
7068                            gint         width,
7069                            gint         height,
7070                            gint        *new_width,
7071                            gint        *new_height)
7072 {
7073   gdk_window_constrain_size (geometry, flags, width, height,
7074                              new_width, new_height);
7075 }
7076
7077 /* Compute the set of geometry hints and flags for a window
7078  * based on the application set geometry, and requisition
7079  * of the window. gtk_widget_get_preferred_size() must have been
7080  * called first.
7081  */
7082 static void
7083 gtk_window_compute_hints (GtkWindow   *window,
7084                           GdkGeometry *new_geometry,
7085                           guint       *new_flags)
7086 {
7087   GtkWindowPrivate *priv = window->priv;
7088   GtkWidget *widget;
7089   gint extra_width = 0;
7090   gint extra_height = 0;
7091   GtkWindowGeometryInfo *geometry_info;
7092   GtkRequisition requisition;
7093
7094   widget = GTK_WIDGET (window);
7095
7096   gtk_widget_get_preferred_size (widget, &requisition, NULL);
7097   geometry_info = gtk_window_get_geometry_info (GTK_WINDOW (widget), FALSE);
7098
7099   if (geometry_info)
7100     {
7101       *new_flags = geometry_info->mask;
7102       *new_geometry = geometry_info->geometry;
7103     }
7104   else
7105     {
7106       *new_flags = 0;
7107     }
7108   
7109   if (geometry_info && geometry_info->widget)
7110     {
7111       /* If the geometry widget is set, then the hints really apply to that
7112        * widget. This is pretty much meaningless unless the window layout
7113        * is such that the rest of the window adds fixed size borders to
7114        * the geometry widget. Our job is to figure the size of the borders;
7115        * We do that by asking how big the toplevel would be if the
7116        * geometry widget was *really big*.
7117        *
7118        *  +----------+
7119        *  |AAAAAAAAA | At small sizes, the minimum sizes of widgets
7120        *  |GGGGG    B| in the border can confuse things
7121        *  |GGGGG    B|
7122        *  |         B|
7123        *  +----------+
7124        *
7125        *  +-----------+
7126        *  |AAAAAAAAA  | When the geometry widget is large, things are
7127        *  |GGGGGGGGGGB| clearer.
7128        *  |GGGGGGGGGGB|
7129        *  |GGGGGGGGGG |
7130        *  +-----------+
7131        */
7132 #define TEMPORARY_SIZE 10000 /* 10,000 pixels should be bigger than real widget sizes */
7133       GtkRequisition requisition;
7134       int current_width, current_height;
7135
7136       _gtk_widget_override_size_request (geometry_info->widget,
7137                                          TEMPORARY_SIZE, TEMPORARY_SIZE,
7138                                          &current_width, &current_height);
7139       gtk_widget_get_preferred_size (widget,
7140                                      &requisition, NULL);
7141       _gtk_widget_restore_size_request (geometry_info->widget,
7142                                         current_width, current_height);
7143
7144       extra_width = requisition.width - TEMPORARY_SIZE;
7145       extra_height = requisition.height - TEMPORARY_SIZE;
7146
7147       if (extra_width < 0 || extra_width < 0)
7148         {
7149           g_warning("Toplevel size doesn't seem to directly depend on the "
7150                     "size of the geometry widget from gtk_window_set_geometry_hints(). "
7151                     "The geometry widget might not be in the window, or it might not "
7152                     "be packed into the window appropriately");
7153           extra_width = MAX(extra_width, 0);
7154           extra_height = MAX(extra_height, 0);
7155         }
7156 #undef TEMPORARY_SIZE
7157     }
7158
7159   /* We don't want to set GDK_HINT_POS in here, we just set it
7160    * in gtk_window_move_resize() when we want the position
7161    * honored.
7162    */
7163   
7164   if (*new_flags & GDK_HINT_BASE_SIZE)
7165     {
7166       new_geometry->base_width += extra_width;
7167       new_geometry->base_height += extra_height;
7168     }
7169   else
7170     {
7171       /* For simplicity, we always set the base hint, even when we
7172        * don't expect it to have any visible effect.
7173        * (Note: geometry_size_to_pixels() depends on this.)
7174        */
7175       *new_flags |= GDK_HINT_BASE_SIZE;
7176
7177       new_geometry->base_width = extra_width;
7178       new_geometry->base_height = extra_height;
7179
7180       /* As for X, if BASE_SIZE is not set but MIN_SIZE is set, then the
7181        * base size is the minimum size */
7182       if (*new_flags & GDK_HINT_MIN_SIZE)
7183         {
7184           if (new_geometry->min_width > 0)
7185             new_geometry->base_width += new_geometry->min_width;
7186           if (new_geometry->min_height > 0)
7187             new_geometry->base_height += new_geometry->min_height;
7188         }
7189     }
7190
7191   if (*new_flags & GDK_HINT_MIN_SIZE)
7192     {
7193       if (new_geometry->min_width < 0)
7194         new_geometry->min_width = requisition.width;
7195       else
7196         new_geometry->min_width = MAX (requisition.width, new_geometry->min_width + extra_width);
7197
7198       if (new_geometry->min_height < 0)
7199         new_geometry->min_height = requisition.height;
7200       else
7201         new_geometry->min_height = MAX (requisition.height, new_geometry->min_height + extra_height);
7202     }
7203   else
7204     {
7205       *new_flags |= GDK_HINT_MIN_SIZE;
7206       
7207       new_geometry->min_width = requisition.width;
7208       new_geometry->min_height = requisition.height;
7209     }
7210   
7211   if (*new_flags & GDK_HINT_MAX_SIZE)
7212     {
7213       if (new_geometry->max_width < 0)
7214         new_geometry->max_width = requisition.width;
7215       else
7216         new_geometry->max_width += extra_width;
7217
7218       if (new_geometry->max_height < 0)
7219         new_geometry->max_height = requisition.height;
7220       else
7221         new_geometry->max_height += extra_height;
7222     }
7223   else if (!priv->resizable)
7224     {
7225       *new_flags |= GDK_HINT_MAX_SIZE;
7226       
7227       new_geometry->max_width = requisition.width;
7228       new_geometry->max_height = requisition.height;
7229     }
7230
7231   *new_flags |= GDK_HINT_WIN_GRAVITY;
7232   new_geometry->win_gravity = priv->gravity;
7233 }
7234
7235 /***********************
7236  * Redrawing functions *
7237  ***********************/
7238
7239 static gboolean
7240 gtk_window_draw (GtkWidget *widget,
7241                  cairo_t   *cr)
7242 {
7243   GtkWindowPrivate *priv = GTK_WINDOW (widget)->priv;
7244   GtkStyleContext *context;
7245   gboolean ret = FALSE;
7246
7247   context = gtk_widget_get_style_context (widget);
7248
7249   gtk_style_context_save (context);
7250
7251   if (!gtk_widget_get_app_paintable (widget))
7252     {
7253       GtkStateFlags state;
7254
7255       state = gtk_widget_get_state_flags (widget);
7256
7257       if (gtk_window_has_toplevel_focus (GTK_WINDOW (widget)))
7258         state |= GTK_STATE_FLAG_FOCUSED;
7259
7260       gtk_style_context_set_state (context, state);
7261       gtk_style_context_add_class (context, GTK_STYLE_CLASS_BACKGROUND);
7262       gtk_render_background (context, cr, 0, 0,
7263                              gtk_widget_get_allocated_width (widget),
7264                              gtk_widget_get_allocated_height (widget));
7265     }
7266
7267   gtk_style_context_restore (context);
7268
7269   if (GTK_WIDGET_CLASS (gtk_window_parent_class)->draw)
7270     ret = GTK_WIDGET_CLASS (gtk_window_parent_class)->draw (widget, cr);
7271
7272   if (priv->grip_window != NULL &&
7273       gtk_cairo_should_draw_window (cr, priv->grip_window))
7274     {
7275       GdkRectangle rect;
7276
7277       gtk_style_context_save (context);
7278       cairo_save (cr);
7279
7280       gtk_cairo_transform_to_window (cr, widget, priv->grip_window);
7281       gtk_window_get_resize_grip_area (GTK_WINDOW (widget), &rect);
7282
7283       gtk_style_context_add_class (context, GTK_STYLE_CLASS_GRIP);
7284       gtk_style_context_set_junction_sides (context, get_grip_junction (widget));
7285       gtk_render_handle (context, cr, 0, 0, rect.width, rect.height);
7286
7287       cairo_restore (cr);
7288       gtk_style_context_restore (context);
7289     }
7290
7291   return ret;
7292 }
7293
7294 /**
7295  * gtk_window_present:
7296  * @window: a #GtkWindow
7297  *
7298  * Presents a window to the user. This may mean raising the window
7299  * in the stacking order, deiconifying it, moving it to the current
7300  * desktop, and/or giving it the keyboard focus, possibly dependent
7301  * on the user's platform, window manager, and preferences.
7302  *
7303  * If @window is hidden, this function calls gtk_widget_show()
7304  * as well.
7305  * 
7306  * This function should be used when the user tries to open a window
7307  * that's already open. Say for example the preferences dialog is
7308  * currently open, and the user chooses Preferences from the menu
7309  * a second time; use gtk_window_present() to move the already-open dialog
7310  * where the user can see it.
7311  *
7312  * If you are calling this function in response to a user interaction,
7313  * it is preferable to use gtk_window_present_with_time().
7314  * 
7315  **/
7316 void
7317 gtk_window_present (GtkWindow *window)
7318 {
7319   gtk_window_present_with_time (window, GDK_CURRENT_TIME);
7320 }
7321
7322 /**
7323  * gtk_window_present_with_time:
7324  * @window: a #GtkWindow
7325  * @timestamp: the timestamp of the user interaction (typically a 
7326  *   button or key press event) which triggered this call
7327  *
7328  * Presents a window to the user in response to a user interaction.
7329  * If you need to present a window without a timestamp, use 
7330  * gtk_window_present(). See gtk_window_present() for details. 
7331  * 
7332  * Since: 2.8
7333  **/
7334 void
7335 gtk_window_present_with_time (GtkWindow *window,
7336                               guint32    timestamp)
7337 {
7338   GtkWidget *widget;
7339   GdkWindow *gdk_window;
7340
7341   g_return_if_fail (GTK_IS_WINDOW (window));
7342
7343   widget = GTK_WIDGET (window);
7344
7345   if (gtk_widget_get_visible (widget))
7346     {
7347       gdk_window = gtk_widget_get_window (widget);
7348
7349       g_assert (gdk_window != NULL);
7350
7351       gdk_window_show (gdk_window);
7352
7353       /* Translate a timestamp of GDK_CURRENT_TIME appropriately */
7354       if (timestamp == GDK_CURRENT_TIME)
7355         {
7356 #ifdef GDK_WINDOWING_X11
7357           GdkDisplay *display;
7358
7359           display = gtk_widget_get_display (GTK_WIDGET (window));
7360           timestamp = gdk_x11_display_get_user_time (display);
7361 #else
7362           timestamp = gtk_get_current_event_time ();
7363 #endif
7364         }
7365
7366       gdk_window_focus (gdk_window, timestamp);
7367     }
7368   else
7369     {
7370       gtk_widget_show (widget);
7371     }
7372 }
7373
7374 /**
7375  * gtk_window_iconify:
7376  * @window: a #GtkWindow
7377  *
7378  * Asks to iconify (i.e. minimize) the specified @window. Note that
7379  * you shouldn't assume the window is definitely iconified afterward,
7380  * because other entities (e.g. the user or <link
7381  * linkend="gtk-X11-arch">window manager</link>) could deiconify it
7382  * again, or there may not be a window manager in which case
7383  * iconification isn't possible, etc. But normally the window will end
7384  * up iconified. Just don't write code that crashes if not.
7385  *
7386  * It's permitted to call this function before showing a window,
7387  * in which case the window will be iconified before it ever appears
7388  * onscreen.
7389  *
7390  * You can track iconification via the "window-state-event" signal
7391  * on #GtkWidget.
7392  * 
7393  **/
7394 void
7395 gtk_window_iconify (GtkWindow *window)
7396 {
7397   GtkWindowPrivate *priv;
7398   GtkWidget *widget;
7399   GdkWindow *toplevel;
7400   
7401   g_return_if_fail (GTK_IS_WINDOW (window));
7402
7403   priv = window->priv;
7404   widget = GTK_WIDGET (window);
7405
7406   priv->iconify_initially = TRUE;
7407
7408   toplevel = gtk_widget_get_window (widget);
7409
7410   if (toplevel != NULL)
7411     gdk_window_iconify (toplevel);
7412 }
7413
7414 /**
7415  * gtk_window_deiconify:
7416  * @window: a #GtkWindow
7417  *
7418  * Asks to deiconify (i.e. unminimize) the specified @window. Note
7419  * that you shouldn't assume the window is definitely deiconified
7420  * afterward, because other entities (e.g. the user or <link
7421  * linkend="gtk-X11-arch">window manager</link>) could iconify it
7422  * again before your code which assumes deiconification gets to run.
7423  *
7424  * You can track iconification via the "window-state-event" signal
7425  * on #GtkWidget.
7426  **/
7427 void
7428 gtk_window_deiconify (GtkWindow *window)
7429 {
7430   GtkWindowPrivate *priv;
7431   GtkWidget *widget;
7432   GdkWindow *toplevel;
7433   
7434   g_return_if_fail (GTK_IS_WINDOW (window));
7435
7436   priv = window->priv;
7437   widget = GTK_WIDGET (window);
7438
7439   priv->iconify_initially = FALSE;
7440
7441   toplevel = gtk_widget_get_window (widget);
7442
7443   if (toplevel != NULL)
7444     gdk_window_deiconify (toplevel);
7445 }
7446
7447 /**
7448  * gtk_window_stick:
7449  * @window: a #GtkWindow
7450  *
7451  * Asks to stick @window, which means that it will appear on all user
7452  * desktops. Note that you shouldn't assume the window is definitely
7453  * stuck afterward, because other entities (e.g. the user or <link
7454  * linkend="gtk-X11-arch">window manager</link>) could unstick it
7455  * again, and some window managers do not support sticking
7456  * windows. But normally the window will end up stuck. Just don't
7457  * write code that crashes if not.
7458  *
7459  * It's permitted to call this function before showing a window.
7460  *
7461  * You can track stickiness via the "window-state-event" signal
7462  * on #GtkWidget.
7463  * 
7464  **/
7465 void
7466 gtk_window_stick (GtkWindow *window)
7467 {
7468   GtkWindowPrivate *priv;
7469   GtkWidget *widget;
7470   GdkWindow *toplevel;
7471   
7472   g_return_if_fail (GTK_IS_WINDOW (window));
7473
7474   priv = window->priv;
7475   widget = GTK_WIDGET (window);
7476
7477   priv->stick_initially = TRUE;
7478
7479   toplevel = gtk_widget_get_window (widget);
7480
7481   if (toplevel != NULL)
7482     gdk_window_stick (toplevel);
7483 }
7484
7485 /**
7486  * gtk_window_unstick:
7487  * @window: a #GtkWindow
7488  *
7489  * Asks to unstick @window, which means that it will appear on only
7490  * one of the user's desktops. Note that you shouldn't assume the
7491  * window is definitely unstuck afterward, because other entities
7492  * (e.g. the user or <link linkend="gtk-X11-arch">window
7493  * manager</link>) could stick it again. But normally the window will
7494  * end up stuck. Just don't write code that crashes if not.
7495  *
7496  * You can track stickiness via the "window-state-event" signal
7497  * on #GtkWidget.
7498  * 
7499  **/
7500 void
7501 gtk_window_unstick (GtkWindow *window)
7502 {
7503   GtkWindowPrivate *priv;
7504   GtkWidget *widget;
7505   GdkWindow *toplevel;
7506   
7507   g_return_if_fail (GTK_IS_WINDOW (window));
7508
7509   priv = window->priv;
7510   widget = GTK_WIDGET (window);
7511
7512   priv->stick_initially = FALSE;
7513
7514   toplevel = gtk_widget_get_window (widget);
7515
7516   if (toplevel != NULL)
7517     gdk_window_unstick (toplevel);
7518 }
7519
7520 /**
7521  * gtk_window_maximize:
7522  * @window: a #GtkWindow
7523  *
7524  * Asks to maximize @window, so that it becomes full-screen. Note that
7525  * you shouldn't assume the window is definitely maximized afterward,
7526  * because other entities (e.g. the user or <link
7527  * linkend="gtk-X11-arch">window manager</link>) could unmaximize it
7528  * again, and not all window managers support maximization. But
7529  * normally the window will end up maximized. Just don't write code
7530  * that crashes if not.
7531  *
7532  * It's permitted to call this function before showing a window,
7533  * in which case the window will be maximized when it appears onscreen
7534  * initially.
7535  *
7536  * You can track maximization via the "window-state-event" signal
7537  * on #GtkWidget.
7538  * 
7539  **/
7540 void
7541 gtk_window_maximize (GtkWindow *window)
7542 {
7543   GtkWindowPrivate *priv;
7544   GtkWidget *widget;
7545   GdkWindow *toplevel;
7546   
7547   g_return_if_fail (GTK_IS_WINDOW (window));
7548
7549   priv = window->priv;
7550   widget = GTK_WIDGET (window);
7551
7552   priv->maximize_initially = TRUE;
7553
7554   toplevel = gtk_widget_get_window (widget);
7555
7556   if (toplevel != NULL)
7557     gdk_window_maximize (toplevel);
7558 }
7559
7560 /**
7561  * gtk_window_unmaximize:
7562  * @window: a #GtkWindow
7563  *
7564  * Asks to unmaximize @window. Note that you shouldn't assume the
7565  * window is definitely unmaximized afterward, because other entities
7566  * (e.g. the user or <link linkend="gtk-X11-arch">window
7567  * manager</link>) could maximize it again, and not all window
7568  * managers honor requests to unmaximize. But normally the window will
7569  * end up unmaximized. Just don't write code that crashes if not.
7570  *
7571  * You can track maximization via the "window-state-event" signal
7572  * on #GtkWidget.
7573  * 
7574  **/
7575 void
7576 gtk_window_unmaximize (GtkWindow *window)
7577 {
7578   GtkWindowPrivate *priv;
7579   GtkWidget *widget;
7580   GdkWindow *toplevel;
7581   
7582   g_return_if_fail (GTK_IS_WINDOW (window));
7583
7584   priv = window->priv;
7585   widget = GTK_WIDGET (window);
7586
7587   priv->maximize_initially = FALSE;
7588
7589   toplevel = gtk_widget_get_window (widget);
7590
7591   if (toplevel != NULL)
7592     gdk_window_unmaximize (toplevel);
7593 }
7594
7595 /**
7596  * gtk_window_fullscreen:
7597  * @window: a #GtkWindow
7598  *
7599  * Asks to place @window in the fullscreen state. Note that you
7600  * shouldn't assume the window is definitely full screen afterward,
7601  * because other entities (e.g. the user or <link
7602  * linkend="gtk-X11-arch">window manager</link>) could unfullscreen it
7603  * again, and not all window managers honor requests to fullscreen
7604  * windows. But normally the window will end up fullscreen. Just
7605  * don't write code that crashes if not.
7606  *
7607  * You can track the fullscreen state via the "window-state-event" signal
7608  * on #GtkWidget.
7609  * 
7610  * Since: 2.2
7611  **/
7612 void
7613 gtk_window_fullscreen (GtkWindow *window)
7614 {
7615   GtkWindowPrivate *priv;
7616   GtkWidget *widget;
7617   GdkWindow *toplevel;
7618
7619   g_return_if_fail (GTK_IS_WINDOW (window));
7620
7621   priv = window->priv;
7622   widget = GTK_WIDGET (window);
7623
7624   priv->fullscreen_initially = TRUE;
7625
7626   toplevel = gtk_widget_get_window (widget);
7627
7628   if (toplevel != NULL)
7629     gdk_window_fullscreen (toplevel);
7630 }
7631
7632 /**
7633  * gtk_window_unfullscreen:
7634  * @window: a #GtkWindow
7635  *
7636  * Asks to toggle off the fullscreen state for @window. Note that you
7637  * shouldn't assume the window is definitely not full screen
7638  * afterward, because other entities (e.g. the user or <link
7639  * linkend="gtk-X11-arch">window manager</link>) could fullscreen it
7640  * again, and not all window managers honor requests to unfullscreen
7641  * windows. But normally the window will end up restored to its normal
7642  * state. Just don't write code that crashes if not.
7643  *
7644  * You can track the fullscreen state via the "window-state-event" signal
7645  * on #GtkWidget.
7646  * 
7647  * Since: 2.2
7648  **/
7649 void
7650 gtk_window_unfullscreen (GtkWindow *window)
7651 {
7652   GtkWidget *widget;
7653   GdkWindow *toplevel;
7654   GtkWindowPrivate *priv;
7655
7656   g_return_if_fail (GTK_IS_WINDOW (window));
7657
7658   priv = window->priv;
7659   widget = GTK_WIDGET (window);
7660
7661   priv->fullscreen_initially = FALSE;
7662
7663   toplevel = gtk_widget_get_window (widget);
7664
7665   if (toplevel != NULL)
7666     gdk_window_unfullscreen (toplevel);
7667 }
7668
7669 /**
7670  * gtk_window_set_keep_above:
7671  * @window: a #GtkWindow
7672  * @setting: whether to keep @window above other windows
7673  *
7674  * Asks to keep @window above, so that it stays on top. Note that
7675  * you shouldn't assume the window is definitely above afterward,
7676  * because other entities (e.g. the user or <link
7677  * linkend="gtk-X11-arch">window manager</link>) could not keep it above,
7678  * and not all window managers support keeping windows above. But
7679  * normally the window will end kept above. Just don't write code
7680  * that crashes if not.
7681  *
7682  * It's permitted to call this function before showing a window,
7683  * in which case the window will be kept above when it appears onscreen
7684  * initially.
7685  *
7686  * You can track the above state via the "window-state-event" signal
7687  * on #GtkWidget.
7688  *
7689  * Note that, according to the <ulink 
7690  * url="http://www.freedesktop.org/Standards/wm-spec">Extended Window 
7691  * Manager Hints</ulink> specification, the above state is mainly meant 
7692  * for user preferences and should not be used by applications e.g. for 
7693  * drawing attention to their dialogs.
7694  *
7695  * Since: 2.4
7696  **/
7697 void
7698 gtk_window_set_keep_above (GtkWindow *window,
7699                            gboolean   setting)
7700 {
7701   GtkWidget *widget;
7702   GtkWindowPrivate *priv;
7703   GdkWindow *toplevel;
7704
7705   g_return_if_fail (GTK_IS_WINDOW (window));
7706
7707   priv = window->priv;
7708   widget = GTK_WIDGET (window);
7709
7710   priv->above_initially = setting != FALSE;
7711   if (setting)
7712     priv->below_initially = FALSE;
7713
7714   toplevel = gtk_widget_get_window (widget);
7715
7716   if (toplevel != NULL)
7717     gdk_window_set_keep_above (toplevel, setting);
7718 }
7719
7720 /**
7721  * gtk_window_set_keep_below:
7722  * @window: a #GtkWindow
7723  * @setting: whether to keep @window below other windows
7724  *
7725  * Asks to keep @window below, so that it stays in bottom. Note that
7726  * you shouldn't assume the window is definitely below afterward,
7727  * because other entities (e.g. the user or <link
7728  * linkend="gtk-X11-arch">window manager</link>) could not keep it below,
7729  * and not all window managers support putting windows below. But
7730  * normally the window will be kept below. Just don't write code
7731  * that crashes if not.
7732  *
7733  * It's permitted to call this function before showing a window,
7734  * in which case the window will be kept below when it appears onscreen
7735  * initially.
7736  *
7737  * You can track the below state via the "window-state-event" signal
7738  * on #GtkWidget.
7739  *
7740  * Note that, according to the <ulink 
7741  * url="http://www.freedesktop.org/Standards/wm-spec">Extended Window 
7742  * Manager Hints</ulink> specification, the above state is mainly meant 
7743  * for user preferences and should not be used by applications e.g. for 
7744  * drawing attention to their dialogs.
7745  *
7746  * Since: 2.4
7747  **/
7748 void
7749 gtk_window_set_keep_below (GtkWindow *window,
7750                            gboolean   setting)
7751 {
7752   GtkWidget *widget;
7753   GtkWindowPrivate *priv;
7754   GdkWindow *toplevel;
7755
7756   g_return_if_fail (GTK_IS_WINDOW (window));
7757
7758   priv = window->priv;
7759   widget = GTK_WIDGET (window);
7760
7761   priv->below_initially = setting != FALSE;
7762   if (setting)
7763     priv->above_initially = FALSE;
7764
7765   toplevel = gtk_widget_get_window (widget);
7766
7767   if (toplevel != NULL)
7768     gdk_window_set_keep_below (toplevel, setting);
7769 }
7770
7771 /**
7772  * gtk_window_set_resizable:
7773  * @window: a #GtkWindow
7774  * @resizable: %TRUE if the user can resize this window
7775  *
7776  * Sets whether the user can resize a window. Windows are user resizable
7777  * by default.
7778  **/
7779 void
7780 gtk_window_set_resizable (GtkWindow *window,
7781                           gboolean   resizable)
7782 {
7783   GtkWindowPrivate *priv;
7784
7785   g_return_if_fail (GTK_IS_WINDOW (window));
7786
7787   priv = window->priv;
7788
7789   resizable = (resizable != FALSE);
7790
7791   if (priv->resizable != resizable)
7792     {
7793       priv->resizable = (resizable != FALSE);
7794
7795       update_grip_visibility (window);
7796
7797       gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window));
7798
7799       g_object_notify (G_OBJECT (window), "resizable");
7800     }
7801 }
7802
7803 /**
7804  * gtk_window_get_resizable:
7805  * @window: a #GtkWindow
7806  *
7807  * Gets the value set by gtk_window_set_resizable().
7808  *
7809  * Return value: %TRUE if the user can resize the window
7810  **/
7811 gboolean
7812 gtk_window_get_resizable (GtkWindow *window)
7813 {
7814   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
7815
7816   return window->priv->resizable;
7817 }
7818
7819 /**
7820  * gtk_window_set_gravity:
7821  * @window: a #GtkWindow
7822  * @gravity: window gravity
7823  *
7824  * Window gravity defines the meaning of coordinates passed to
7825  * gtk_window_move(). See gtk_window_move() and #GdkGravity for
7826  * more details.
7827  *
7828  * The default window gravity is #GDK_GRAVITY_NORTH_WEST which will
7829  * typically "do what you mean."
7830  *
7831  **/
7832 void
7833 gtk_window_set_gravity (GtkWindow *window,
7834                         GdkGravity gravity)
7835 {
7836   GtkWindowPrivate *priv;
7837
7838   g_return_if_fail (GTK_IS_WINDOW (window));
7839
7840   priv = window->priv;
7841
7842   if (gravity != priv->gravity)
7843     {
7844       priv->gravity = gravity;
7845
7846       /* gtk_window_move_resize() will adapt gravity
7847        */
7848       gtk_widget_queue_resize_no_redraw (GTK_WIDGET (window));
7849
7850       g_object_notify (G_OBJECT (window), "gravity");
7851     }
7852 }
7853
7854 /**
7855  * gtk_window_get_gravity:
7856  * @window: a #GtkWindow
7857  *
7858  * Gets the value set by gtk_window_set_gravity().
7859  *
7860  * Return value: (transfer none): window gravity
7861  **/
7862 GdkGravity
7863 gtk_window_get_gravity (GtkWindow *window)
7864 {
7865   g_return_val_if_fail (GTK_IS_WINDOW (window), 0);
7866
7867   return window->priv->gravity;
7868 }
7869
7870 /**
7871  * gtk_window_begin_resize_drag:
7872  * @window: a #GtkWindow
7873  * @button: mouse button that initiated the drag
7874  * @edge: position of the resize control
7875  * @root_x: X position where the user clicked to initiate the drag, in root window coordinates
7876  * @root_y: Y position where the user clicked to initiate the drag
7877  * @timestamp: timestamp from the click event that initiated the drag
7878  *
7879  * Starts resizing a window. This function is used if an application
7880  * has window resizing controls. When GDK can support it, the resize
7881  * will be done using the standard mechanism for the <link
7882  * linkend="gtk-X11-arch">window manager</link> or windowing
7883  * system. Otherwise, GDK will try to emulate window resizing,
7884  * potentially not all that well, depending on the windowing system.
7885  * 
7886  **/
7887 void
7888 gtk_window_begin_resize_drag  (GtkWindow    *window,
7889                                GdkWindowEdge edge,
7890                                gint          button,
7891                                gint          root_x,
7892                                gint          root_y,
7893                                guint32       timestamp)
7894 {
7895   GtkWidget *widget;
7896   GdkWindow *toplevel;
7897
7898   g_return_if_fail (GTK_IS_WINDOW (window));
7899   widget = GTK_WIDGET (window);
7900   g_return_if_fail (gtk_widget_get_visible (widget));
7901
7902   toplevel = gtk_widget_get_window (widget);
7903
7904   gdk_window_begin_resize_drag (toplevel,
7905                                 edge, button,
7906                                 root_x, root_y,
7907                                 timestamp);
7908 }
7909
7910 /**
7911  * gtk_window_begin_move_drag:
7912  * @window: a #GtkWindow
7913  * @button: mouse button that initiated the drag
7914  * @root_x: X position where the user clicked to initiate the drag, in root window coordinates
7915  * @root_y: Y position where the user clicked to initiate the drag
7916  * @timestamp: timestamp from the click event that initiated the drag
7917  *
7918  * Starts moving a window. This function is used if an application has
7919  * window movement grips. When GDK can support it, the window movement
7920  * will be done using the standard mechanism for the <link
7921  * linkend="gtk-X11-arch">window manager</link> or windowing
7922  * system. Otherwise, GDK will try to emulate window movement,
7923  * potentially not all that well, depending on the windowing system.
7924  * 
7925  **/
7926 void
7927 gtk_window_begin_move_drag  (GtkWindow *window,
7928                              gint       button,
7929                              gint       root_x,
7930                              gint       root_y,
7931                              guint32    timestamp)
7932 {
7933   GtkWidget *widget;
7934   GdkWindow *toplevel;
7935
7936   g_return_if_fail (GTK_IS_WINDOW (window));
7937   widget = GTK_WIDGET (window);
7938   g_return_if_fail (gtk_widget_get_visible (widget));
7939
7940   toplevel = gtk_widget_get_window (widget);
7941
7942   gdk_window_begin_move_drag (toplevel,
7943                               button,
7944                               root_x, root_y,
7945                               timestamp);
7946 }
7947
7948 /**
7949  * gtk_window_set_screen:
7950  * @window: a #GtkWindow.
7951  * @screen: a #GdkScreen.
7952  *
7953  * Sets the #GdkScreen where the @window is displayed; if
7954  * the window is already mapped, it will be unmapped, and
7955  * then remapped on the new screen.
7956  *
7957  * Since: 2.2
7958  */
7959 void
7960 gtk_window_set_screen (GtkWindow *window,
7961                        GdkScreen *screen)
7962 {
7963   GtkWindowPrivate *priv;
7964   GtkWidget *widget;
7965   GdkScreen *previous_screen;
7966   gboolean was_mapped;
7967
7968   g_return_if_fail (GTK_IS_WINDOW (window));
7969   g_return_if_fail (GDK_IS_SCREEN (screen));
7970
7971   priv = window->priv;
7972
7973   if (screen == priv->screen)
7974     return;
7975
7976   widget = GTK_WIDGET (window);
7977
7978   previous_screen = priv->screen;
7979   was_mapped = gtk_widget_get_mapped (widget);
7980
7981   if (was_mapped)
7982     gtk_widget_unmap (widget);
7983   if (gtk_widget_get_realized (widget))
7984     gtk_widget_unrealize (widget);
7985
7986   gtk_window_free_key_hash (window);
7987   priv->screen = screen;
7988   gtk_widget_reset_rc_styles (widget);
7989   if (screen != previous_screen)
7990     {
7991       if (previous_screen)
7992         g_signal_handlers_disconnect_by_func (previous_screen,
7993                                               gtk_window_on_composited_changed, window);
7994       g_signal_connect (screen, "composited-changed",
7995                         G_CALLBACK (gtk_window_on_composited_changed), window);
7996
7997       _gtk_widget_propagate_screen_changed (widget, previous_screen);
7998       _gtk_widget_propagate_composited_changed (widget);
7999     }
8000   g_object_notify (G_OBJECT (window), "screen");
8001
8002   if (was_mapped)
8003     gtk_widget_map (widget);
8004 }
8005
8006 static void
8007 gtk_window_on_composited_changed (GdkScreen *screen,
8008                                   GtkWindow *window)
8009 {
8010   gtk_widget_queue_draw (GTK_WIDGET (window));
8011   
8012   _gtk_widget_propagate_composited_changed (GTK_WIDGET (window));
8013 }
8014
8015 static GdkScreen *
8016 gtk_window_check_screen (GtkWindow *window)
8017 {
8018   GtkWindowPrivate *priv = window->priv;
8019
8020   if (priv->screen)
8021     return priv->screen;
8022   else
8023     {
8024       g_warning ("Screen for GtkWindow not set; you must always set\n"
8025                  "a screen for a GtkWindow before using the window");
8026       return NULL;
8027     }
8028 }
8029
8030 /**
8031  * gtk_window_get_screen:
8032  * @window: a #GtkWindow.
8033  *
8034  * Returns the #GdkScreen associated with @window.
8035  *
8036  * Return value: (transfer none): a #GdkScreen.
8037  *
8038  * Since: 2.2
8039  */
8040 GdkScreen*
8041 gtk_window_get_screen (GtkWindow *window)
8042 {
8043   g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
8044
8045   return window->priv->screen;
8046 }
8047
8048 /**
8049  * gtk_window_is_active:
8050  * @window: a #GtkWindow
8051  * 
8052  * Returns whether the window is part of the current active toplevel.
8053  * (That is, the toplevel window receiving keystrokes.)
8054  * The return value is %TRUE if the window is active toplevel
8055  * itself, but also if it is, say, a #GtkPlug embedded in the active toplevel.
8056  * You might use this function if you wanted to draw a widget
8057  * differently in an active window from a widget in an inactive window.
8058  * See gtk_window_has_toplevel_focus()
8059  * 
8060  * Return value: %TRUE if the window part of the current active window.
8061  *
8062  * Since: 2.4
8063  **/
8064 gboolean
8065 gtk_window_is_active (GtkWindow *window)
8066 {
8067   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
8068
8069   return window->priv->is_active;
8070 }
8071
8072 /**
8073  * gtk_window_has_toplevel_focus:
8074  * @window: a #GtkWindow
8075  * 
8076  * Returns whether the input focus is within this GtkWindow.
8077  * For real toplevel windows, this is identical to gtk_window_is_active(),
8078  * but for embedded windows, like #GtkPlug, the results will differ.
8079  * 
8080  * Return value: %TRUE if the input focus is within this GtkWindow
8081  *
8082  * Since: 2.4
8083  **/
8084 gboolean
8085 gtk_window_has_toplevel_focus (GtkWindow *window)
8086 {
8087   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
8088
8089   return window->priv->has_toplevel_focus;
8090 }
8091
8092 G_DEFINE_TYPE (GtkWindowGroup, gtk_window_group, G_TYPE_OBJECT)
8093
8094 static void
8095 gtk_window_group_init (GtkWindowGroup *group)
8096 {
8097   group->priv = G_TYPE_INSTANCE_GET_PRIVATE (group,
8098                                              GTK_TYPE_WINDOW_GROUP,
8099                                              GtkWindowGroupPrivate);
8100 }
8101
8102 static void
8103 gtk_window_group_class_init (GtkWindowGroupClass *klass)
8104 {
8105   g_type_class_add_private (klass, sizeof (GtkWindowGroupPrivate));
8106 }
8107
8108 /**
8109  * gtk_window_group_new:
8110  * 
8111  * Creates a new #GtkWindowGroup object. Grabs added with
8112  * gtk_grab_add() only affect windows within the same #GtkWindowGroup.
8113  * 
8114  * Return value: a new #GtkWindowGroup. 
8115  **/
8116 GtkWindowGroup *
8117 gtk_window_group_new (void)
8118 {
8119   return g_object_new (GTK_TYPE_WINDOW_GROUP, NULL);
8120 }
8121
8122 static void
8123 window_group_cleanup_grabs (GtkWindowGroup *group,
8124                             GtkWindow      *window)
8125 {
8126   GtkWindowGroupPrivate *priv;
8127   GtkDeviceGrabInfo *info;
8128   GSList *tmp_list;
8129   GSList *to_remove = NULL;
8130
8131   priv = group->priv;
8132
8133   tmp_list = priv->grabs;
8134   while (tmp_list)
8135     {
8136       if (gtk_widget_get_toplevel (tmp_list->data) == (GtkWidget*) window)
8137         to_remove = g_slist_prepend (to_remove, g_object_ref (tmp_list->data));
8138       tmp_list = tmp_list->next;
8139     }
8140
8141   while (to_remove)
8142     {
8143       gtk_grab_remove (to_remove->data);
8144       g_object_unref (to_remove->data);
8145       to_remove = g_slist_delete_link (to_remove, to_remove);
8146     }
8147
8148   tmp_list = priv->device_grabs;
8149
8150   while (tmp_list)
8151     {
8152       info = tmp_list->data;
8153
8154       if (gtk_widget_get_toplevel (info->widget) == (GtkWidget *) window)
8155         to_remove = g_slist_prepend (to_remove, info);
8156
8157       tmp_list = tmp_list->next;
8158     }
8159
8160   while (to_remove)
8161     {
8162       info = to_remove->data;
8163
8164       gtk_device_grab_remove (info->widget, info->device);
8165       to_remove = g_slist_delete_link (to_remove, to_remove);
8166     }
8167 }
8168
8169 /**
8170  * gtk_window_group_add_window:
8171  * @window_group: a #GtkWindowGroup
8172  * @window: the #GtkWindow to add
8173  * 
8174  * Adds a window to a #GtkWindowGroup. 
8175  **/
8176 void
8177 gtk_window_group_add_window (GtkWindowGroup *window_group,
8178                              GtkWindow      *window)
8179 {
8180   GtkWindowPrivate *priv;
8181
8182   g_return_if_fail (GTK_IS_WINDOW_GROUP (window_group));
8183   g_return_if_fail (GTK_IS_WINDOW (window));
8184
8185   priv = window->priv;
8186
8187   if (priv->group != window_group)
8188     {
8189       g_object_ref (window);
8190       g_object_ref (window_group);
8191
8192       if (priv->group)
8193         gtk_window_group_remove_window (priv->group, window);
8194       else
8195         window_group_cleanup_grabs (gtk_window_get_group (NULL), window);
8196
8197       priv->group = window_group;
8198
8199       g_object_unref (window);
8200     }
8201 }
8202
8203 /**
8204  * gtk_window_group_remove_window:
8205  * @window_group: a #GtkWindowGroup
8206  * @window: the #GtkWindow to remove
8207  * 
8208  * Removes a window from a #GtkWindowGroup.
8209  **/
8210 void
8211 gtk_window_group_remove_window (GtkWindowGroup *window_group,
8212                                 GtkWindow      *window)
8213 {
8214   GtkWindowPrivate *priv;
8215
8216   g_return_if_fail (GTK_IS_WINDOW_GROUP (window_group));
8217   g_return_if_fail (GTK_IS_WINDOW (window));
8218   priv = window->priv;
8219   g_return_if_fail (priv->group == window_group);
8220
8221   g_object_ref (window);
8222
8223   window_group_cleanup_grabs (window_group, window);
8224   priv->group = NULL;
8225
8226   g_object_unref (window_group);
8227   g_object_unref (window);
8228 }
8229
8230 /**
8231  * gtk_window_group_list_windows:
8232  * @window_group: a #GtkWindowGroup
8233  *
8234  * Returns a list of the #GtkWindows that belong to @window_group.
8235  *
8236  * Returns: (element-type GtkWindow) (transfer container): A
8237  *   newly-allocated list of windows inside the group.
8238  *
8239  * Since: 2.14
8240  **/
8241 GList *
8242 gtk_window_group_list_windows (GtkWindowGroup *window_group)
8243 {
8244   GList *toplevels, *toplevel, *group_windows;
8245
8246   g_return_val_if_fail (GTK_IS_WINDOW_GROUP (window_group), NULL);
8247
8248   group_windows = NULL;
8249   toplevels = gtk_window_list_toplevels ();
8250
8251   for (toplevel = toplevels; toplevel; toplevel = toplevel->next)
8252     {
8253       GtkWindow *window = toplevel->data;
8254
8255       if (window_group == window->priv->group)
8256         group_windows = g_list_prepend (group_windows, window);
8257     }
8258
8259   g_list_free (toplevels);
8260
8261   return g_list_reverse (group_windows);
8262 }
8263
8264 /**
8265  * gtk_window_get_group:
8266  * @window: (allow-none): a #GtkWindow, or %NULL
8267  *
8268  * Returns the group for @window or the default group, if
8269  * @window is %NULL or if @window does not have an explicit
8270  * window group.
8271  *
8272  * Returns: (transfer none): the #GtkWindowGroup for a window or the default group
8273  *
8274  * Since: 2.10
8275  */
8276 GtkWindowGroup *
8277 gtk_window_get_group (GtkWindow *window)
8278 {
8279   if (window && window->priv->group)
8280     return window->priv->group;
8281   else
8282     {
8283       static GtkWindowGroup *default_group = NULL;
8284
8285       if (!default_group)
8286         default_group = gtk_window_group_new ();
8287
8288       return default_group;
8289     }
8290 }
8291
8292 /**
8293  * gtk_window_has_group:
8294  * @window: a #GtkWindow
8295  *
8296  * Returns whether @window has an explicit window group.
8297  *
8298  * Return value: %TRUE if @window has an explicit window group.
8299  *
8300  * Since 2.22
8301  **/
8302 gboolean
8303 gtk_window_has_group (GtkWindow *window)
8304 {
8305   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
8306
8307   return window->priv->group != NULL;
8308 }
8309
8310 /**
8311  * gtk_window_group_get_current_grab:
8312  * @window_group: a #GtkWindowGroup
8313  *
8314  * Gets the current grab widget of the given group,
8315  * see gtk_grab_add().
8316  *
8317  * Returns: (transfer none): the current grab widget of the group
8318  *
8319  * Since: 2.22
8320  */
8321 GtkWidget *
8322 gtk_window_group_get_current_grab (GtkWindowGroup *window_group)
8323 {
8324   g_return_val_if_fail (GTK_IS_WINDOW_GROUP (window_group), NULL);
8325
8326   if (window_group->priv->grabs)
8327     return GTK_WIDGET (window_group->priv->grabs->data);
8328   return NULL;
8329 }
8330
8331 void
8332 _gtk_window_group_add_grab (GtkWindowGroup *window_group,
8333                             GtkWidget      *widget)
8334 {
8335   GtkWindowGroupPrivate *priv;
8336
8337   priv = window_group->priv;
8338   priv->grabs = g_slist_prepend (priv->grabs, widget);
8339 }
8340
8341 void
8342 _gtk_window_group_remove_grab (GtkWindowGroup *window_group,
8343                                GtkWidget      *widget)
8344 {
8345   GtkWindowGroupPrivate *priv;
8346
8347   priv = window_group->priv;
8348   priv->grabs = g_slist_remove (priv->grabs, widget);
8349 }
8350
8351
8352 void
8353 _gtk_window_group_add_device_grab (GtkWindowGroup *window_group,
8354                                    GtkWidget      *widget,
8355                                    GdkDevice      *device,
8356                                    gboolean        block_others)
8357 {
8358   GtkWindowGroupPrivate *priv;
8359   GtkDeviceGrabInfo *info;
8360
8361   priv = window_group->priv;
8362
8363   info = g_slice_new0 (GtkDeviceGrabInfo);
8364   info->widget = widget;
8365   info->device = device;
8366   info->block_others = block_others;
8367
8368   priv->device_grabs = g_slist_prepend (priv->device_grabs, info);
8369 }
8370
8371 void
8372 _gtk_window_group_remove_device_grab (GtkWindowGroup *window_group,
8373                                       GtkWidget      *widget,
8374                                       GdkDevice      *device)
8375 {
8376   GtkWindowGroupPrivate *priv;
8377   GtkDeviceGrabInfo *info;
8378   GSList *list, *node = NULL;
8379   GdkDevice *other_device;
8380
8381   priv = window_group->priv;
8382   other_device = gdk_device_get_associated_device (device);
8383   list = priv->device_grabs;
8384
8385   while (list)
8386     {
8387       info = list->data;
8388
8389       if (info->widget == widget &&
8390           (info->device == device ||
8391            info->device == other_device))
8392         {
8393           node = list;
8394           break;
8395         }
8396
8397       list = list->next;
8398     }
8399
8400   if (node)
8401     {
8402       info = node->data;
8403
8404       priv->device_grabs = g_slist_delete_link (priv->device_grabs, node);
8405       g_slice_free (GtkDeviceGrabInfo, info);
8406     }
8407 }
8408
8409 /**
8410  * gtk_window_group_get_current_device_grab:
8411  * @window_group: a #GtkWindowGroup
8412  * @device: a #GdkDevice
8413  *
8414  * Returns the current grab widget for @device, or %NULL if none.
8415  *
8416  * Returns: (transfer none): The grab widget, or %NULL
8417  *
8418  * Since: 3.0
8419  */
8420 GtkWidget *
8421 gtk_window_group_get_current_device_grab (GtkWindowGroup *window_group,
8422                                           GdkDevice      *device)
8423 {
8424   GtkWindowGroupPrivate *priv;
8425   GtkDeviceGrabInfo *info;
8426   GdkDevice *other_device;
8427   GSList *list;
8428
8429   g_return_val_if_fail (GTK_IS_WINDOW_GROUP (window_group), NULL);
8430   g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
8431
8432   priv = window_group->priv;
8433   list = priv->device_grabs;
8434   other_device = gdk_device_get_associated_device (device);
8435
8436   while (list)
8437     {
8438       info = list->data;
8439       list = list->next;
8440
8441       if (info->device == device ||
8442           info->device == other_device)
8443         return info->widget;
8444     }
8445
8446   return NULL;
8447 }
8448
8449 gboolean
8450 _gtk_window_group_widget_is_blocked_for_device (GtkWindowGroup *window_group,
8451                                                 GtkWidget      *widget,
8452                                                 GdkDevice      *device)
8453 {
8454   GtkWindowGroupPrivate *priv;
8455   GtkDeviceGrabInfo *info;
8456   GdkDevice *other_device;
8457   GSList *list;
8458
8459   priv = window_group->priv;
8460   other_device = gdk_device_get_associated_device (device);
8461   list = priv->device_grabs;
8462
8463   while (list)
8464     {
8465       info = list->data;
8466       list = list->next;
8467
8468       /* Look for blocking grabs on other device pairs
8469        * that have the passed widget within the GTK+ grab.
8470        */
8471       if (info->block_others &&
8472           info->device != device &&
8473           info->device != other_device &&
8474           (info->widget == widget ||
8475            gtk_widget_is_ancestor (widget, info->widget)))
8476         return TRUE;
8477     }
8478
8479   return FALSE;
8480 }
8481
8482 /*
8483   Derived from XParseGeometry() in XFree86  
8484
8485   Copyright 1985, 1986, 1987,1998  The Open Group
8486
8487   All Rights Reserved.
8488
8489   The above copyright notice and this permission notice shall be included
8490   in all copies or substantial portions of the Software.
8491
8492   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
8493   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
8494   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
8495   IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
8496   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
8497   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
8498   OTHER DEALINGS IN THE SOFTWARE.
8499
8500   Except as contained in this notice, the name of The Open Group shall
8501   not be used in advertising or otherwise to promote the sale, use or
8502   other dealings in this Software without prior written authorization
8503   from The Open Group.
8504 */
8505
8506
8507 /*
8508  *    XParseGeometry parses strings of the form
8509  *   "=<width>x<height>{+-}<xoffset>{+-}<yoffset>", where
8510  *   width, height, xoffset, and yoffset are unsigned integers.
8511  *   Example:  "=80x24+300-49"
8512  *   The equal sign is optional.
8513  *   It returns a bitmask that indicates which of the four values
8514  *   were actually found in the string.  For each value found,
8515  *   the corresponding argument is updated;  for each value
8516  *   not found, the corresponding argument is left unchanged. 
8517  */
8518
8519 /* The following code is from Xlib, and is minimally modified, so we
8520  * can track any upstream changes if required.  Don't change this
8521  * code. Or if you do, put in a huge comment marking which thing
8522  * changed.
8523  */
8524
8525 static int
8526 read_int (gchar   *string,
8527           gchar  **next)
8528 {
8529   int result = 0;
8530   int sign = 1;
8531   
8532   if (*string == '+')
8533     string++;
8534   else if (*string == '-')
8535     {
8536       string++;
8537       sign = -1;
8538     }
8539
8540   for (; (*string >= '0') && (*string <= '9'); string++)
8541     {
8542       result = (result * 10) + (*string - '0');
8543     }
8544
8545   *next = string;
8546
8547   if (sign >= 0)
8548     return (result);
8549   else
8550     return (-result);
8551 }
8552
8553 /* 
8554  * Bitmask returned by XParseGeometry().  Each bit tells if the corresponding
8555  * value (x, y, width, height) was found in the parsed string.
8556  */
8557 #define NoValue         0x0000
8558 #define XValue          0x0001
8559 #define YValue          0x0002
8560 #define WidthValue      0x0004
8561 #define HeightValue     0x0008
8562 #define AllValues       0x000F
8563 #define XNegative       0x0010
8564 #define YNegative       0x0020
8565
8566 /* Try not to reformat/modify, so we can compare/sync with X sources */
8567 static int
8568 gtk_XParseGeometry (const char   *string,
8569                     int          *x,
8570                     int          *y,
8571                     unsigned int *width,   
8572                     unsigned int *height)  
8573 {
8574   int mask = NoValue;
8575   char *strind;
8576   unsigned int tempWidth, tempHeight;
8577   int tempX, tempY;
8578   char *nextCharacter;
8579
8580   /* These initializations are just to silence gcc */
8581   tempWidth = 0;
8582   tempHeight = 0;
8583   tempX = 0;
8584   tempY = 0;
8585   
8586   if ( (string == NULL) || (*string == '\0')) return(mask);
8587   if (*string == '=')
8588     string++;  /* ignore possible '=' at beg of geometry spec */
8589
8590   strind = (char *)string;
8591   if (*strind != '+' && *strind != '-' && *strind != 'x') {
8592     tempWidth = read_int(strind, &nextCharacter);
8593     if (strind == nextCharacter) 
8594       return (0);
8595     strind = nextCharacter;
8596     mask |= WidthValue;
8597   }
8598
8599   if (*strind == 'x' || *strind == 'X') {       
8600     strind++;
8601     tempHeight = read_int(strind, &nextCharacter);
8602     if (strind == nextCharacter)
8603       return (0);
8604     strind = nextCharacter;
8605     mask |= HeightValue;
8606   }
8607
8608   if ((*strind == '+') || (*strind == '-')) {
8609     if (*strind == '-') {
8610       strind++;
8611       tempX = -read_int(strind, &nextCharacter);
8612       if (strind == nextCharacter)
8613         return (0);
8614       strind = nextCharacter;
8615       mask |= XNegative;
8616
8617     }
8618     else
8619       { strind++;
8620       tempX = read_int(strind, &nextCharacter);
8621       if (strind == nextCharacter)
8622         return(0);
8623       strind = nextCharacter;
8624       }
8625     mask |= XValue;
8626     if ((*strind == '+') || (*strind == '-')) {
8627       if (*strind == '-') {
8628         strind++;
8629         tempY = -read_int(strind, &nextCharacter);
8630         if (strind == nextCharacter)
8631           return(0);
8632         strind = nextCharacter;
8633         mask |= YNegative;
8634
8635       }
8636       else
8637         {
8638           strind++;
8639           tempY = read_int(strind, &nextCharacter);
8640           if (strind == nextCharacter)
8641             return(0);
8642           strind = nextCharacter;
8643         }
8644       mask |= YValue;
8645     }
8646   }
8647         
8648   /* If strind isn't at the end of the string the it's an invalid
8649                 geometry specification. */
8650
8651   if (*strind != '\0') return (0);
8652
8653   if (mask & XValue)
8654     *x = tempX;
8655   if (mask & YValue)
8656     *y = tempY;
8657   if (mask & WidthValue)
8658     *width = tempWidth;
8659   if (mask & HeightValue)
8660     *height = tempHeight;
8661   return (mask);
8662 }
8663
8664 /**
8665  * gtk_window_parse_geometry:
8666  * @window: a #GtkWindow
8667  * @geometry: geometry string
8668  * 
8669  * Parses a standard X Window System geometry string - see the
8670  * manual page for X (type 'man X') for details on this.
8671  * gtk_window_parse_geometry() does work on all GTK+ ports
8672  * including Win32 but is primarily intended for an X environment.
8673  *
8674  * If either a size or a position can be extracted from the
8675  * geometry string, gtk_window_parse_geometry() returns %TRUE
8676  * and calls gtk_window_set_default_size() and/or gtk_window_move()
8677  * to resize/move the window.
8678  *
8679  * If gtk_window_parse_geometry() returns %TRUE, it will also
8680  * set the #GDK_HINT_USER_POS and/or #GDK_HINT_USER_SIZE hints
8681  * indicating to the window manager that the size/position of
8682  * the window was user-specified. This causes most window
8683  * managers to honor the geometry.
8684  *
8685  * Note that for gtk_window_parse_geometry() to work as expected, it has
8686  * to be called when the window has its "final" size, i.e. after calling
8687  * gtk_widget_show_all() on the contents and gtk_window_set_geometry_hints()
8688  * on the window.
8689  * |[
8690  * #include <gtk/gtk.h>
8691  *    
8692  * static void
8693  * fill_with_content (GtkWidget *vbox)
8694  * {
8695  *   /&ast; fill with content... &ast;/
8696  * }
8697  *    
8698  * int
8699  * main (int argc, char *argv[])
8700  * {
8701  *   GtkWidget *window, *vbox;
8702  *   GdkGeometry size_hints = {
8703  *     100, 50, 0, 0, 100, 50, 10, 10, 0.0, 0.0, GDK_GRAVITY_NORTH_WEST  
8704  *   };
8705  *    
8706  *   gtk_init (&argc, &argv);
8707  *   
8708  *   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
8709  *   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0);
8710  *   
8711  *   gtk_container_add (GTK_CONTAINER (window), vbox);
8712  *   fill_with_content (vbox);
8713  *   gtk_widget_show_all (vbox);
8714  *   
8715  *   gtk_window_set_geometry_hints (GTK_WINDOW (window),
8716  *                                  window,
8717  *                                  &size_hints,
8718  *                                  GDK_HINT_MIN_SIZE | 
8719  *                                  GDK_HINT_BASE_SIZE | 
8720  *                                  GDK_HINT_RESIZE_INC);
8721  *   
8722  *   if (argc &gt; 1)
8723  *     {
8724  *       if (!gtk_window_parse_geometry (GTK_WINDOW (window), argv[1]))
8725  *         fprintf (stderr, "Failed to parse '%s'\n", argv[1]);
8726  *     }
8727  *    
8728  *   gtk_widget_show_all (window);
8729  *   gtk_main ();
8730  *    
8731  *   return 0;
8732  * }
8733  * ]|
8734  *
8735  * Return value: %TRUE if string was parsed successfully
8736  **/
8737 gboolean
8738 gtk_window_parse_geometry (GtkWindow   *window,
8739                            const gchar *geometry)
8740 {
8741   gint result, x = 0, y = 0;
8742   guint w, h;
8743   GtkWidget *child;
8744   GdkGravity grav;
8745   gboolean size_set, pos_set;
8746   GdkScreen *screen;
8747   
8748   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
8749   g_return_val_if_fail (geometry != NULL, FALSE);
8750
8751   child = gtk_bin_get_child (GTK_BIN (window));
8752   if (!child || !gtk_widget_get_visible (child))
8753     g_warning ("gtk_window_parse_geometry() called on a window with no "
8754                "visible children; the window should be set up before "
8755                "gtk_window_parse_geometry() is called.");
8756
8757   screen = gtk_window_check_screen (window);
8758   
8759   result = gtk_XParseGeometry (geometry, &x, &y, &w, &h);
8760
8761   size_set = FALSE;
8762   if ((result & WidthValue) || (result & HeightValue))
8763     {
8764       gtk_window_set_default_size_internal (window, 
8765                                             TRUE, result & WidthValue ? w : -1,
8766                                             TRUE, result & HeightValue ? h : -1, 
8767                                             TRUE);
8768       size_set = TRUE;
8769     }
8770
8771   gtk_window_get_size (window, (gint *)&w, (gint *)&h);
8772   
8773   grav = GDK_GRAVITY_NORTH_WEST;
8774
8775   if ((result & XNegative) && (result & YNegative))
8776     grav = GDK_GRAVITY_SOUTH_EAST;
8777   else if (result & XNegative)
8778     grav = GDK_GRAVITY_NORTH_EAST;
8779   else if (result & YNegative)
8780     grav = GDK_GRAVITY_SOUTH_WEST;
8781
8782   if ((result & XValue) == 0)
8783     x = 0;
8784
8785   if ((result & YValue) == 0)
8786     y = 0;
8787
8788   if (grav == GDK_GRAVITY_SOUTH_WEST ||
8789       grav == GDK_GRAVITY_SOUTH_EAST)
8790     y = gdk_screen_get_height (screen) - h + y;
8791
8792   if (grav == GDK_GRAVITY_SOUTH_EAST ||
8793       grav == GDK_GRAVITY_NORTH_EAST)
8794     x = gdk_screen_get_width (screen) - w + x;
8795
8796   /* we don't let you put a window offscreen; maybe some people would
8797    * prefer to be able to, but it's kind of a bogus thing to do.
8798    */
8799   if (y < 0)
8800     y = 0;
8801
8802   if (x < 0)
8803     x = 0;
8804
8805   pos_set = FALSE;
8806   if ((result & XValue) || (result & YValue))
8807     {
8808       gtk_window_set_gravity (window, grav);
8809       gtk_window_move (window, x, y);
8810       pos_set = TRUE;
8811     }
8812
8813   if (size_set || pos_set)
8814     {
8815       /* Set USSize, USPosition hints */
8816       GtkWindowGeometryInfo *info;
8817
8818       info = gtk_window_get_geometry_info (window, TRUE);
8819
8820       if (pos_set)
8821         info->mask |= GDK_HINT_USER_POS;
8822       if (size_set)
8823         info->mask |= GDK_HINT_USER_SIZE;
8824     }
8825   
8826   return result != 0;
8827 }
8828
8829 static void
8830 gtk_window_mnemonic_hash_foreach (guint      keyval,
8831                                   GSList    *targets,
8832                                   gpointer   data)
8833 {
8834   struct {
8835     GtkWindow *window;
8836     GtkWindowKeysForeachFunc func;
8837     gpointer func_data;
8838   } *info = data;
8839
8840   (*info->func) (info->window, keyval, info->window->priv->mnemonic_modifier, TRUE, info->func_data);
8841 }
8842
8843 void
8844 _gtk_window_keys_foreach (GtkWindow                *window,
8845                           GtkWindowKeysForeachFunc func,
8846                           gpointer                 func_data)
8847 {
8848   GSList *groups;
8849   GtkMnemonicHash *mnemonic_hash;
8850
8851   struct {
8852     GtkWindow *window;
8853     GtkWindowKeysForeachFunc func;
8854     gpointer func_data;
8855   } info;
8856
8857   info.window = window;
8858   info.func = func;
8859   info.func_data = func_data;
8860
8861   mnemonic_hash = gtk_window_get_mnemonic_hash (window, FALSE);
8862   if (mnemonic_hash)
8863     _gtk_mnemonic_hash_foreach (mnemonic_hash,
8864                                 gtk_window_mnemonic_hash_foreach, &info);
8865
8866   groups = gtk_accel_groups_from_object (G_OBJECT (window));
8867   while (groups)
8868     {
8869       GtkAccelGroup *group = groups->data;
8870       gint i;
8871
8872       for (i = 0; i < group->priv->n_accels; i++)
8873         {
8874           GtkAccelKey *key = &group->priv->priv_accels[i].key;
8875           
8876           if (key->accel_key)
8877             (*func) (window, key->accel_key, key->accel_mods, FALSE, func_data);
8878         }
8879       
8880       groups = groups->next;
8881     }
8882 }
8883
8884 static void
8885 gtk_window_keys_changed (GtkWindow *window)
8886 {
8887   gtk_window_free_key_hash (window);
8888   gtk_window_get_key_hash (window);
8889 }
8890
8891 typedef struct _GtkWindowKeyEntry GtkWindowKeyEntry;
8892
8893 struct _GtkWindowKeyEntry
8894 {
8895   guint keyval;
8896   guint modifiers;
8897   guint is_mnemonic : 1;
8898 };
8899
8900 static void 
8901 window_key_entry_destroy (gpointer data)
8902 {
8903   g_slice_free (GtkWindowKeyEntry, data);
8904 }
8905
8906 static void
8907 add_to_key_hash (GtkWindow      *window,
8908                  guint           keyval,
8909                  GdkModifierType modifiers,
8910                  gboolean        is_mnemonic,
8911                  gpointer        data)
8912 {
8913   GtkKeyHash *key_hash = data;
8914
8915   GtkWindowKeyEntry *entry = g_slice_new (GtkWindowKeyEntry);
8916
8917   entry->keyval = keyval;
8918   entry->modifiers = modifiers;
8919   entry->is_mnemonic = is_mnemonic;
8920
8921   /* GtkAccelGroup stores lowercased accelerators. To deal
8922    * with this, if <Shift> was specified, uppercase.
8923    */
8924   if (modifiers & GDK_SHIFT_MASK)
8925     {
8926       if (keyval == GDK_KEY_Tab)
8927         keyval = GDK_KEY_ISO_Left_Tab;
8928       else
8929         keyval = gdk_keyval_to_upper (keyval);
8930     }
8931   
8932   _gtk_key_hash_add_entry (key_hash, keyval, entry->modifiers, entry);
8933 }
8934
8935 static GtkKeyHash *
8936 gtk_window_get_key_hash (GtkWindow *window)
8937 {
8938   GdkScreen *screen = gtk_window_check_screen (window);
8939   GtkKeyHash *key_hash = g_object_get_qdata (G_OBJECT (window), quark_gtk_window_key_hash);
8940   
8941   if (key_hash)
8942     return key_hash;
8943   
8944   key_hash = _gtk_key_hash_new (gdk_keymap_get_for_display (gdk_screen_get_display (screen)),
8945                                 (GDestroyNotify)window_key_entry_destroy);
8946   _gtk_window_keys_foreach (window, add_to_key_hash, key_hash);
8947   g_object_set_qdata (G_OBJECT (window), quark_gtk_window_key_hash, key_hash);
8948
8949   return key_hash;
8950 }
8951
8952 static void
8953 gtk_window_free_key_hash (GtkWindow *window)
8954 {
8955   GtkKeyHash *key_hash = g_object_get_qdata (G_OBJECT (window), quark_gtk_window_key_hash);
8956   if (key_hash)
8957     {
8958       _gtk_key_hash_free (key_hash);
8959       g_object_set_qdata (G_OBJECT (window), quark_gtk_window_key_hash, NULL);
8960     }
8961 }
8962
8963 /**
8964  * gtk_window_activate_key:
8965  * @window:  a #GtkWindow
8966  * @event:   a #GdkEventKey
8967  *
8968  * Activates mnemonics and accelerators for this #GtkWindow. This is normally
8969  * called by the default ::key_press_event handler for toplevel windows,
8970  * however in some cases it may be useful to call this directly when
8971  * overriding the standard key handling for a toplevel window.
8972  *
8973  * Return value: %TRUE if a mnemonic or accelerator was found and activated.
8974  *
8975  * Since: 2.4
8976  */
8977 gboolean
8978 gtk_window_activate_key (GtkWindow   *window,
8979                          GdkEventKey *event)
8980 {
8981   GtkKeyHash *key_hash;
8982   GtkWindowKeyEntry *found_entry = NULL;
8983   gboolean enable_mnemonics;
8984   gboolean enable_accels;
8985
8986   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
8987   g_return_val_if_fail (event != NULL, FALSE);
8988
8989   key_hash = gtk_window_get_key_hash (window);
8990
8991   if (key_hash)
8992     {
8993       GSList *tmp_list;
8994       GSList *entries = _gtk_key_hash_lookup (key_hash,
8995                                               event->hardware_keycode,
8996                                               event->state,
8997                                               gtk_accelerator_get_default_mod_mask (),
8998                                               event->group);
8999
9000       g_object_get (gtk_widget_get_settings (GTK_WIDGET (window)),
9001                     "gtk-enable-mnemonics", &enable_mnemonics,
9002                     "gtk-enable-accels", &enable_accels,
9003                     NULL);
9004
9005       for (tmp_list = entries; tmp_list; tmp_list = tmp_list->next)
9006         {
9007           GtkWindowKeyEntry *entry = tmp_list->data;
9008           if (entry->is_mnemonic)
9009             {
9010               if (enable_mnemonics)
9011                 {
9012                   found_entry = entry;
9013                   break;
9014                 }
9015             }
9016           else 
9017             {
9018               if (enable_accels && !found_entry)
9019                 {
9020                   found_entry = entry;
9021                 }
9022             }
9023         }
9024
9025       g_slist_free (entries);
9026     }
9027
9028   if (found_entry)
9029     {
9030       if (found_entry->is_mnemonic)
9031         {
9032           if (enable_mnemonics)
9033             return gtk_window_mnemonic_activate (window, found_entry->keyval,
9034                                                  found_entry->modifiers);
9035         }
9036       else
9037         {
9038           if (enable_accels)
9039             return gtk_accel_groups_activate (G_OBJECT (window), found_entry->keyval,
9040                                               found_entry->modifiers);
9041         }
9042     }
9043
9044   return FALSE;
9045 }
9046
9047 static void
9048 window_update_has_focus (GtkWindow *window)
9049 {
9050   GtkWindowPrivate *priv = window->priv;
9051   GtkWidget *widget = GTK_WIDGET (window);
9052   gboolean has_focus = priv->has_toplevel_focus && priv->is_active;
9053
9054   if (has_focus != priv->has_focus)
9055     {
9056       priv->has_focus = has_focus;
9057
9058       if (has_focus)
9059         {
9060           if (priv->focus_widget &&
9061               priv->focus_widget != widget &&
9062               !gtk_widget_has_focus (priv->focus_widget))
9063             do_focus_change (priv->focus_widget, TRUE);
9064         }
9065       else
9066         {
9067           if (priv->focus_widget &&
9068               priv->focus_widget != widget &&
9069               gtk_widget_has_focus (priv->focus_widget))
9070             do_focus_change (priv->focus_widget, FALSE);
9071         }
9072     }
9073 }
9074
9075 /**
9076  * _gtk_window_set_is_active:
9077  * @window: a #GtkWindow
9078  * @is_active: %TRUE if the window is in the currently active toplevel
9079  * 
9080  * Internal function that sets whether the #GtkWindow is part
9081  * of the currently active toplevel window (taking into account inter-process
9082  * embedding.)
9083  **/
9084 void
9085 _gtk_window_set_is_active (GtkWindow *window,
9086                            gboolean   is_active)
9087 {
9088   GtkWindowPrivate *priv;
9089
9090   g_return_if_fail (GTK_IS_WINDOW (window));
9091
9092   priv = window->priv;
9093
9094   is_active = is_active != FALSE;
9095
9096   if (is_active != priv->is_active)
9097     {
9098       priv->is_active = is_active;
9099       window_update_has_focus (window);
9100
9101       g_object_notify (G_OBJECT (window), "is-active");
9102     }
9103 }
9104
9105 /**
9106  * _gtk_window_set_is_toplevel:
9107  * @window: a #GtkWindow
9108  * @is_toplevel: %TRUE if the window is still a real toplevel (nominally a
9109  * child of the root window); %FALSE if it is not (for example, for an
9110  * in-process, parented GtkPlug)
9111  *
9112  * Internal function used by #GtkPlug when it gets parented/unparented by a
9113  * #GtkSocket.  This keeps the @window's #GTK_TOPLEVEL flag in sync with the
9114  * global list of toplevel windows.
9115  */
9116 void
9117 _gtk_window_set_is_toplevel (GtkWindow *window,
9118                              gboolean   is_toplevel)
9119 {
9120   GtkWidget *widget;
9121   GtkWidget *toplevel;
9122
9123   widget = GTK_WIDGET (window);
9124
9125   if (gtk_widget_is_toplevel (widget))
9126     g_assert (g_slist_find (toplevel_list, window) != NULL);
9127   else
9128     g_assert (g_slist_find (toplevel_list, window) == NULL);
9129
9130   if (is_toplevel == gtk_widget_is_toplevel (widget))
9131     return;
9132
9133   if (is_toplevel)
9134     {
9135       /* Pass through regular pathways of an embedded toplevel
9136        * to go through unmapping and hiding the widget before
9137        * becomming a toplevel again.
9138        *
9139        * We remain hidden after becomming toplevel in order to
9140        * avoid problems during an embedded toplevel's dispose cycle
9141        * (When a toplevel window is shown it tries to grab focus again,
9142        * this causes problems while disposing).
9143        */
9144       gtk_widget_hide (widget);
9145
9146       /* Save the toplevel this widget was previously anchored into before
9147        * propagating a hierarchy-changed.
9148        *
9149        * Usually this happens by way of gtk_widget_unparent() and we are
9150        * already unanchored at this point, just adding this clause incase
9151        * things happen differently.
9152        */
9153       toplevel = gtk_widget_get_toplevel (widget);
9154       if (!gtk_widget_is_toplevel (toplevel))
9155         toplevel = NULL;
9156
9157       _gtk_widget_set_is_toplevel (widget, TRUE);
9158
9159       /* When a window becomes toplevel after being embedded and anchored
9160        * into another window we need to unset it's anchored flag so that
9161        * the hierarchy changed signal kicks in properly.
9162        */
9163       _gtk_widget_set_anchored (widget, FALSE);
9164       _gtk_widget_propagate_hierarchy_changed (widget, toplevel);
9165
9166       toplevel_list = g_slist_prepend (toplevel_list, window);
9167     }
9168   else
9169     {
9170       _gtk_widget_set_is_toplevel (widget, FALSE);
9171       toplevel_list = g_slist_remove (toplevel_list, window);
9172
9173       _gtk_widget_propagate_hierarchy_changed (widget, widget);
9174     }
9175 }
9176
9177 /**
9178  * _gtk_window_set_has_toplevel_focus:
9179  * @window: a #GtkWindow
9180  * @has_toplevel_focus: %TRUE if the in
9181  * 
9182  * Internal function that sets whether the keyboard focus for the
9183  * toplevel window (taking into account inter-process embedding.)
9184  **/
9185 void
9186 _gtk_window_set_has_toplevel_focus (GtkWindow *window,
9187                                    gboolean   has_toplevel_focus)
9188 {
9189   GtkWindowPrivate *priv;
9190
9191   g_return_if_fail (GTK_IS_WINDOW (window));
9192
9193   priv = window->priv;
9194
9195   has_toplevel_focus = has_toplevel_focus != FALSE;
9196
9197   if (has_toplevel_focus != priv->has_toplevel_focus)
9198     {
9199       priv->has_toplevel_focus = has_toplevel_focus;
9200       window_update_has_focus (window);
9201
9202       g_object_notify (G_OBJECT (window), "has-toplevel-focus");
9203     }
9204 }
9205
9206 /**
9207  * gtk_window_set_auto_startup_notification:
9208  * @setting: %TRUE to automatically do startup notification
9209  *
9210  * By default, after showing the first #GtkWindow, GTK+ calls 
9211  * gdk_notify_startup_complete().  Call this function to disable 
9212  * the automatic startup notification. You might do this if your 
9213  * first window is a splash screen, and you want to delay notification 
9214  * until after your real main window has been shown, for example.
9215  *
9216  * In that example, you would disable startup notification
9217  * temporarily, show your splash screen, then re-enable it so that
9218  * showing the main window would automatically result in notification.
9219  * 
9220  * Since: 2.2
9221  **/
9222 void
9223 gtk_window_set_auto_startup_notification (gboolean setting)
9224 {
9225   disable_startup_notification = !setting;
9226 }
9227
9228 /**
9229  * gtk_window_get_window_type:
9230  * @window: a #GtkWindow
9231  *
9232  * Gets the type of the window. See #GtkWindowType.
9233  *
9234  * Return value: the type of the window
9235  *
9236  * Since: 2.20
9237  **/
9238 GtkWindowType
9239 gtk_window_get_window_type (GtkWindow *window)
9240 {
9241   g_return_val_if_fail (GTK_IS_WINDOW (window), GTK_WINDOW_TOPLEVEL);
9242
9243   return window->priv->type;
9244 }
9245
9246 /**
9247  * gtk_window_get_mnemonics_visible:
9248  * @window: a #GtkWindow
9249  *
9250  * Gets the value of the #GtkWindow:mnemonics-visible property.
9251  *
9252  * Returns: %TRUE if mnemonics are supposed to be visible
9253  * in this window.
9254  *
9255  * Since: 2.20
9256  */
9257 gboolean
9258 gtk_window_get_mnemonics_visible (GtkWindow *window)
9259 {
9260   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
9261
9262   return window->priv->mnemonics_visible;
9263 }
9264
9265 /**
9266  * gtk_window_set_mnemonics_visible:
9267  * @window: a #GtkWindow
9268  * @setting: the new value
9269  *
9270  * Sets the #GtkWindow:mnemonics-visible property.
9271  *
9272  * Since: 2.20
9273  */
9274 void
9275 gtk_window_set_mnemonics_visible (GtkWindow *window,
9276                                   gboolean   setting)
9277 {
9278   GtkWindowPrivate *priv;
9279
9280   g_return_if_fail (GTK_IS_WINDOW (window));
9281
9282   priv = window->priv;
9283
9284   setting = setting != FALSE;
9285
9286   if (priv->mnemonics_visible != setting)
9287     {
9288       priv->mnemonics_visible = setting;
9289       g_object_notify (G_OBJECT (window), "mnemonics-visible");
9290     }
9291
9292   priv->mnemonics_visible_set = TRUE;
9293 }
9294
9295 void
9296 _gtk_window_get_wmclass (GtkWindow  *window,
9297                          gchar     **wmclass_name,
9298                          gchar     **wmclass_class)
9299 {
9300   GtkWindowPrivate *priv = window->priv;
9301
9302   *wmclass_name = priv->wmclass_name;
9303   *wmclass_class = priv->wmclass_class;
9304 }
9305
9306 /**
9307  * gtk_window_set_has_user_ref_count:
9308  * @window: a #GtkWindow
9309  * @setting: the new value
9310  *
9311  * Tells GTK+ whether to drop its extra reference to the window
9312  * when gtk_window_destroy() is called.
9313  *
9314  * This function is only exported for the benefit of language
9315  * bindings which may need to keep the window alive until their
9316  * wrapper object is garbage collected. There is no justification
9317  * for ever calling this function in an application.
9318  *
9319  * Since: 3.0
9320  */
9321 void
9322 gtk_window_set_has_user_ref_count (GtkWindow *window,
9323                                    gboolean   setting)
9324 {
9325   g_return_if_fail (GTK_IS_WINDOW (window));
9326
9327   window->priv->has_user_ref_count = setting;
9328 }