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