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