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