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