]> Pileus Git - ~andy/gtk/blob - gtk/gtkwindow.c
Add docs.
[~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 <string.h>
28 #include <limits.h>
29 #include "gdk/gdk.h"
30 #include "gdk/gdkkeysyms.h"
31
32 #include "gtkprivate.h"
33 #include "gtkrc.h"
34 #include "gtkwindow.h"
35 #include "gtkwindow-decorate.h"
36 #include "gtkbindings.h"
37 #include "gtkkeyhash.h"
38 #include "gtkmain.h"
39 #include "gtkiconfactory.h"
40 #include "gtkintl.h"
41 #include "gtkmarshalers.h"
42 #include "gtkplug.h"
43
44 enum {
45   SET_FOCUS,
46   FRAME_EVENT,
47   ACTIVATE_FOCUS,
48   ACTIVATE_DEFAULT,
49   MOVE_FOCUS,
50   KEYS_CHANGED,
51   LAST_SIGNAL
52 };
53
54 enum {
55   PROP_0,
56
57   /* Construct */
58   PROP_TYPE,
59
60   /* Normal Props */
61   PROP_TITLE,
62   PROP_ALLOW_SHRINK,
63   PROP_ALLOW_GROW,
64   PROP_RESIZABLE,
65   PROP_MODAL,
66   PROP_WIN_POS,
67   PROP_DEFAULT_WIDTH,
68   PROP_DEFAULT_HEIGHT,
69   PROP_DESTROY_WITH_PARENT,
70   PROP_ICON,
71   PROP_SCREEN,
72   PROP_TYPE_HINT,
73   PROP_SKIP_TASKBAR_HINT,
74   PROP_SKIP_PAGER_HINT,
75   
76   /* Readonly properties */
77   PROP_IS_ACTIVE,
78   PROP_HAS_TOPLEVEL_FOCUS,
79   
80   LAST_ARG
81 };
82
83 typedef struct
84 {
85   GList     *icon_list;
86   GdkPixmap *icon_pixmap;
87   GdkPixmap *icon_mask;
88   guint      realized : 1;
89   guint      using_default_icon : 1;
90   guint      using_parent_icon : 1;
91 } GtkWindowIconInfo;
92
93 typedef struct {
94   GdkGeometry    geometry; /* Last set of geometry hints we set */
95   GdkWindowHints flags;
96   GdkRectangle   configure_request;
97 } GtkWindowLastGeometryInfo;
98
99 struct _GtkWindowGeometryInfo
100 {
101   /* Properties that the app has set on the window
102    */
103   GdkGeometry    geometry;      /* Geometry hints */
104   GdkWindowHints mask;
105   GtkWidget     *widget;        /* subwidget to which hints apply */
106   /* from last gtk_window_resize () - if > 0, indicates that
107    * we should resize to this size.
108    */
109   gint           resize_width;  
110   gint           resize_height;
111
112   /* From last gtk_window_move () prior to mapping -
113    * only used if initial_pos_set
114    */
115   gint           initial_x;
116   gint           initial_y;
117   
118   /* Default size - used only the FIRST time we map a window,
119    * only if > 0.
120    */
121   gint           default_width; 
122   gint           default_height;
123   /* whether to use initial_x, initial_y */
124   guint          initial_pos_set : 1;
125   /* CENTER_ALWAYS or other position constraint changed since
126    * we sent the last configure request.
127    */
128   guint          position_constraints_changed : 1;
129
130   /* if true, default_width, height come from gtk_window_parse_geometry,
131    * and thus should be multiplied by the increments and affect the
132    * geometry widget only
133    */
134   guint          default_is_geometry : 1;
135   
136   GtkWindowLastGeometryInfo last;
137 };
138
139 typedef struct _GtkWindowMnemonic GtkWindowMnemonic;
140
141 struct _GtkWindowMnemonic {
142   GtkWindow *window;
143   guint keyval;
144
145   GSList *targets;
146 };
147
148 typedef struct _GtkWindowPrivate GtkWindowPrivate;
149
150 struct _GtkWindowPrivate
151 {
152   guint fullscreen_initially : 1;
153   guint skips_taskbar : 1;
154   guint skips_pager : 1;
155 };
156
157 static void gtk_window_class_init         (GtkWindowClass    *klass);
158 static void gtk_window_init               (GtkWindow         *window);
159 static void gtk_window_dispose            (GObject           *object);
160 static void gtk_window_destroy            (GtkObject         *object);
161 static void gtk_window_finalize           (GObject           *object);
162 static void gtk_window_private_finalize   (GtkWindowPrivate  *priv);
163 static void gtk_window_show               (GtkWidget         *widget);
164 static void gtk_window_hide               (GtkWidget         *widget);
165 static void gtk_window_map                (GtkWidget         *widget);
166 static void gtk_window_unmap              (GtkWidget         *widget);
167 static void gtk_window_realize            (GtkWidget         *widget);
168 static void gtk_window_unrealize          (GtkWidget         *widget);
169 static void gtk_window_size_request       (GtkWidget         *widget,
170                                            GtkRequisition    *requisition);
171 static void gtk_window_size_allocate      (GtkWidget         *widget,
172                                            GtkAllocation     *allocation);
173 static gint gtk_window_event              (GtkWidget *widget,
174                                            GdkEvent *event);
175 static gboolean gtk_window_frame_event    (GtkWindow *window,
176                                            GdkEvent *event);
177 static gint gtk_window_configure_event    (GtkWidget         *widget,
178                                            GdkEventConfigure *event);
179 static gint gtk_window_key_press_event    (GtkWidget         *widget,
180                                            GdkEventKey       *event);
181 static gint gtk_window_key_release_event  (GtkWidget         *widget,
182                                            GdkEventKey       *event);
183 static gint gtk_window_enter_notify_event (GtkWidget         *widget,
184                                            GdkEventCrossing  *event);
185 static gint gtk_window_leave_notify_event (GtkWidget         *widget,
186                                            GdkEventCrossing  *event);
187 static gint gtk_window_focus_in_event     (GtkWidget         *widget,
188                                            GdkEventFocus     *event);
189 static gint gtk_window_focus_out_event    (GtkWidget         *widget,
190                                            GdkEventFocus     *event);
191 static gint gtk_window_client_event       (GtkWidget         *widget,
192                                            GdkEventClient    *event);
193 static void gtk_window_check_resize       (GtkContainer      *container);
194 static gint gtk_window_focus              (GtkWidget        *widget,
195                                            GtkDirectionType  direction);
196 static void gtk_window_real_set_focus     (GtkWindow         *window,
197                                            GtkWidget         *focus);
198
199 static void gtk_window_real_activate_default (GtkWindow         *window);
200 static void gtk_window_real_activate_focus   (GtkWindow         *window);
201 static void gtk_window_move_focus            (GtkWindow         *window,
202                                               GtkDirectionType   dir);
203 static void gtk_window_keys_changed          (GtkWindow         *window);
204 static void gtk_window_read_rcfiles       (GtkWidget         *widget,
205                                            GdkEventClient    *event);
206 static void gtk_window_paint              (GtkWidget         *widget,
207                                            GdkRectangle      *area);
208 static gint gtk_window_expose             (GtkWidget         *widget,
209                                            GdkEventExpose    *event);
210 static void gtk_window_unset_transient_for         (GtkWindow  *window);
211 static void gtk_window_transient_parent_realized   (GtkWidget  *parent,
212                                                     GtkWidget  *window);
213 static void gtk_window_transient_parent_unrealized (GtkWidget  *parent,
214                                                     GtkWidget  *window);
215
216 static GdkScreen *gtk_window_check_screen (GtkWindow *window);
217
218 static GtkWindowGeometryInfo* gtk_window_get_geometry_info         (GtkWindow    *window,
219                                                                     gboolean      create);
220
221 static void     gtk_window_move_resize               (GtkWindow    *window);
222 static gboolean gtk_window_compare_hints             (GdkGeometry  *geometry_a,
223                                                       guint         flags_a,
224                                                       GdkGeometry  *geometry_b,
225                                                       guint         flags_b);
226 static void     gtk_window_constrain_size            (GtkWindow    *window,
227                                                       GdkGeometry  *geometry,
228                                                       guint         flags,
229                                                       gint          width,
230                                                       gint          height,
231                                                       gint         *new_width,
232                                                       gint         *new_height);
233 static void     gtk_window_constrain_position        (GtkWindow    *window,
234                                                       gint          new_width,
235                                                       gint          new_height,
236                                                       gint         *x,
237                                                       gint         *y);
238 static void     gtk_window_compute_hints             (GtkWindow    *window,
239                                                       GdkGeometry  *new_geometry,
240                                                       guint        *new_flags);
241 static void     gtk_window_compute_configure_request (GtkWindow    *window,
242                                                       GdkRectangle *request,
243                                                       GdkGeometry  *geometry,
244                                                       guint        *flags);
245
246 static void     gtk_window_set_default_size_internal (GtkWindow    *window,
247                                                       gboolean      change_width,
248                                                       gint          width,
249                                                       gboolean      change_height,
250                                                       gint          height,
251                                                       gboolean      is_geometry);
252
253 static void     gtk_window_realize_icon               (GtkWindow    *window);
254 static void     gtk_window_unrealize_icon             (GtkWindow    *window);
255
256 static void        gtk_window_notify_keys_changed (GtkWindow   *window);
257 static GtkKeyHash *gtk_window_get_key_hash        (GtkWindow   *window);
258 static void        gtk_window_free_key_hash       (GtkWindow   *window);
259
260 static GSList      *toplevel_list = NULL;
261 static GHashTable  *mnemonic_hash_table = NULL;
262 static GtkBinClass *parent_class = NULL;
263 static guint        window_signals[LAST_SIGNAL] = { 0 };
264 static GList       *default_icon_list = NULL;
265 static guint        default_icon_serial = 0;
266 static gboolean     disable_startup_notification = FALSE;
267 static gboolean     sent_startup_notification = FALSE;
268
269 static void gtk_window_set_property (GObject         *object,
270                                      guint            prop_id,
271                                      const GValue    *value,
272                                      GParamSpec      *pspec);
273 static void gtk_window_get_property (GObject         *object,
274                                      guint            prop_id,
275                                      GValue          *value,
276                                      GParamSpec      *pspec);
277
278
279 static guint
280 mnemonic_hash (gconstpointer key)
281 {
282   const GtkWindowMnemonic *k;
283   guint h;
284   
285   k = (GtkWindowMnemonic *)key;
286   
287   h = (gulong) k->window;
288   h ^= k->keyval << 16;
289   h ^= k->keyval >> 16;
290
291   return h;
292 }
293
294 static gboolean
295 mnemonic_equal (gconstpointer a, gconstpointer b)
296 {
297   const GtkWindowMnemonic *ka;
298   const GtkWindowMnemonic *kb;
299   
300   ka = (GtkWindowMnemonic *)a;
301   kb = (GtkWindowMnemonic *)b;
302
303   return
304     (ka->window == kb->window) &&
305     (ka->keyval == kb->keyval);
306 }
307
308 GtkWindowPrivate*
309 gtk_window_get_private (GtkWindow *window)
310 {
311   GtkWindowPrivate *private;
312   static GQuark private_quark = 0;
313
314   if (!private_quark)
315     private_quark = g_quark_from_static_string ("gtk-window-private");
316
317   private = g_object_get_qdata (G_OBJECT (window), private_quark);
318
319   if (!private)
320     {
321       private = g_new0 (GtkWindowPrivate, 1);
322
323       private->fullscreen_initially = FALSE;
324       private->skips_pager = FALSE;
325       private->skips_taskbar = FALSE;
326       
327       g_object_set_qdata_full (G_OBJECT (window), private_quark,
328                                private,
329                                (GDestroyNotify) gtk_window_private_finalize);
330     }
331
332   return private;
333 }
334
335 GType
336 gtk_window_get_type (void)
337 {
338   static GType window_type = 0;
339
340   if (!window_type)
341     {
342       static const GTypeInfo window_info =
343       {
344         sizeof (GtkWindowClass),
345         NULL,           /* base_init */
346         NULL,           /* base_finalize */
347         (GClassInitFunc) gtk_window_class_init,
348         NULL,           /* class_finalize */
349         NULL,           /* class_data */
350         sizeof (GtkWindow),
351         0,              /* n_preallocs */
352         (GInstanceInitFunc) gtk_window_init,
353       };
354
355       window_type = g_type_register_static (GTK_TYPE_BIN, "GtkWindow",
356                                             &window_info, 0);
357     }
358
359   return window_type;
360 }
361
362 static void
363 add_tab_bindings (GtkBindingSet    *binding_set,
364                   GdkModifierType   modifiers,
365                   GtkDirectionType  direction)
366 {
367   gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
368                                 "move_focus", 1,
369                                 GTK_TYPE_DIRECTION_TYPE, direction);
370   gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
371                                 "move_focus", 1,
372                                 GTK_TYPE_DIRECTION_TYPE, direction);
373 }
374
375 static void
376 add_arrow_bindings (GtkBindingSet    *binding_set,
377                     guint             keysym,
378                     GtkDirectionType  direction)
379 {
380   guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
381   
382   gtk_binding_entry_add_signal (binding_set, keysym, 0,
383                                 "move_focus", 1,
384                                 GTK_TYPE_DIRECTION_TYPE, direction);
385   gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
386                                 "move_focus", 1,
387                                 GTK_TYPE_DIRECTION_TYPE, direction);
388   gtk_binding_entry_add_signal (binding_set, keypad_keysym, 0,
389                                 "move_focus", 1,
390                                 GTK_TYPE_DIRECTION_TYPE, direction);
391   gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
392                                 "move_focus", 1,
393                                 GTK_TYPE_DIRECTION_TYPE, direction);
394 }
395
396
397 static void
398 gtk_window_class_init (GtkWindowClass *klass)
399 {
400   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
401   GtkObjectClass *object_class;
402   GtkWidgetClass *widget_class;
403   GtkContainerClass *container_class;
404   GtkBindingSet *binding_set;
405   
406   object_class = (GtkObjectClass*) klass;
407   widget_class = (GtkWidgetClass*) klass;
408   container_class = (GtkContainerClass*) klass;
409   
410   parent_class = g_type_class_peek_parent (klass);
411
412   mnemonic_hash_table = g_hash_table_new (mnemonic_hash, mnemonic_equal);
413
414   gobject_class->dispose = gtk_window_dispose;
415   gobject_class->finalize = gtk_window_finalize;
416
417   gobject_class->set_property = gtk_window_set_property;
418   gobject_class->get_property = gtk_window_get_property;
419   
420   object_class->destroy = gtk_window_destroy;
421
422   widget_class->show = gtk_window_show;
423   widget_class->hide = gtk_window_hide;
424   widget_class->map = gtk_window_map;
425   widget_class->unmap = gtk_window_unmap;
426   widget_class->realize = gtk_window_realize;
427   widget_class->unrealize = gtk_window_unrealize;
428   widget_class->size_request = gtk_window_size_request;
429   widget_class->size_allocate = gtk_window_size_allocate;
430   widget_class->configure_event = gtk_window_configure_event;
431   widget_class->key_press_event = gtk_window_key_press_event;
432   widget_class->key_release_event = gtk_window_key_release_event;
433   widget_class->enter_notify_event = gtk_window_enter_notify_event;
434   widget_class->leave_notify_event = gtk_window_leave_notify_event;
435   widget_class->focus_in_event = gtk_window_focus_in_event;
436   widget_class->focus_out_event = gtk_window_focus_out_event;
437   widget_class->client_event = gtk_window_client_event;
438   widget_class->focus = gtk_window_focus;
439   
440   widget_class->expose_event = gtk_window_expose;
441    
442   container_class->check_resize = gtk_window_check_resize;
443
444   klass->set_focus = gtk_window_real_set_focus;
445   klass->frame_event = gtk_window_frame_event;
446
447   klass->activate_default = gtk_window_real_activate_default;
448   klass->activate_focus = gtk_window_real_activate_focus;
449   klass->move_focus = gtk_window_move_focus;
450   klass->keys_changed = gtk_window_keys_changed;
451   
452   /* Construct */
453   g_object_class_install_property (gobject_class,
454                                    PROP_TYPE,
455                                    g_param_spec_enum ("type",
456                                                       _("Window Type"),
457                                                       _("The type of the window"),
458                                                       GTK_TYPE_WINDOW_TYPE,
459                                                       GTK_WINDOW_TOPLEVEL,
460                                                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
461
462   /* Regular Props */
463   g_object_class_install_property (gobject_class,
464                                    PROP_TITLE,
465                                    g_param_spec_string ("title",
466                                                         _("Window Title"),
467                                                         _("The title of the window"),
468                                                         NULL,
469                                                         G_PARAM_READWRITE));
470
471   g_object_class_install_property (gobject_class,
472                                    PROP_ALLOW_SHRINK,
473                                    g_param_spec_boolean ("allow_shrink",
474                                                          _("Allow Shrink"),
475                                                          /* xgettext:no-c-format */
476                                                          _("If TRUE, the window has no mimimum size. Setting this to TRUE is 99% of the time a bad idea"),
477                                                          FALSE,
478                                                          G_PARAM_READWRITE));
479
480   g_object_class_install_property (gobject_class,
481                                    PROP_ALLOW_GROW,
482                                    g_param_spec_boolean ("allow_grow",
483                                                          _("Allow Grow"),
484                                                          _("If TRUE, users can expand the window beyond its minimum size"),
485                                                          TRUE,
486                                                          G_PARAM_READWRITE));
487
488   g_object_class_install_property (gobject_class,
489                                    PROP_RESIZABLE,
490                                    g_param_spec_boolean ("resizable",
491                                                          _("Resizable"),
492                                                          _("If TRUE, users can resize the window"),
493                                                          TRUE,
494                                                          G_PARAM_READWRITE));
495   
496   g_object_class_install_property (gobject_class,
497                                    PROP_MODAL,
498                                    g_param_spec_boolean ("modal",
499                                                          _("Modal"),
500                                                          _("If TRUE, the window is modal (other windows are not usable while this one is up)"),
501                                                          FALSE,
502                                                          G_PARAM_READWRITE));
503
504   g_object_class_install_property (gobject_class,
505                                    PROP_WIN_POS,
506                                    g_param_spec_enum ("window_position",
507                                                       _("Window Position"),
508                                                       _("The initial position of the window"),
509                                                       GTK_TYPE_WINDOW_POSITION,
510                                                       GTK_WIN_POS_NONE,
511                                                       G_PARAM_READWRITE));
512  
513   g_object_class_install_property (gobject_class,
514                                    PROP_DEFAULT_WIDTH,
515                                    g_param_spec_int ("default_width",
516                                                      _("Default Width"),
517                                                      _("The default width of the window, used when initially showing the window"),
518                                                      -1,
519                                                      G_MAXINT,
520                                                      -1,
521                                                      G_PARAM_READWRITE));
522   
523   g_object_class_install_property (gobject_class,
524                                    PROP_DEFAULT_HEIGHT,
525                                    g_param_spec_int ("default_height",
526                                                      _("Default Height"),
527                                                      _("The default height of the window, used when initially showing the window"),
528                                                      -1,
529                                                      G_MAXINT,
530                                                      -1,
531                                                      G_PARAM_READWRITE));
532   
533   g_object_class_install_property (gobject_class,
534                                    PROP_DESTROY_WITH_PARENT,
535                                    g_param_spec_boolean ("destroy_with_parent",
536                                                          _("Destroy with Parent"),
537                                                          _("If this window should be destroyed when the parent is destroyed"),
538                                                          FALSE,
539                                                          G_PARAM_READWRITE));
540
541   g_object_class_install_property (gobject_class,
542                                    PROP_ICON,
543                                    g_param_spec_object ("icon",
544                                                         _("Icon"),
545                                                         _("Icon for this window"),
546                                                         GDK_TYPE_PIXBUF,
547                                                         G_PARAM_READWRITE));
548   
549   g_object_class_install_property (gobject_class,
550                                    PROP_SCREEN,
551                                    g_param_spec_object ("screen",
552                                                         _("Screen"),
553                                                         _("The screen where this window will be displayed"),
554                                                         GDK_TYPE_SCREEN,
555                                                         G_PARAM_READWRITE));
556
557   g_object_class_install_property (gobject_class,
558                                    PROP_IS_ACTIVE,
559                                    g_param_spec_boolean ("is_active",
560                                                          _("Is Active"),
561                                                          _("Whether the toplevel is the current active window"),
562                                                          FALSE,
563                                                          G_PARAM_READABLE));
564   
565   g_object_class_install_property (gobject_class,
566                                    PROP_HAS_TOPLEVEL_FOCUS,
567                                    g_param_spec_boolean ("has_toplevel_focus",
568                                                          _("Focus in Toplevel"),
569                                                          _("Whether the input focus is within this GtkWindow"),
570                                                          FALSE,
571                                                          G_PARAM_READABLE));
572
573   g_object_class_install_property (gobject_class,
574                                    PROP_TYPE_HINT,
575                                    g_param_spec_enum ("type_hint",
576                                                       _("Type hint"),
577                                                       _("Hint to help the desktop environment understand what kind of window this is and how to treat it."),
578                                                       GDK_TYPE_WINDOW_TYPE_HINT,
579                                                       GDK_WINDOW_TYPE_HINT_NORMAL,
580                                                       G_PARAM_READWRITE));
581
582   g_object_class_install_property (gobject_class,
583                                    PROP_SKIP_TASKBAR_HINT,
584                                    g_param_spec_boolean ("skip_taskbar_hint",
585                                                          _("Skip taskbar"),
586                                                          _("TRUE if the window should not be in the task bar."),
587                                                          FALSE,
588                                                          G_PARAM_READWRITE));
589
590   g_object_class_install_property (gobject_class,
591                                    PROP_SKIP_PAGER_HINT,
592                                    g_param_spec_boolean ("skip_pager_hint",
593                                                          _("Skip pager"),
594                                                          _("TRUE if the window should not be in the pager."),
595                                                          FALSE,
596                                                          G_PARAM_READWRITE));  
597
598   window_signals[SET_FOCUS] =
599     g_signal_new ("set_focus",
600                   G_TYPE_FROM_CLASS (gobject_class),
601                   G_SIGNAL_RUN_LAST,
602                   G_STRUCT_OFFSET (GtkWindowClass, set_focus),
603                   NULL, NULL,
604                   _gtk_marshal_VOID__OBJECT,
605                   G_TYPE_NONE, 1,
606                   GTK_TYPE_WIDGET);
607   
608   window_signals[FRAME_EVENT] =
609     g_signal_new ("frame_event",
610                   G_TYPE_FROM_CLASS (gobject_class),
611                   G_SIGNAL_RUN_LAST,
612                   G_STRUCT_OFFSET(GtkWindowClass, frame_event),
613                   _gtk_boolean_handled_accumulator, NULL,
614                   _gtk_marshal_BOOLEAN__BOXED,
615                   G_TYPE_BOOLEAN, 1,
616                   GDK_TYPE_EVENT);
617
618   window_signals[ACTIVATE_FOCUS] =
619     g_signal_new ("activate_focus",
620                   G_TYPE_FROM_CLASS (gobject_class),
621                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
622                   G_STRUCT_OFFSET (GtkWindowClass, activate_focus),
623                   NULL, NULL,
624                   _gtk_marshal_VOID__VOID,
625                   G_TYPE_NONE,
626                   0);
627
628   window_signals[ACTIVATE_DEFAULT] =
629     g_signal_new ("activate_default",
630                   G_TYPE_FROM_CLASS (gobject_class),
631                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
632                   G_STRUCT_OFFSET (GtkWindowClass, activate_default),
633                   NULL, NULL,
634                   _gtk_marshal_VOID__VOID,
635                   G_TYPE_NONE,
636                   0);
637
638   window_signals[MOVE_FOCUS] =
639     g_signal_new ("move_focus",
640                   G_TYPE_FROM_CLASS (gobject_class),
641                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
642                   G_STRUCT_OFFSET (GtkWindowClass, move_focus),
643                   NULL, NULL,
644                   _gtk_marshal_VOID__ENUM,
645                   G_TYPE_NONE,
646                   1,
647                   GTK_TYPE_DIRECTION_TYPE);
648
649   window_signals[KEYS_CHANGED] =
650     g_signal_new ("keys_changed",
651                   G_TYPE_FROM_CLASS (gobject_class),
652                   G_SIGNAL_RUN_FIRST,
653                   G_STRUCT_OFFSET (GtkWindowClass, keys_changed),
654                   NULL, NULL,
655                   _gtk_marshal_VOID__VOID,
656                   G_TYPE_NONE,
657                   0);
658
659   /*
660    * Key bindings
661    */
662
663   binding_set = gtk_binding_set_by_class (klass);
664
665   gtk_binding_entry_add_signal (binding_set, GDK_space, 0,
666                                 "activate_focus", 0);
667   gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, 0,
668                                 "activate_focus", 0);
669   
670   gtk_binding_entry_add_signal (binding_set, GDK_Return, 0,
671                                 "activate_default", 0);
672
673   gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0,
674                                 "activate_default", 0);
675
676   add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
677   add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
678   add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
679   add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
680
681   add_tab_bindings (binding_set, 0, GTK_DIR_TAB_FORWARD);
682   add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
683   add_tab_bindings (binding_set, GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
684   add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
685 }
686
687 static void
688 gtk_window_init (GtkWindow *window)
689 {
690   GdkColormap *colormap;
691   
692   GTK_WIDGET_UNSET_FLAGS (window, GTK_NO_WINDOW);
693   GTK_WIDGET_SET_FLAGS (window, GTK_TOPLEVEL);
694
695   GTK_PRIVATE_SET_FLAG (window, GTK_ANCHORED);
696
697   gtk_container_set_resize_mode (GTK_CONTAINER (window), GTK_RESIZE_QUEUE);
698
699   window->title = NULL;
700   window->wmclass_name = g_strdup (g_get_prgname ());
701   window->wmclass_class = g_strdup (gdk_get_program_class ());
702   window->wm_role = NULL;
703   window->geometry_info = NULL;
704   window->type = GTK_WINDOW_TOPLEVEL;
705   window->focus_widget = NULL;
706   window->default_widget = NULL;
707   window->configure_request_count = 0;
708   window->allow_shrink = FALSE;
709   window->allow_grow = TRUE;
710   window->configure_notify_received = FALSE;
711   window->position = GTK_WIN_POS_NONE;
712   window->need_default_size = TRUE;
713   window->need_default_position = TRUE;
714   window->modal = FALSE;
715   window->frame = NULL;
716   window->has_frame = FALSE;
717   window->frame_left = 0;
718   window->frame_right = 0;
719   window->frame_top = 0;
720   window->frame_bottom = 0;
721   window->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
722   window->gravity = GDK_GRAVITY_NORTH_WEST;
723   window->decorated = TRUE;
724   window->mnemonic_modifier = GDK_MOD1_MASK;
725   window->screen = gdk_screen_get_default ();
726   
727   colormap = _gtk_widget_peek_colormap ();
728   if (colormap)
729     gtk_widget_set_colormap (GTK_WIDGET (window), colormap);
730   
731   g_object_ref (window);
732   gtk_object_sink (GTK_OBJECT (window));
733   window->has_user_ref_count = TRUE;
734   toplevel_list = g_slist_prepend (toplevel_list, window);
735
736   gtk_decorated_window_init (window);
737
738   g_signal_connect (window,
739                     "event",
740                     G_CALLBACK (gtk_window_event),
741                     NULL);
742 }
743
744 static void
745 gtk_window_set_property (GObject      *object,
746                          guint         prop_id,
747                          const GValue *value,
748                          GParamSpec   *pspec)
749 {
750   GtkWindow  *window;
751   
752   window = GTK_WINDOW (object);
753
754   switch (prop_id)
755     {
756     case PROP_TYPE:
757       window->type = g_value_get_enum (value);
758       break;
759     case PROP_TITLE:
760       gtk_window_set_title (window, g_value_get_string (value));
761       break;
762     case PROP_ALLOW_SHRINK:
763       window->allow_shrink = g_value_get_boolean (value);
764       gtk_widget_queue_resize (GTK_WIDGET (window));
765       break;
766     case PROP_ALLOW_GROW:
767       window->allow_grow = g_value_get_boolean (value);
768       gtk_widget_queue_resize (GTK_WIDGET (window));
769       g_object_notify (G_OBJECT (window), "resizable");
770       break;
771     case PROP_RESIZABLE:
772       window->allow_grow = g_value_get_boolean (value);
773       gtk_widget_queue_resize (GTK_WIDGET (window));
774       g_object_notify (G_OBJECT (window), "allow_grow");
775       break;
776     case PROP_MODAL:
777       gtk_window_set_modal (window, g_value_get_boolean (value));
778       break;
779     case PROP_WIN_POS:
780       gtk_window_set_position (window, g_value_get_enum (value));
781       break;
782     case PROP_DEFAULT_WIDTH:
783       gtk_window_set_default_size_internal (window,
784                                             TRUE, g_value_get_int (value),
785                                             FALSE, -1, FALSE);
786       break;
787     case PROP_DEFAULT_HEIGHT:
788       gtk_window_set_default_size_internal (window,
789                                             FALSE, -1,
790                                             TRUE, g_value_get_int (value), FALSE);
791       break;
792     case PROP_DESTROY_WITH_PARENT:
793       gtk_window_set_destroy_with_parent (window, g_value_get_boolean (value));
794       break;
795     case PROP_ICON:
796       gtk_window_set_icon (window,
797                            g_value_get_object (value));
798       break;
799     case PROP_SCREEN:
800       gtk_window_set_screen (window, g_value_get_object (value));
801       break;
802     case PROP_TYPE_HINT:
803       gtk_window_set_type_hint (window,
804                                 g_value_get_enum (value));
805       break;
806     case PROP_SKIP_TASKBAR_HINT:
807       gtk_window_set_skip_taskbar_hint (window,
808                                         g_value_get_boolean (value));
809       break;
810     case PROP_SKIP_PAGER_HINT:
811       gtk_window_set_skip_pager_hint (window,
812                                       g_value_get_boolean (value));
813       break;
814       
815     default:
816       break;
817     }
818 }
819
820 static void
821 gtk_window_get_property (GObject      *object,
822                          guint         prop_id,
823                          GValue       *value,
824                          GParamSpec   *pspec)
825 {
826   GtkWindow  *window;
827
828   window = GTK_WINDOW (object);
829
830   switch (prop_id)
831     {
832       GtkWindowGeometryInfo *info;
833     case PROP_TYPE:
834       g_value_set_enum (value, window->type);
835       break;
836     case PROP_TITLE:
837       g_value_set_string (value, window->title);
838       break;
839     case PROP_ALLOW_SHRINK:
840       g_value_set_boolean (value, window->allow_shrink);
841       break;
842     case PROP_ALLOW_GROW:
843       g_value_set_boolean (value, window->allow_grow);
844       break;
845     case PROP_RESIZABLE:
846       g_value_set_boolean (value, window->allow_grow);
847       break;
848     case PROP_MODAL:
849       g_value_set_boolean (value, window->modal);
850       break;
851     case PROP_WIN_POS:
852       g_value_set_enum (value, window->position);
853       break;
854     case PROP_DEFAULT_WIDTH:
855       info = gtk_window_get_geometry_info (window, FALSE);
856       if (!info)
857         g_value_set_int (value, -1);
858       else
859         g_value_set_int (value, info->default_width);
860       break;
861     case PROP_DEFAULT_HEIGHT:
862       info = gtk_window_get_geometry_info (window, FALSE);
863       if (!info)
864         g_value_set_int (value, -1);
865       else
866         g_value_set_int (value, info->default_height);
867       break;
868     case PROP_DESTROY_WITH_PARENT:
869       g_value_set_boolean (value, window->destroy_with_parent);
870       break;
871     case PROP_ICON:
872       g_value_set_object (value, gtk_window_get_icon (window));
873       break;
874     case PROP_SCREEN:
875       g_value_set_object (value, window->screen);
876       break;
877     case PROP_IS_ACTIVE:
878       g_value_set_boolean (value, window->is_active);
879       break;
880     case PROP_HAS_TOPLEVEL_FOCUS:
881       g_value_set_boolean (value, window->has_toplevel_focus);
882       break;
883     case PROP_TYPE_HINT:
884       g_value_set_enum (value,
885                         window->type_hint);
886       break;
887     case PROP_SKIP_TASKBAR_HINT:
888       g_value_set_boolean (value,
889                            gtk_window_get_skip_taskbar_hint (window));
890       break;
891     case PROP_SKIP_PAGER_HINT:
892       g_value_set_boolean (value,
893                            gtk_window_get_skip_pager_hint (window));
894       break;
895     default:
896       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
897       break;
898     }
899 }
900
901 /**
902  * gtk_window_new:
903  * @type: type of window
904  * 
905  * Creates a new #GtkWindow, which is a toplevel window that can
906  * contain other widgets. Nearly always, the type of the window should
907  * be #GTK_WINDOW_TOPLEVEL. If you're implementing something like a
908  * popup menu from scratch (which is a bad idea, just use #GtkMenu),
909  * you might use #GTK_WINDOW_POPUP. #GTK_WINDOW_POPUP is not for
910  * dialogs, though in some other toolkits dialogs are called "popups".
911  * In GTK+, #GTK_WINDOW_POPUP means a pop-up menu or pop-up tooltip.
912  * On X11, popup windows are not controlled by the <link
913  * linkend="gtk-X11-arch">window manager</link>.
914  *
915  * If you simply want an undecorated window (no window borders), use
916  * gtk_window_set_decorated(), don't use #GTK_WINDOW_POPUP.
917  * 
918  * Return value: a new #GtkWindow.
919  **/
920 GtkWidget*
921 gtk_window_new (GtkWindowType type)
922 {
923   GtkWindow *window;
924
925   g_return_val_if_fail (type >= GTK_WINDOW_TOPLEVEL && type <= GTK_WINDOW_POPUP, NULL);
926
927   window = g_object_new (GTK_TYPE_WINDOW, NULL);
928
929   window->type = type;
930
931   return GTK_WIDGET (window);
932 }
933
934 /**
935  * gtk_window_set_title:
936  * @window: a #GtkWindow
937  * @title: title of the window
938  * 
939  * Sets the title of the #GtkWindow. The title of a window will be
940  * displayed in its title bar; on the X Window System, the title bar
941  * is rendered by the <link linkend="gtk-X11-arch">window
942  * manager</link>, so exactly how the title appears to users may vary
943  * according to a user's exact configuration. The title should help a
944  * user distinguish this window from other windows they may have
945  * open. A good title might include the application name and current
946  * document filename, for example.
947  * 
948  **/
949 void
950 gtk_window_set_title (GtkWindow   *window,
951                       const gchar *title)
952 {
953   g_return_if_fail (GTK_IS_WINDOW (window));
954
955   if (window->title)
956     g_free (window->title);
957   window->title = g_strdup (title);
958
959   if (GTK_WIDGET_REALIZED (window))
960     {
961       gdk_window_set_title (GTK_WIDGET (window)->window, window->title);
962
963       gtk_decorated_window_set_title (window, title);
964     }
965
966   g_object_notify (G_OBJECT (window), "title");
967 }
968
969 /**
970  * gtk_window_get_title:
971  * @window: a #GtkWindow
972  *
973  * Retrieves the title of the window. See gtk_window_set_title().
974  *
975  * Return value: the title of the window, or %NULL if none has
976  *    been set explicitely. The returned string is owned by the widget
977  *    and must not be modified or freed.
978  **/
979 G_CONST_RETURN gchar *
980 gtk_window_get_title (GtkWindow *window)
981 {
982   g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
983
984   return window->title;
985 }
986
987 /**
988  * gtk_window_set_wmclass:
989  * @window: a #GtkWindow
990  * @wmclass_name: window name hint
991  * @wmclass_class: window class hint
992  *
993  * Don't use this function. It sets the X Window System "class" and
994  * "name" hints for a window.  According to the ICCCM, you should
995  * always set these to the same value for all windows in an
996  * application, and GTK+ sets them to that value by default, so calling
997  * this function is sort of pointless. However, you may want to call
998  * gtk_window_set_role() on each window in your application, for the
999  * benefit of the session manager. Setting the role allows the window
1000  * manager to restore window positions when loading a saved session.
1001  * 
1002  **/
1003 void
1004 gtk_window_set_wmclass (GtkWindow *window,
1005                         const gchar *wmclass_name,
1006                         const gchar *wmclass_class)
1007 {
1008   g_return_if_fail (GTK_IS_WINDOW (window));
1009
1010   g_free (window->wmclass_name);
1011   window->wmclass_name = g_strdup (wmclass_name);
1012
1013   g_free (window->wmclass_class);
1014   window->wmclass_class = g_strdup (wmclass_class);
1015
1016   if (GTK_WIDGET_REALIZED (window))
1017     g_warning ("gtk_window_set_wmclass: shouldn't set wmclass after window is realized!\n");
1018 }
1019
1020 /**
1021  * gtk_window_set_role:
1022  * @window: a #GtkWindow
1023  * @role: unique identifier for the window to be used when restoring a session
1024  *
1025  * This function is only useful on X11, not with other GTK+ targets.
1026  * 
1027  * In combination with the window title, the window role allows a
1028  * <link linkend="gtk-X11-arch">window manager</link> to identify "the
1029  * same" window when an application is restarted. So for example you
1030  * might set the "toolbox" role on your app's toolbox window, so that
1031  * when the user restarts their session, the window manager can put
1032  * the toolbox back in the same place.
1033  *
1034  * If a window already has a unique title, you don't need to set the
1035  * role, since the WM can use the title to identify the window when
1036  * restoring the session.
1037  * 
1038  **/
1039 void
1040 gtk_window_set_role (GtkWindow   *window,
1041                      const gchar *role)
1042 {
1043   g_return_if_fail (GTK_IS_WINDOW (window));
1044
1045   if (role == window->wm_role)
1046     return;
1047   
1048   g_free (window->wm_role);
1049   window->wm_role = g_strdup (role);
1050   
1051   if (GTK_WIDGET_REALIZED (window))
1052     g_warning ("gtk_window_set_role(): shouldn't set role after window is realized!\n");
1053 }
1054
1055 /**
1056  * gtk_window_get_role:
1057  * @window: a #GtkWindow
1058  *
1059  * Returns the role of the window. See gtk_window_set_role() for
1060  * further explanation.
1061  *
1062  * Return value: the role of the window if set, or %NULL. The
1063  *   returned is owned by the widget and must not be modified
1064  *   or freed.
1065  **/
1066 G_CONST_RETURN gchar *
1067 gtk_window_get_role (GtkWindow *window)
1068 {
1069   g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
1070
1071   return window->wm_role;
1072 }
1073
1074 /**
1075  * gtk_window_set_focus:
1076  * @window: a #GtkWindow
1077  * @focus: widget to be the new focus widget, or %NULL to unset
1078  *   any focus widget for the toplevel window.
1079  *
1080  * If @focus is not the current focus widget, and is focusable, sets
1081  * it as the focus widget for the window. If @focus is %NULL, unsets
1082  * the focus widget for this window. To set the focus to a particular
1083  * widget in the toplevel, it is usually more convenient to use
1084  * gtk_widget_grab_focus() instead of this function.
1085  **/
1086 void
1087 gtk_window_set_focus (GtkWindow *window,
1088                       GtkWidget *focus)
1089 {
1090   g_return_if_fail (GTK_IS_WINDOW (window));
1091   if (focus)
1092     {
1093       g_return_if_fail (GTK_IS_WIDGET (focus));
1094       g_return_if_fail (GTK_WIDGET_CAN_FOCUS (focus));
1095     }
1096
1097   if (focus)
1098     gtk_widget_grab_focus (focus);
1099   else
1100     {
1101       /* Clear the existing focus chain, so that when we focus into
1102        * the window again, we start at the beginnning.
1103        */
1104       GtkWidget *widget = window->focus_widget;
1105       if (widget)
1106         {
1107           while (widget->parent)
1108             {
1109               widget = widget->parent;
1110               gtk_container_set_focus_child (GTK_CONTAINER (widget), NULL);
1111             }
1112         }
1113       
1114       _gtk_window_internal_set_focus (window, NULL);
1115     }
1116 }
1117
1118 void
1119 _gtk_window_internal_set_focus (GtkWindow *window,
1120                                 GtkWidget *focus)
1121 {
1122   g_return_if_fail (GTK_IS_WINDOW (window));
1123
1124   if ((window->focus_widget != focus) ||
1125       (focus && !GTK_WIDGET_HAS_FOCUS (focus)))
1126     g_signal_emit (window, window_signals[SET_FOCUS], 0, focus);
1127 }
1128
1129 /**
1130  * gtk_window_set_default:
1131  * @window: a #GtkWindow
1132  * @default_widget: widget to be the default, or %NULL to unset the
1133  *                  default widget for the toplevel.
1134  *
1135  * The default widget is the widget that's activated when the user
1136  * presses Enter in a dialog (for example). This function sets or
1137  * unsets the default widget for a #GtkWindow about. When setting
1138  * (rather than unsetting) the default widget it's generally easier to
1139  * call gtk_widget_grab_focus() on the widget. Before making a widget
1140  * the default widget, you must set the #GTK_CAN_DEFAULT flag on the
1141  * widget you'd like to make the default using GTK_WIDGET_SET_FLAGS().
1142  **/
1143 void
1144 gtk_window_set_default (GtkWindow *window,
1145                         GtkWidget *default_widget)
1146 {
1147   g_return_if_fail (GTK_IS_WINDOW (window));
1148
1149   if (default_widget)
1150     g_return_if_fail (GTK_WIDGET_CAN_DEFAULT (default_widget));
1151   
1152   if (window->default_widget != default_widget)
1153     {
1154       GtkWidget *old_default_widget = NULL;
1155       
1156       if (default_widget)
1157         g_object_ref (default_widget);
1158       
1159       if (window->default_widget)
1160         {
1161           old_default_widget = window->default_widget;
1162           
1163           if (window->focus_widget != window->default_widget ||
1164               !GTK_WIDGET_RECEIVES_DEFAULT (window->default_widget))
1165             GTK_WIDGET_UNSET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
1166           gtk_widget_queue_draw (window->default_widget);
1167         }
1168
1169       window->default_widget = default_widget;
1170
1171       if (window->default_widget)
1172         {
1173           if (window->focus_widget == NULL ||
1174               !GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget))
1175             GTK_WIDGET_SET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
1176           gtk_widget_queue_draw (window->default_widget);
1177         }
1178
1179       if (old_default_widget)
1180         g_object_notify (G_OBJECT (old_default_widget), "has_default");
1181       
1182       if (default_widget)
1183         {
1184           g_object_notify (G_OBJECT (default_widget), "has_default");
1185           g_object_unref (default_widget);
1186         }
1187     }
1188 }
1189
1190 void
1191 gtk_window_set_policy (GtkWindow *window,
1192                        gboolean   allow_shrink,
1193                        gboolean   allow_grow,
1194                        gboolean   auto_shrink)
1195 {
1196   g_return_if_fail (GTK_IS_WINDOW (window));
1197
1198   window->allow_shrink = (allow_shrink != FALSE);
1199   window->allow_grow = (allow_grow != FALSE);
1200
1201   g_object_freeze_notify (G_OBJECT (window));
1202   g_object_notify (G_OBJECT (window), "allow_shrink");
1203   g_object_notify (G_OBJECT (window), "allow_grow");
1204   g_object_notify (G_OBJECT (window), "resizable");
1205   g_object_thaw_notify (G_OBJECT (window));
1206   
1207   gtk_widget_queue_resize (GTK_WIDGET (window));
1208 }
1209
1210 static gboolean
1211 handle_keys_changed (gpointer data)
1212 {
1213   GtkWindow *window;
1214
1215   GDK_THREADS_ENTER ();
1216   window = GTK_WINDOW (data);
1217
1218   if (window->keys_changed_handler)
1219     {
1220       gtk_idle_remove (window->keys_changed_handler);
1221       window->keys_changed_handler = 0;
1222     }
1223
1224   g_signal_emit (window, window_signals[KEYS_CHANGED], 0);
1225   GDK_THREADS_LEAVE ();
1226   
1227   return FALSE;
1228 }
1229
1230 static void
1231 gtk_window_notify_keys_changed (GtkWindow *window)
1232 {
1233   if (!window->keys_changed_handler)
1234     window->keys_changed_handler = gtk_idle_add (handle_keys_changed, window);
1235 }
1236
1237 /**
1238  * gtk_window_add_accel_group:
1239  * @window: window to attach accelerator group to
1240  * @accel_group: a #GtkAccelGroup
1241  *
1242  * Associate @accel_group with @window, such that calling
1243  * gtk_accel_groups_activate() on @window will activate accelerators
1244  * in @accel_group.
1245  **/
1246 void
1247 gtk_window_add_accel_group (GtkWindow     *window,
1248                             GtkAccelGroup *accel_group)
1249 {
1250   g_return_if_fail (GTK_IS_WINDOW (window));
1251   g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group));
1252
1253   _gtk_accel_group_attach (accel_group, G_OBJECT (window));
1254   g_signal_connect_object (accel_group, "accel_changed",
1255                            G_CALLBACK (gtk_window_notify_keys_changed),
1256                            window, G_CONNECT_SWAPPED);
1257 }
1258
1259 /**
1260  * gtk_window_remove_accel_group:
1261  * @window: a #GtkWindow
1262  * @accel_group: a #GtkAccelGroup
1263  *
1264  * Reverses the effects of gtk_window_add_accel_group().
1265  **/
1266 void
1267 gtk_window_remove_accel_group (GtkWindow     *window,
1268                                GtkAccelGroup *accel_group)
1269 {
1270   g_return_if_fail (GTK_IS_WINDOW (window));
1271   g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group));
1272
1273   g_signal_handlers_disconnect_by_func (accel_group,
1274                                         gtk_window_notify_keys_changed,
1275                                         window);
1276   _gtk_accel_group_detach (accel_group, G_OBJECT (window));
1277 }
1278
1279 /**
1280  * gtk_window_add_mnemonic:
1281  * @window: a #GtkWindow
1282  * @keyval: the mnemonic
1283  * @target: the widget that gets activated by the mnemonic
1284  *
1285  * Adds a mnemonic to this window.
1286  */
1287 void
1288 gtk_window_add_mnemonic (GtkWindow *window,
1289                          guint      keyval,
1290                          GtkWidget *target)
1291 {
1292   GtkWindowMnemonic key;
1293   GtkWindowMnemonic *mnemonic;
1294
1295   g_return_if_fail (GTK_IS_WINDOW (window));
1296   g_return_if_fail (GTK_IS_WIDGET (target));
1297   
1298   key.window = window;
1299   key.keyval = keyval;
1300   mnemonic = g_hash_table_lookup (mnemonic_hash_table, &key);
1301
1302   if (mnemonic)
1303     {
1304       g_return_if_fail (g_slist_find (mnemonic->targets, target) == NULL);
1305       mnemonic->targets = g_slist_append (mnemonic->targets, target);
1306     }
1307   else
1308     {
1309       mnemonic = g_new (GtkWindowMnemonic, 1);
1310       *mnemonic = key;
1311       mnemonic->targets = g_slist_prepend (NULL, target);
1312       g_hash_table_insert (mnemonic_hash_table, mnemonic, mnemonic);
1313     }
1314   gtk_window_notify_keys_changed (window);
1315 }
1316
1317 /**
1318  * gtk_window_remove_mnemonic:
1319  * @window: a #GtkWindow
1320  * @keyval: the mnemonic
1321  * @target: the widget that gets activated by the mnemonic
1322  *
1323  * Removes a mnemonic from this window.
1324  */
1325 void
1326 gtk_window_remove_mnemonic (GtkWindow *window,
1327                             guint      keyval,
1328                             GtkWidget *target)
1329 {
1330   GtkWindowMnemonic key;
1331   GtkWindowMnemonic *mnemonic;
1332
1333   g_return_if_fail (GTK_IS_WINDOW (window));
1334   g_return_if_fail (GTK_IS_WIDGET (target));
1335   
1336   key.window = window;
1337   key.keyval = keyval;
1338   mnemonic = g_hash_table_lookup (mnemonic_hash_table, &key);
1339
1340   g_return_if_fail (mnemonic && g_slist_find (mnemonic->targets, target) != NULL);
1341
1342   mnemonic->targets = g_slist_remove (mnemonic->targets, target);
1343   if (mnemonic->targets == NULL)
1344     {
1345       g_hash_table_remove (mnemonic_hash_table, mnemonic);
1346       g_free (mnemonic);
1347     }
1348   gtk_window_notify_keys_changed (window);
1349 }
1350
1351 /**
1352  * gtk_window_mnemonic_activate:
1353  * @window: a #GtkWindow
1354  * @keyval: the mnemonic
1355  * @modifier: the modifiers 
1356  * @returns: %TRUE if the activation is done. 
1357  * 
1358  * Activates the targets associated with the mnemonic.
1359  */
1360 gboolean
1361 gtk_window_mnemonic_activate (GtkWindow      *window,
1362                               guint           keyval,
1363                               GdkModifierType modifier)
1364 {
1365   GtkWindowMnemonic key;
1366   GtkWindowMnemonic *mnemonic;
1367   GSList *list;
1368   GtkWidget *widget, *chosen_widget;
1369   gboolean overloaded;
1370
1371   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
1372
1373   if (window->mnemonic_modifier != (modifier & gtk_accelerator_get_default_mod_mask ()))
1374     return FALSE;
1375   
1376   key.window = window;
1377   key.keyval = keyval;
1378   mnemonic = g_hash_table_lookup (mnemonic_hash_table, &key);
1379
1380   if (!mnemonic)
1381     return FALSE;
1382   
1383   overloaded = FALSE;
1384   chosen_widget = NULL;
1385   list = mnemonic->targets;
1386   while (list)
1387     {
1388       widget = GTK_WIDGET (list->data);
1389       
1390       if (GTK_WIDGET_IS_SENSITIVE (widget) &&
1391           GTK_WIDGET_MAPPED (widget))
1392         {
1393           if (chosen_widget)
1394             {
1395               overloaded = TRUE;
1396               break;
1397             }
1398           else
1399             chosen_widget = widget;
1400         }
1401       list = g_slist_next (list);
1402     }
1403
1404   if (chosen_widget)
1405     {
1406       /* For round robin we put the activated entry on
1407        * the end of the list after activation
1408        */
1409       mnemonic->targets = g_slist_remove (mnemonic->targets, chosen_widget);
1410       mnemonic->targets = g_slist_append (mnemonic->targets, chosen_widget);
1411
1412       return gtk_widget_mnemonic_activate (chosen_widget, overloaded);
1413     }
1414   return FALSE;
1415 }
1416
1417 /**
1418  * gtk_window_set_mnemonic_modifier:
1419  * @window: a #GtkWindow
1420  * @modifier: the modifier mask used to activate
1421  *               mnemonics on this window.
1422  *
1423  * Sets the mnemonic modifier for this window. 
1424  **/
1425 void
1426 gtk_window_set_mnemonic_modifier (GtkWindow      *window,
1427                                   GdkModifierType modifier)
1428 {
1429   g_return_if_fail (GTK_IS_WINDOW (window));
1430   g_return_if_fail ((modifier & ~GDK_MODIFIER_MASK) == 0);
1431
1432   window->mnemonic_modifier = modifier;
1433   gtk_window_notify_keys_changed (window);
1434 }
1435
1436 /**
1437  * gtk_window_get_mnemonic_modifier:
1438  * @window: a #GtkWindow
1439  *
1440  * Returns the mnemonic modifier for this window. See
1441  * gtk_window_set_mnemonic_modifier().
1442  *
1443  * Return value: the modifier mask used to activate
1444  *               mnemonics on this window.
1445  **/
1446 GdkModifierType
1447 gtk_window_get_mnemonic_modifier (GtkWindow *window)
1448 {
1449   g_return_val_if_fail (GTK_IS_WINDOW (window), 0);
1450
1451   return window->mnemonic_modifier;
1452 }
1453
1454 /**
1455  * gtk_window_set_position:
1456  * @window: a #GtkWindow.
1457  * @position: a position constraint.
1458  *
1459  * Sets a position constraint for this window. If the old or new
1460  * constraint is %GTK_WIN_POS_CENTER_ALWAYS, this will also cause
1461  * the window to be repositioned to satisfy the new constraint. 
1462  **/
1463 void
1464 gtk_window_set_position (GtkWindow         *window,
1465                          GtkWindowPosition  position)
1466 {
1467   g_return_if_fail (GTK_IS_WINDOW (window));
1468
1469   if (position == GTK_WIN_POS_CENTER_ALWAYS ||
1470       window->position == GTK_WIN_POS_CENTER_ALWAYS)
1471     {
1472       GtkWindowGeometryInfo *info;
1473
1474       info = gtk_window_get_geometry_info (window, TRUE);
1475
1476       /* this flag causes us to re-request the CENTER_ALWAYS
1477        * constraint in gtk_window_move_resize(), see
1478        * comment in that function.
1479        */
1480       info->position_constraints_changed = TRUE;
1481
1482       gtk_widget_queue_resize (GTK_WIDGET (window));
1483     }
1484
1485   window->position = position;
1486   
1487   g_object_notify (G_OBJECT (window), "window_position");
1488 }
1489
1490 /**
1491  * gtk_window_activate_focus:
1492  * @window: a #GtkWindow
1493  * 
1494  * Activates the current focused widget within the window.
1495  * 
1496  * Return value: %TRUE if a widget got activated.
1497  **/
1498 gboolean 
1499 gtk_window_activate_focus (GtkWindow *window)
1500 {
1501   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
1502
1503   if (window->focus_widget)
1504     {
1505       if (GTK_WIDGET_IS_SENSITIVE (window->focus_widget))
1506         gtk_widget_activate (window->focus_widget);
1507       return TRUE;
1508     }
1509
1510   return FALSE;
1511 }
1512
1513 /**
1514  * gtk_window_get_focus:
1515  * @window: a #GtkWindow
1516  * 
1517  * Retrieves the current focused widget within the window.
1518  * Note that this is the widget that would have the focus
1519  * if the toplevel window focused; if the toplevel window
1520  * is not focused then  <literal>GTK_WIDGET_HAS_FOCUS (widget)</literal> will
1521  * not be %TRUE for the widget. 
1522  * 
1523  * Return value: the currently focused widget.
1524  **/
1525 GtkWidget *
1526 gtk_window_get_focus (GtkWindow *window)
1527 {
1528   g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
1529
1530   return window->focus_widget;
1531 }
1532
1533 /**
1534  * gtk_window_activate_default:
1535  * @window: a #GtkWindow
1536  * 
1537  * Activates the default widget for the window, unless the current 
1538  * focused widget has been configured to receive the default action 
1539  * (see #GTK_RECEIVES_DEFAULT in #GtkWidgetFlags), in which case the
1540  * focused widget is activated. 
1541  * 
1542  * Return value: %TRUE if a widget got activated.
1543  **/
1544 gboolean
1545 gtk_window_activate_default (GtkWindow *window)
1546 {
1547   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
1548
1549   if (window->default_widget && GTK_WIDGET_IS_SENSITIVE (window->default_widget) &&
1550       (!window->focus_widget || !GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget)))
1551     {
1552       gtk_widget_activate (window->default_widget);
1553       return TRUE;
1554     }
1555   else if (window->focus_widget)
1556     {
1557       if (GTK_WIDGET_IS_SENSITIVE (window->focus_widget))
1558         gtk_widget_activate (window->focus_widget);
1559       return TRUE;
1560     }
1561
1562   return FALSE;
1563 }
1564
1565 /**
1566  * gtk_window_set_modal:
1567  * @window: a #GtkWindow
1568  * @modal: whether the window is modal
1569  * 
1570  * Sets a window modal or non-modal. Modal windows prevent interaction
1571  * with other windows in the same application. To keep modal dialogs
1572  * on top of main application windows, use
1573  * gtk_window_set_transient_for() to make the dialog transient for the
1574  * parent; most <link linkend="gtk-X11-arch">window managers</link>
1575  * will then disallow lowering the dialog below the parent.
1576  * 
1577  * 
1578  **/
1579 void
1580 gtk_window_set_modal (GtkWindow *window,
1581                       gboolean   modal)
1582 {
1583   g_return_if_fail (GTK_IS_WINDOW (window));
1584
1585   window->modal = modal != FALSE;
1586   
1587   /* adjust desired modality state */
1588   if (GTK_WIDGET_VISIBLE (window) && window->modal)
1589     gtk_grab_add (GTK_WIDGET (window));
1590   else
1591     gtk_grab_remove (GTK_WIDGET (window));
1592
1593   g_object_notify (G_OBJECT (window), "modal");
1594 }
1595
1596 /**
1597  * gtk_window_get_modal:
1598  * @window: a #GtkWindow
1599  * 
1600  * Returns whether the window is modal. See gtk_window_set_modal().
1601  *
1602  * Return value: %TRUE if the window is set to be modal and
1603  *               establishes a grab when shown
1604  **/
1605 gboolean
1606 gtk_window_get_modal (GtkWindow *window)
1607 {
1608   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
1609
1610   return window->modal;
1611 }
1612
1613 /**
1614  * gtk_window_list_toplevels:
1615  * 
1616  * Returns a list of all existing toplevel windows. The widgets
1617  * in the list are not individually referenced. If you want
1618  * to iterate through the list and perform actions involving
1619  * callbacks that might destroy the widgets, you <emphasis>must</emphasis> call
1620  * <literal>g_list_foreach (result, (GFunc)g_object_ref, NULL)</literal> first, and
1621  * then unref all the widgets afterwards.
1622  * 
1623  * Return value: list of toplevel widgets
1624  **/
1625 GList*
1626 gtk_window_list_toplevels (void)
1627 {
1628   GList *list = NULL;
1629   GSList *slist;
1630
1631   for (slist = toplevel_list; slist; slist = slist->next)
1632     list = g_list_prepend (list, slist->data);
1633
1634   return list;
1635 }
1636
1637 void
1638 gtk_window_add_embedded_xid (GtkWindow *window, guint xid)
1639 {
1640   GList *embedded_windows;
1641
1642   g_return_if_fail (GTK_IS_WINDOW (window));
1643
1644   embedded_windows = g_object_get_data (G_OBJECT (window), "gtk-embedded");
1645   if (embedded_windows)
1646     g_object_steal_qdata (G_OBJECT (window), 
1647                           g_quark_from_static_string ("gtk-embedded"));
1648   embedded_windows = g_list_prepend (embedded_windows,
1649                                      GUINT_TO_POINTER (xid));
1650
1651   g_object_set_data_full (G_OBJECT (window), "gtk-embedded", 
1652                           embedded_windows,
1653                           embedded_windows ?
1654                             (GDestroyNotify) g_list_free : NULL);
1655 }
1656
1657 void
1658 gtk_window_remove_embedded_xid (GtkWindow *window, guint xid)
1659 {
1660   GList *embedded_windows;
1661   GList *node;
1662
1663   g_return_if_fail (GTK_IS_WINDOW (window));
1664   
1665   embedded_windows = g_object_get_data (G_OBJECT (window), "gtk-embedded");
1666   if (embedded_windows)
1667     g_object_steal_qdata (G_OBJECT (window), 
1668                           g_quark_from_static_string ("gtk-embedded"));
1669
1670   node = g_list_find (embedded_windows, GUINT_TO_POINTER (xid));
1671   if (node)
1672     {
1673       embedded_windows = g_list_remove_link (embedded_windows, node);
1674       g_list_free_1 (node);
1675     }
1676   
1677   g_object_set_data_full (G_OBJECT (window), "gtk-embedded",
1678                           embedded_windows,
1679                           embedded_windows ?
1680                             (GDestroyNotify) g_list_free : NULL);
1681 }
1682
1683 void       
1684 _gtk_window_reposition (GtkWindow *window,
1685                         gint       x,
1686                         gint       y)
1687 {
1688   g_return_if_fail (GTK_IS_WINDOW (window));
1689
1690   gtk_window_move (window, x, y);
1691 }
1692
1693 static void
1694 gtk_window_dispose (GObject *object)
1695 {
1696   GtkWindow *window = GTK_WINDOW (object);
1697
1698   gtk_window_set_focus (window, NULL);
1699   gtk_window_set_default (window, NULL);
1700
1701   G_OBJECT_CLASS (parent_class)->dispose (object);
1702 }
1703
1704 static void
1705 parent_destroyed_callback (GtkWindow *parent, GtkWindow *child)
1706 {
1707   gtk_widget_destroy (GTK_WIDGET (child));
1708 }
1709
1710 static void
1711 connect_parent_destroyed (GtkWindow *window)
1712 {
1713   if (window->transient_parent)
1714     {
1715       g_signal_connect (window->transient_parent,
1716                         "destroy",
1717                         G_CALLBACK (parent_destroyed_callback),
1718                         window);
1719     }  
1720 }
1721
1722 static void
1723 disconnect_parent_destroyed (GtkWindow *window)
1724 {
1725   if (window->transient_parent)
1726     {
1727       g_signal_handlers_disconnect_by_func (window->transient_parent,
1728                                             parent_destroyed_callback,
1729                                             window);
1730     }
1731 }
1732
1733 static void
1734 gtk_window_transient_parent_realized (GtkWidget *parent,
1735                                       GtkWidget *window)
1736 {
1737   if (GTK_WIDGET_REALIZED (window))
1738     gdk_window_set_transient_for (window->window, parent->window);
1739 }
1740
1741 static void
1742 gtk_window_transient_parent_unrealized (GtkWidget *parent,
1743                                         GtkWidget *window)
1744 {
1745   if (GTK_WIDGET_REALIZED (window))
1746     gdk_property_delete (window->window, 
1747                          gdk_atom_intern ("WM_TRANSIENT_FOR", FALSE));
1748 }
1749
1750 static void
1751 gtk_window_transient_parent_screen_changed (GtkWindow   *parent,
1752                                             GParamSpec  *pspec,
1753                                             GtkWindow   *window)
1754 {
1755   gtk_window_set_screen (window, parent->screen);
1756 }
1757
1758 static void       
1759 gtk_window_unset_transient_for  (GtkWindow *window)
1760 {
1761   if (window->transient_parent)
1762     {
1763       g_signal_handlers_disconnect_by_func (window->transient_parent,
1764                                             gtk_window_transient_parent_realized,
1765                                             window);
1766       g_signal_handlers_disconnect_by_func (window->transient_parent,
1767                                             gtk_window_transient_parent_unrealized,
1768                                             window);
1769       g_signal_handlers_disconnect_by_func (window->transient_parent,
1770                                             gtk_window_transient_parent_screen_changed,
1771                                             window);
1772       g_signal_handlers_disconnect_by_func (window->transient_parent,
1773                                             gtk_widget_destroyed,
1774                                             &window->transient_parent);
1775
1776       if (window->destroy_with_parent)
1777         disconnect_parent_destroyed (window);
1778       
1779       window->transient_parent = NULL;
1780     }
1781 }
1782
1783 /**
1784  * gtk_window_set_transient_for:
1785  * @window: a #GtkWindow
1786  * @parent: parent window
1787  *
1788  * Dialog windows should be set transient for the main application
1789  * window they were spawned from. This allows <link
1790  * linkend="gtk-X11-arch">window managers</link> to e.g. keep the
1791  * dialog on top of the main window, or center the dialog over the
1792  * main window. gtk_dialog_new_with_buttons() and other convenience
1793  * functions in GTK+ will sometimes call
1794  * gtk_window_set_transient_for() on your behalf.
1795  *
1796  * On Windows, this function will and put the child window
1797  * on top of the parent, much as the window manager would have
1798  * done on X.
1799  * 
1800  **/
1801 void       
1802 gtk_window_set_transient_for  (GtkWindow *window, 
1803                                GtkWindow *parent)
1804 {
1805   g_return_if_fail (GTK_IS_WINDOW (window));
1806   g_return_if_fail (parent == NULL || GTK_IS_WINDOW (parent));
1807   g_return_if_fail (window != parent);
1808
1809     
1810   if (window->transient_parent)
1811     {
1812       if (GTK_WIDGET_REALIZED (window) && 
1813           GTK_WIDGET_REALIZED (window->transient_parent) && 
1814           (!parent || !GTK_WIDGET_REALIZED (parent)))
1815         gtk_window_transient_parent_unrealized (GTK_WIDGET (window->transient_parent),
1816                                                 GTK_WIDGET (window));
1817
1818       gtk_window_unset_transient_for (window);
1819     }
1820
1821   window->transient_parent = parent;
1822
1823   if (parent)
1824     {
1825       g_signal_connect (parent, "destroy",
1826                         G_CALLBACK (gtk_widget_destroyed),
1827                         &window->transient_parent);
1828       g_signal_connect (parent, "realize",
1829                         G_CALLBACK (gtk_window_transient_parent_realized),
1830                         window);
1831       g_signal_connect (parent, "unrealize",
1832                         G_CALLBACK (gtk_window_transient_parent_unrealized),
1833                         window);
1834       g_signal_connect (parent, "notify::screen",
1835                         G_CALLBACK (gtk_window_transient_parent_screen_changed),
1836                         window);
1837       
1838       gtk_window_set_screen (window, parent->screen);
1839
1840       if (window->destroy_with_parent)
1841         connect_parent_destroyed (window);
1842       
1843       if (GTK_WIDGET_REALIZED (window) &&
1844           GTK_WIDGET_REALIZED (parent))
1845         gtk_window_transient_parent_realized (GTK_WIDGET (parent),
1846                                               GTK_WIDGET (window));
1847     }
1848 }
1849
1850 /**
1851  * gtk_window_get_transient_for:
1852  * @window: a #GtkWindow
1853  *
1854  * Fetches the transient parent for this window. See
1855  * gtk_window_set_transient_for().
1856  *
1857  * Return value: the transient parent for this window, or %NULL
1858  *    if no transient parent has been set.
1859  **/
1860 GtkWindow *
1861 gtk_window_get_transient_for (GtkWindow *window)
1862 {
1863   g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
1864
1865   return window->transient_parent;
1866 }
1867
1868 /**
1869  * gtk_window_set_type_hint:
1870  * @window: a #GtkWindow
1871  * @hint: the window type
1872  *
1873  * By setting the type hint for the window, you allow the window
1874  * manager to decorate and handle the window in a way which is
1875  * suitable to the function of the window in your application.
1876  *
1877  * This function should be called before the window becomes visible.
1878  *
1879  * gtk_dialog_new_with_buttons() and other convenience functions in GTK+
1880  * will sometimes call gtk_window_set_type_hint() on your behalf.
1881  * 
1882  **/
1883 void
1884 gtk_window_set_type_hint (GtkWindow           *window, 
1885                           GdkWindowTypeHint    hint)
1886 {
1887   g_return_if_fail (GTK_IS_WINDOW (window));
1888   g_return_if_fail (!GTK_WIDGET_VISIBLE (window));
1889   window->type_hint = hint;
1890 }
1891
1892 /**
1893  * gtk_window_get_type_hint:
1894  * @window: a #GtkWindow
1895  *
1896  * Gets the type hint for this window. See gtk_window_set_type_hint().
1897  *
1898  * Return value: the type hint for @window.
1899  **/
1900 GdkWindowTypeHint
1901 gtk_window_get_type_hint (GtkWindow *window)
1902 {
1903   g_return_val_if_fail (GTK_IS_WINDOW (window), GDK_WINDOW_TYPE_HINT_NORMAL);
1904
1905   return window->type_hint;
1906 }
1907
1908 /**
1909  * gtk_window_set_skip_taskbar_hint:
1910  * @window: a #GtkWindow 
1911  * @setting: %TRUE to keep this window from appearing in the task bar
1912  * 
1913  * Windows may set a hint asking the desktop environment not to display
1914  * the window in the task bar. This function toggles this hint.
1915  * 
1916  * Since: 2.2
1917  **/
1918 void
1919 gtk_window_set_skip_taskbar_hint (GtkWindow *window,
1920                                   gboolean   setting)
1921 {
1922   GtkWindowPrivate *priv;
1923
1924   g_return_if_fail (GTK_IS_WINDOW (window));
1925   
1926   priv = gtk_window_get_private (window);
1927
1928   setting = setting != FALSE;
1929
1930   if (priv->skips_taskbar != setting)
1931     {
1932       priv->skips_taskbar = setting;
1933       if (GTK_WIDGET_REALIZED (window))
1934         gdk_window_set_skip_taskbar_hint (GTK_WIDGET (window)->window,
1935                                           priv->skips_taskbar);
1936       g_object_notify (G_OBJECT (window), "skip_taskbar_hint");
1937     }
1938 }
1939
1940 /**
1941  * gtk_window_get_skip_taskbar_hint:
1942  * @window: a #GtkWindow
1943  * 
1944  * Gets the value set by gtk_window_set_skip_taskbar_hint()
1945  * 
1946  * Return value: %TRUE if window shouldn't be in taskbar
1947  * 
1948  * Since: 2.2
1949  **/
1950 gboolean
1951 gtk_window_get_skip_taskbar_hint (GtkWindow *window)
1952 {
1953   GtkWindowPrivate *priv;
1954
1955   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
1956   
1957   priv = gtk_window_get_private (window);
1958
1959   return priv->skips_taskbar;
1960 }
1961
1962 /**
1963  * gtk_window_set_skip_pager_hint:
1964  * @window: a #GtkWindow 
1965  * @setting: %TRUE to keep this window from appearing in the pager
1966  * 
1967  * Windows may set a hint asking the desktop environment not to display
1968  * the window in the pager. This function toggles this hint.
1969  * (A "pager" is any desktop navigation tool such as a workspace
1970  * switcher that displays a thumbnail representation of the windows
1971  * on the screen.)
1972  * 
1973  * Since: 2.2
1974  **/
1975 void
1976 gtk_window_set_skip_pager_hint (GtkWindow *window,
1977                                 gboolean   setting)
1978 {
1979   GtkWindowPrivate *priv;
1980
1981   g_return_if_fail (GTK_IS_WINDOW (window));
1982   
1983   priv = gtk_window_get_private (window);
1984
1985   setting = setting != FALSE;
1986
1987   if (priv->skips_pager != setting)
1988     {
1989       priv->skips_pager = setting;
1990       if (GTK_WIDGET_REALIZED (window))
1991         gdk_window_set_skip_pager_hint (GTK_WIDGET (window)->window,
1992                                         priv->skips_pager);
1993       g_object_notify (G_OBJECT (window), "skip_pager_hint");
1994     }
1995 }
1996
1997 /**
1998  * gtk_window_get_skip_pager_hint:
1999  * @window: a #GtkWindow
2000  * 
2001  * Gets the value set by gtk_window_set_skip_pager_hint().
2002  * 
2003  * Return value: %TRUE if window shouldn't be in pager
2004  * 
2005  * Since: 2.2
2006  **/
2007 gboolean
2008 gtk_window_get_skip_pager_hint (GtkWindow *window)
2009 {
2010   GtkWindowPrivate *priv;
2011
2012   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
2013   
2014   priv = gtk_window_get_private (window);
2015
2016   return priv->skips_pager;
2017 }
2018
2019 /**
2020  * gtk_window_set_destroy_with_parent:
2021  * @window: a #GtkWindow
2022  * @setting: whether to destroy @window with its transient parent
2023  * 
2024  * If @setting is %TRUE, then destroying the transient parent of @window
2025  * will also destroy @window itself. This is useful for dialogs that
2026  * shouldn't persist beyond the lifetime of the main window they're
2027  * associated with, for example.
2028  **/
2029 void
2030 gtk_window_set_destroy_with_parent  (GtkWindow *window,
2031                                      gboolean   setting)
2032 {
2033   g_return_if_fail (GTK_IS_WINDOW (window));
2034
2035   if (window->destroy_with_parent == (setting != FALSE))
2036     return;
2037
2038   if (window->destroy_with_parent)
2039     {
2040       disconnect_parent_destroyed (window);
2041     }
2042   else
2043     {
2044       connect_parent_destroyed (window);
2045     }
2046   
2047   window->destroy_with_parent = setting;
2048
2049   g_object_notify (G_OBJECT (window), "destroy_with_parent");
2050 }
2051
2052 /**
2053  * gtk_window_get_destroy_with_parent:
2054  * @window: a #GtkWindow
2055  * 
2056  * Returns whether the window will be destroyed with its transient parent. See
2057  * gtk_window_set_destroy_with_parent ().
2058  *
2059  * Return value: %TRUE if the window will be destroyed with its transient parent.
2060  **/
2061 gboolean
2062 gtk_window_get_destroy_with_parent (GtkWindow *window)
2063 {
2064   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
2065
2066   return window->destroy_with_parent;
2067 }
2068
2069 static GtkWindowGeometryInfo*
2070 gtk_window_get_geometry_info (GtkWindow *window,
2071                               gboolean   create)
2072 {
2073   GtkWindowGeometryInfo *info;
2074
2075   info = window->geometry_info;
2076   if (!info && create)
2077     {
2078       info = g_new0 (GtkWindowGeometryInfo, 1);
2079
2080       info->default_width = -1;
2081       info->default_height = -1;
2082       info->resize_width = -1;
2083       info->resize_height = -1;
2084       info->initial_x = 0;
2085       info->initial_y = 0;
2086       info->initial_pos_set = FALSE;
2087       info->default_is_geometry = FALSE;
2088       info->position_constraints_changed = FALSE;
2089       info->last.configure_request.x = 0;
2090       info->last.configure_request.y = 0;
2091       info->last.configure_request.width = -1;
2092       info->last.configure_request.height = -1;
2093       info->widget = NULL;
2094       info->mask = 0;
2095       window->geometry_info = info;
2096     }
2097
2098   return info;
2099 }
2100
2101 /**
2102  * gtk_window_set_geometry_hints:
2103  * @window: a #GtkWindow
2104  * @geometry_widget: widget the geometry hints will be applied to
2105  * @geometry: struct containing geometry information
2106  * @geom_mask: mask indicating which struct fields should be paid attention to
2107  *
2108  * This function sets up hints about how a window can be resized by
2109  * the user.  You can set a minimum and maximum size; allowed resize
2110  * increments (e.g. for xterm, you can only resize by the size of a
2111  * character); aspect ratios; and more. See the #GdkGeometry struct.
2112  * 
2113  **/
2114 void       
2115 gtk_window_set_geometry_hints (GtkWindow       *window,
2116                                GtkWidget       *geometry_widget,
2117                                GdkGeometry     *geometry,
2118                                GdkWindowHints   geom_mask)
2119 {
2120   GtkWindowGeometryInfo *info;
2121
2122   g_return_if_fail (GTK_IS_WINDOW (window));
2123   g_return_if_fail (geometry_widget == NULL || GTK_IS_WIDGET (geometry_widget));
2124
2125   info = gtk_window_get_geometry_info (window, TRUE);
2126   
2127   if (info->widget)
2128     g_signal_handlers_disconnect_by_func (info->widget,
2129                                           gtk_widget_destroyed,
2130                                           &info->widget);
2131   
2132   info->widget = geometry_widget;
2133   if (info->widget)
2134     g_signal_connect (geometry_widget, "destroy",
2135                       G_CALLBACK (gtk_widget_destroyed),
2136                       &info->widget);
2137
2138   if (geometry)
2139     info->geometry = *geometry;
2140
2141   /* We store gravity in window->gravity not in the hints. */
2142   info->mask = geom_mask & ~(GDK_HINT_WIN_GRAVITY);
2143
2144   if (geom_mask & GDK_HINT_WIN_GRAVITY)
2145     {
2146       gtk_window_set_gravity (window, geometry->win_gravity);
2147     }
2148   
2149   gtk_widget_queue_resize (GTK_WIDGET (window));
2150 }
2151
2152 /**
2153  * gtk_window_set_decorated:
2154  * @window: a #GtkWindow
2155  * @setting: %TRUE to decorate the window
2156  *
2157  * By default, windows are decorated with a title bar, resize
2158  * controls, etc.  Some <link linkend="gtk-X11-arch">window
2159  * managers</link> allow GTK+ to disable these decorations, creating a
2160  * borderless window. If you set the decorated property to %FALSE
2161  * using this function, GTK+ will do its best to convince the window
2162  * manager not to decorate the window. Depending on the system, this
2163  * function may not have any effect when called on a window that is
2164  * already visible, so you should call it before calling gtk_window_show().
2165  *
2166  * On Windows, this function always works, since there's no window manager
2167  * policy involved.
2168  * 
2169  **/
2170 void
2171 gtk_window_set_decorated (GtkWindow *window,
2172                           gboolean   setting)
2173 {
2174   g_return_if_fail (GTK_IS_WINDOW (window));
2175
2176   setting = setting != FALSE;
2177
2178   if (setting == window->decorated)
2179     return;
2180
2181   window->decorated = setting;
2182   
2183   if (GTK_WIDGET (window)->window)
2184     {
2185       if (window->decorated)
2186         gdk_window_set_decorations (GTK_WIDGET (window)->window,
2187                                     GDK_DECOR_ALL);
2188       else
2189         gdk_window_set_decorations (GTK_WIDGET (window)->window,
2190                                     0);
2191     }
2192 }
2193
2194 /**
2195  * gtk_window_get_decorated:
2196  * @window: a #GtkWindow
2197  *
2198  * Returns whether the window has been set to have decorations
2199  * such as a title bar via gtk_window_set_decorated().
2200  *
2201  * Return value: %TRUE if the window has been set to have decorations
2202  **/
2203 gboolean
2204 gtk_window_get_decorated (GtkWindow *window)
2205 {
2206   g_return_val_if_fail (GTK_IS_WINDOW (window), TRUE);
2207
2208   return window->decorated;
2209 }
2210
2211 static GtkWindowIconInfo*
2212 get_icon_info (GtkWindow *window)
2213 {
2214   return g_object_get_data (G_OBJECT (window),
2215                             "gtk-window-icon-info");
2216 }
2217      
2218 static GtkWindowIconInfo*
2219 ensure_icon_info (GtkWindow *window)
2220 {
2221   GtkWindowIconInfo *info;
2222
2223   info = get_icon_info (window);
2224   
2225   if (info == NULL)
2226     {
2227       info = g_new0 (GtkWindowIconInfo, 1);
2228       g_object_set_data_full (G_OBJECT (window),
2229                               "gtk-window-icon-info",
2230                               info,
2231                               g_free);
2232     }
2233
2234   return info;
2235 }
2236
2237 typedef struct {
2238   guint serial;
2239   GdkPixmap *pixmap;
2240   GdkPixmap *mask;
2241 } ScreenIconInfo;
2242
2243 ScreenIconInfo *
2244 get_screen_icon_info (GdkScreen *screen)
2245 {
2246   ScreenIconInfo *info = g_object_get_data (G_OBJECT (screen), 
2247                                             "gtk-window-default-icon-pixmap");
2248   if (!info)
2249     {
2250       info = g_new0 (ScreenIconInfo, 1);
2251       g_object_set_data (G_OBJECT (screen), "gtk-window-default-icon-pixmap", info);
2252     }
2253
2254   if (info->serial != default_icon_serial)
2255     {
2256       if (info->pixmap)
2257         {
2258           g_object_remove_weak_pointer (G_OBJECT (info->pixmap), (gpointer*)&info->pixmap);
2259           info->pixmap = NULL;
2260         }
2261           
2262       if (info->mask)
2263         {
2264           g_object_remove_weak_pointer (G_OBJECT (info->mask), (gpointer*)&info->mask);
2265           info->mask = NULL;
2266         }
2267
2268       info->serial = default_icon_serial;
2269     }
2270   
2271   return info;
2272 }
2273
2274 static void
2275 get_pixmap_and_mask (GdkWindow          *window,
2276                      GtkWindowIconInfo  *parent_info,
2277                      gboolean            is_default_list,
2278                      GList              *icon_list,
2279                      GdkPixmap         **pmap_return,
2280                      GdkBitmap         **mask_return)
2281 {
2282   GdkScreen *screen = gdk_drawable_get_screen (window);
2283   ScreenIconInfo *default_icon_info = get_screen_icon_info (screen);
2284   GdkPixbuf *best_icon;
2285   GList *tmp_list;
2286   int best_size;
2287   
2288   *pmap_return = NULL;
2289   *mask_return = NULL;
2290   
2291   if (is_default_list &&
2292       default_icon_info->pixmap != NULL)
2293     {
2294       /* Use shared icon pixmap for all windows on this screen.
2295        */
2296       if (default_icon_info->pixmap)
2297         g_object_ref (default_icon_info->pixmap);
2298       if (default_icon_info->mask)
2299         g_object_ref (default_icon_info->mask);
2300
2301       *pmap_return = default_icon_info->pixmap;
2302       *mask_return = default_icon_info->mask;
2303     }
2304   else if (parent_info && parent_info->icon_pixmap)
2305     {
2306       if (parent_info->icon_pixmap)
2307         g_object_ref (parent_info->icon_pixmap);
2308       if (parent_info->icon_mask)
2309         g_object_ref (parent_info->icon_mask);
2310       
2311       *pmap_return = parent_info->icon_pixmap;
2312       *mask_return = parent_info->icon_mask;
2313     }
2314   else
2315     {
2316 #define IDEAL_SIZE 48
2317   
2318       best_size = G_MAXINT;
2319       best_icon = NULL;
2320       tmp_list = icon_list;
2321       while (tmp_list != NULL)
2322         {
2323           GdkPixbuf *pixbuf = tmp_list->data;
2324           int this;
2325       
2326           /* average width and height - if someone passes in a rectangular
2327            * icon they deserve what they get.
2328            */
2329           this = gdk_pixbuf_get_width (pixbuf) + gdk_pixbuf_get_height (pixbuf);
2330           this /= 2;
2331       
2332           if (best_icon == NULL)
2333             {
2334               best_icon = pixbuf;
2335               best_size = this;
2336             }
2337           else
2338             {
2339               /* icon is better if it's 32 pixels or larger, and closer to
2340                * the ideal size than the current best.
2341                */
2342               if (this >= 32 &&
2343                   (ABS (best_size - IDEAL_SIZE) <
2344                    ABS (this - IDEAL_SIZE)))
2345                 {
2346                   best_icon = pixbuf;
2347                   best_size = this;
2348                 }
2349             }
2350
2351           tmp_list = tmp_list->next;
2352         }
2353
2354       if (best_icon)
2355         gdk_pixbuf_render_pixmap_and_mask_for_colormap (best_icon,
2356                                                         gdk_screen_get_system_colormap (screen),
2357                                                         pmap_return,
2358                                                         mask_return,
2359                                                         128);
2360
2361       /* Save pmap/mask for others to use if appropriate */
2362       if (parent_info)
2363         {
2364           parent_info->icon_pixmap = *pmap_return;
2365           parent_info->icon_mask = *mask_return;
2366
2367           if (parent_info->icon_pixmap)
2368             g_object_ref (parent_info->icon_pixmap);
2369           if (parent_info->icon_mask)
2370             g_object_ref (parent_info->icon_mask);
2371         }
2372       else if (is_default_list)
2373         {
2374           default_icon_info->pixmap = *pmap_return;
2375           default_icon_info->mask = *mask_return;
2376
2377           if (default_icon_info->pixmap)
2378             g_object_add_weak_pointer (G_OBJECT (default_icon_info->pixmap),
2379                                        (gpointer*)&default_icon_info->pixmap);
2380           if (default_icon_info->mask) 
2381             g_object_add_weak_pointer (G_OBJECT (default_icon_info->mask),
2382                                        (gpointer*)&default_icon_info->mask);
2383         }
2384     }
2385 }
2386
2387 static void
2388 gtk_window_realize_icon (GtkWindow *window)
2389 {
2390   GtkWidget *widget;
2391   GtkWindowIconInfo *info;
2392   GList *icon_list;
2393   
2394   widget = GTK_WIDGET (window);
2395
2396   g_return_if_fail (widget->window != NULL);
2397
2398   /* no point setting an icon on override-redirect */
2399   if (window->type == GTK_WINDOW_POPUP)
2400     return;
2401
2402   icon_list = NULL;
2403   
2404   info = ensure_icon_info (window);
2405
2406   if (info->realized)
2407     return;
2408
2409   g_return_if_fail (info->icon_pixmap == NULL);
2410   g_return_if_fail (info->icon_mask == NULL);
2411   
2412   info->using_default_icon = FALSE;
2413   info->using_parent_icon = FALSE;
2414   
2415   icon_list = info->icon_list;
2416   
2417   /* Inherit from transient parent */
2418   if (icon_list == NULL && window->transient_parent)
2419     {
2420       icon_list = ensure_icon_info (window->transient_parent)->icon_list;
2421       if (icon_list)
2422         info->using_parent_icon = TRUE;
2423     }      
2424
2425   /* Inherit from default */
2426   if (icon_list == NULL)
2427     {
2428       icon_list = default_icon_list;
2429       if (icon_list)
2430         info->using_default_icon = TRUE;
2431     }
2432   
2433   gdk_window_set_icon_list (widget->window, icon_list);
2434
2435   get_pixmap_and_mask (widget->window,
2436                        info->using_parent_icon ? ensure_icon_info (window->transient_parent) : NULL,
2437                        info->using_default_icon,
2438                        icon_list,
2439                        &info->icon_pixmap,
2440                        &info->icon_mask);
2441   
2442   /* This is a slight ICCCM violation since it's a color pixmap not
2443    * a bitmap, but everyone does it.
2444    */
2445   gdk_window_set_icon (widget->window,
2446                        NULL,
2447                        info->icon_pixmap,
2448                        info->icon_mask);
2449
2450   info->realized = TRUE;
2451 }
2452
2453 static void
2454 gtk_window_unrealize_icon (GtkWindow *window)
2455 {
2456   GtkWindowIconInfo *info;
2457   GtkWidget *widget;
2458
2459   widget = GTK_WIDGET (window);
2460   
2461   info = get_icon_info (window);
2462
2463   if (info == NULL)
2464     return;
2465   
2466   if (info->icon_pixmap)
2467     g_object_unref (info->icon_pixmap);
2468
2469   if (info->icon_mask)
2470     g_object_unref (info->icon_mask);
2471
2472   info->icon_pixmap = NULL;
2473   info->icon_mask = NULL;
2474
2475   /* We don't clear the properties on the window, just figure the
2476    * window is going away.
2477    */
2478
2479   info->realized = FALSE;
2480 }
2481
2482 /**
2483  * gtk_window_set_icon_list:
2484  * @window: a #GtkWindow
2485  * @list: list of #GdkPixbuf
2486  *
2487  * Sets up the icon representing a #GtkWindow. The icon is used when
2488  * the window is minimized (also known as iconified).  Some window
2489  * managers or desktop environments may also place it in the window
2490  * frame, or display it in other contexts.
2491  *
2492  * gtk_window_set_icon_list() allows you to pass in the same icon in
2493  * several hand-drawn sizes. The list should contain the natural sizes
2494  * your icon is available in; that is, don't scale the image before
2495  * passing it to GTK+. Scaling is postponed until the last minute,
2496  * when the desired final size is known, to allow best quality.
2497  *
2498  * By passing several sizes, you may improve the final image quality
2499  * of the icon, by reducing or eliminating automatic image scaling.
2500  *
2501  * Recommended sizes to provide: 16x16, 32x32, 48x48 at minimum, and
2502  * larger images (64x64, 128x128) if you have them.
2503  *
2504  * See also gtk_window_set_default_icon_list() to set the icon
2505  * for all windows in your application in one go.
2506  *
2507  * Note that transient windows (those who have been set transient for another
2508  * window using gtk_window_set_transient_for()) will inherit their
2509  * icon from their transient parent. So there's no need to explicitly
2510  * set the icon on transient windows.
2511  **/
2512 void
2513 gtk_window_set_icon_list (GtkWindow  *window,
2514                           GList      *list)
2515 {
2516   GtkWindowIconInfo *info;
2517
2518   g_return_if_fail (GTK_IS_WINDOW (window));
2519
2520   info = ensure_icon_info (window);
2521
2522   if (info->icon_list == list) /* check for NULL mostly */
2523     return;
2524
2525   g_list_foreach (info->icon_list,
2526                   (GFunc) g_object_unref, NULL);
2527
2528   g_list_free (info->icon_list);
2529
2530   info->icon_list = g_list_copy (list);
2531   g_list_foreach (info->icon_list,
2532                   (GFunc) g_object_ref, NULL);
2533
2534   g_object_notify (G_OBJECT (window), "icon");
2535   
2536   gtk_window_unrealize_icon (window);
2537   
2538   if (GTK_WIDGET_REALIZED (window))
2539     gtk_window_realize_icon (window);
2540
2541   /* We could try to update our transient children, but I don't think
2542    * it's really worth it. If we did it, the best way would probably
2543    * be to have children connect to notify::icon_list
2544    */
2545 }
2546
2547 /**
2548  * gtk_window_get_icon_list:
2549  * @window: a #GtkWindow
2550  * 
2551  * Retrieves the list of icons set by gtk_window_set_icon_list().
2552  * The list is copied, but the reference count on each
2553  * member won't be incremented.
2554  * 
2555  * Return value: copy of window's icon list
2556  **/
2557 GList*
2558 gtk_window_get_icon_list (GtkWindow  *window)
2559 {
2560   GtkWindowIconInfo *info;
2561   
2562   g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
2563
2564   info = get_icon_info (window);
2565
2566   if (info)
2567     return g_list_copy (info->icon_list);
2568   else
2569     return NULL;  
2570 }
2571
2572 /**
2573  * gtk_window_set_icon:
2574  * @window: a #GtkWindow
2575  * @icon: icon image, or %NULL
2576  * 
2577  * Sets up the icon representing a #GtkWindow. This icon is used when
2578  * the window is minimized (also known as iconified).  Some window
2579  * managers or desktop environments may also place it in the window
2580  * frame, or display it in other contexts.
2581  *
2582  * The icon should be provided in whatever size it was naturally
2583  * drawn; that is, don't scale the image before passing it to
2584  * GTK+. Scaling is postponed until the last minute, when the desired
2585  * final size is known, to allow best quality.
2586  *
2587  * If you have your icon hand-drawn in multiple sizes, use
2588  * gtk_window_set_icon_list(). Then the best size will be used.
2589  *
2590  * This function is equivalent to calling gtk_window_set_icon_list()
2591  * with a 1-element list.
2592  *
2593  * See also gtk_window_set_default_icon_list() to set the icon
2594  * for all windows in your application in one go.
2595  **/
2596 void
2597 gtk_window_set_icon (GtkWindow  *window,
2598                      GdkPixbuf  *icon)
2599 {
2600   GList *list;
2601   
2602   g_return_if_fail (GTK_IS_WINDOW (window));
2603   g_return_if_fail (icon == NULL || GDK_IS_PIXBUF (icon));
2604
2605   list = NULL;
2606
2607   if (icon)
2608     list = g_list_append (list, icon);
2609   
2610   gtk_window_set_icon_list (window, list);
2611   g_list_free (list);  
2612 }
2613
2614 /**
2615  * gtk_window_get_icon:
2616  * @window: a #GtkWindow
2617  * 
2618  * Gets the value set by gtk_window_set_icon() (or if you've
2619  * called gtk_window_set_icon_list(), gets the first icon in
2620  * the icon list).
2621  * 
2622  * Return value: icon for window
2623  **/
2624 GdkPixbuf*
2625 gtk_window_get_icon (GtkWindow  *window)
2626 {
2627   GtkWindowIconInfo *info;
2628
2629   g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
2630
2631   info = get_icon_info (window);
2632   if (info && info->icon_list)
2633     return GDK_PIXBUF (info->icon_list->data);
2634   else
2635     return NULL;
2636 }
2637
2638 /* Load pixbuf, printing warning on failure if error == NULL
2639  */
2640 static GdkPixbuf *
2641 load_pixbuf_verbosely (const char *filename,
2642                        GError    **err)
2643 {
2644   GError *local_err = NULL;
2645   GdkPixbuf *pixbuf;
2646
2647   pixbuf = gdk_pixbuf_new_from_file (filename, &local_err);
2648
2649   if (!pixbuf)
2650     {
2651       if (err)
2652         *err = local_err;
2653       else
2654         {
2655           g_warning ("Error loading icon from file '%s':\n\t%s",
2656                      filename, local_err->message);
2657           g_error_free (local_err);
2658         }
2659     }
2660
2661   return pixbuf;
2662 }
2663
2664 /**
2665  * gtk_window_set_icon_from_file:
2666  * @window: a #GtkWindow
2667  * @filename: location of icon file
2668  * @err: location to store error, or %NULL.
2669  *
2670  * Sets the icon for @window.  
2671  * Warns on failure if @err is %NULL.
2672  *
2673  * This function is equivalent to calling gtk_window_set_icon()
2674  * with a pixbuf created by loading the image from @filename.
2675  *
2676  * Returns: %TRUE if setting the icon succeeded.
2677  *
2678  * Since: 2.2
2679  **/
2680 gboolean
2681 gtk_window_set_icon_from_file (GtkWindow   *window,
2682                                const gchar *filename,
2683                                GError     **err)
2684 {
2685   GdkPixbuf *pixbuf = load_pixbuf_verbosely (filename, err);
2686
2687   if (pixbuf)
2688     {
2689       gtk_window_set_icon (window, pixbuf);
2690       g_object_unref (pixbuf);
2691       
2692       return TRUE;
2693     }
2694   else
2695     return FALSE;
2696 }
2697
2698 /**
2699  * gtk_window_set_default_icon_list:
2700  * @list: a list of #GdkPixbuf
2701  *
2702  * Sets an icon list to be used as fallback for windows that haven't
2703  * had gtk_window_set_icon_list() called on them to set up a
2704  * window-specific icon list. This function allows you to set up the
2705  * icon for all windows in your app at once.
2706  *
2707  * See gtk_window_set_icon_list() for more details.
2708  * 
2709  **/
2710 void
2711 gtk_window_set_default_icon_list (GList *list)
2712 {
2713   GList *toplevels;
2714   GList *tmp_list;
2715   if (list == default_icon_list)
2716     return;
2717
2718   /* Update serial so we don't used cached pixmaps/masks
2719    */
2720   default_icon_serial++;
2721   
2722   g_list_foreach (default_icon_list,
2723                   (GFunc) g_object_unref, NULL);
2724
2725   g_list_free (default_icon_list);
2726
2727   default_icon_list = g_list_copy (list);
2728   g_list_foreach (default_icon_list,
2729                   (GFunc) g_object_ref, NULL);
2730   
2731   /* Update all toplevels */
2732   toplevels = gtk_window_list_toplevels ();
2733   tmp_list = toplevels;
2734   while (tmp_list != NULL)
2735     {
2736       GtkWindowIconInfo *info;
2737       GtkWindow *w = tmp_list->data;
2738       
2739       info = get_icon_info (w);
2740       if (info && info->using_default_icon)
2741         {
2742           gtk_window_unrealize_icon (w);
2743           if (GTK_WIDGET_REALIZED (w))
2744             gtk_window_realize_icon (w);
2745         }
2746
2747       tmp_list = tmp_list->next;
2748     }
2749   g_list_free (toplevels);
2750 }
2751
2752 /**
2753  * gtk_window_set_default_icon_from_file:
2754  * @filename: location of icon file
2755  * @err: location to store error, or %NULL.
2756  *
2757  * Sets an icon to be used as fallback for windows that haven't
2758  * had gtk_window_set_icon_list() called on them from a file
2759  * on disk. Warns on failure if @err is %NULL.
2760  *
2761  * Returns: %TRUE if setting the icon succeeded.
2762  *
2763  * Since: 2.2
2764  **/
2765 gboolean
2766 gtk_window_set_default_icon_from_file (const gchar *filename,
2767                                        GError     **err)
2768 {
2769   GdkPixbuf *pixbuf = load_pixbuf_verbosely (filename, err);
2770
2771   if (pixbuf)
2772     {
2773       GList *list = g_list_prepend (NULL, pixbuf);
2774       gtk_window_set_default_icon_list (list);
2775       g_list_free (list);
2776
2777       g_object_unref (pixbuf);
2778       
2779       return TRUE;
2780     }
2781   else
2782     return FALSE;
2783 }
2784
2785 /**
2786  * gtk_window_get_default_icon_list:
2787  * 
2788  * Gets the value set by gtk_window_set_default_icon_list().
2789  * The list is a copy and should be freed with g_list_free(),
2790  * but the pixbufs in the list have not had their reference count
2791  * incremented.
2792  * 
2793  * Return value: copy of default icon list 
2794  **/
2795 GList*
2796 gtk_window_get_default_icon_list (void)
2797 {
2798   return g_list_copy (default_icon_list);
2799 }
2800
2801 static void
2802 gtk_window_set_default_size_internal (GtkWindow    *window,
2803                                       gboolean      change_width,
2804                                       gint          width,
2805                                       gboolean      change_height,
2806                                       gint          height,
2807                                       gboolean      is_geometry)
2808 {
2809   GtkWindowGeometryInfo *info;
2810
2811   g_return_if_fail (change_width == FALSE || width >= -1);
2812   g_return_if_fail (change_height == FALSE || height >= -1);
2813
2814   info = gtk_window_get_geometry_info (window, TRUE);
2815
2816   g_object_freeze_notify (G_OBJECT (window));
2817
2818   info->default_is_geometry = is_geometry != FALSE;
2819
2820   if (change_width)
2821     {
2822       if (width == 0)
2823         width = 1;
2824
2825       if (width < 0)
2826         width = -1;
2827
2828       info->default_width = width;
2829
2830       g_object_notify (G_OBJECT (window), "default_width");
2831     }
2832
2833   if (change_height)
2834     {
2835       if (height == 0)
2836         height = 1;
2837
2838       if (height < 0)
2839         height = -1;
2840
2841       info->default_height = height;
2842       
2843       g_object_notify (G_OBJECT (window), "default_height");
2844     }
2845   
2846   g_object_thaw_notify (G_OBJECT (window));
2847   
2848   gtk_widget_queue_resize (GTK_WIDGET (window));
2849 }
2850
2851 /**
2852  * gtk_window_set_default_size:
2853  * @window: a #GtkWindow
2854  * @width: width in pixels, or -1 to unset the default width
2855  * @height: height in pixels, or -1 to unset the default height
2856  *
2857  * Sets the default size of a window. If the window's "natural" size
2858  * (its size request) is larger than the default, the default will be
2859  * ignored. More generally, if the default size does not obey the
2860  * geometry hints for the window (gtk_window_set_geometry_hints() can
2861  * be used to set these explicitly), the default size will be clamped
2862  * to the nearest permitted size.
2863  * 
2864  * Unlike gtk_widget_set_size_request(), which sets a size request for
2865  * a widget and thus would keep users from shrinking the window, this
2866  * function only sets the initial size, just as if the user had
2867  * resized the window themselves. Users can still shrink the window
2868  * again as they normally would. Setting a default size of -1 means to
2869  * use the "natural" default size (the size request of the window).
2870  *
2871  * For more control over a window's initial size and how resizing works,
2872  * investigate gtk_window_set_geometry_hints().
2873  *
2874  * For some uses, gtk_window_resize() is a more appropriate function.
2875  * gtk_window_resize() changes the current size of the window, rather
2876  * than the size to be used on initial display. gtk_window_resize() always
2877  * affects the window itself, not the geometry widget.
2878  *
2879  * The default size of a window only affects the first time a window is
2880  * shown; if a window is hidden and re-shown, it will remember the size
2881  * it had prior to hiding, rather than using the default size.
2882  *
2883  * Windows can't actually be 0x0 in size, they must be at least 1x1, but
2884  * passing 0 for @width and @height is OK, resulting in a 1x1 default size.
2885  **/
2886 void       
2887 gtk_window_set_default_size (GtkWindow   *window,
2888                              gint         width,
2889                              gint         height)
2890 {
2891   g_return_if_fail (GTK_IS_WINDOW (window));
2892   g_return_if_fail (width >= -1);
2893   g_return_if_fail (height >= -1);
2894
2895   gtk_window_set_default_size_internal (window, TRUE, width, TRUE, height, FALSE);
2896 }
2897
2898 /**
2899  * gtk_window_get_default_size:
2900  * @window: a #GtkWindow
2901  * @width: location to store the default width, or %NULL
2902  * @height: location to store the default height, or %NULL
2903  *
2904  * Gets the default size of the window. A value of -1 for the width or
2905  * height indicates that a default size has not been explicitly set
2906  * for that dimension, so the "natural" size of the window will be
2907  * used.
2908  * 
2909  **/
2910 void
2911 gtk_window_get_default_size (GtkWindow *window,
2912                              gint      *width,
2913                              gint      *height)
2914 {
2915   GtkWindowGeometryInfo *info;
2916
2917   g_return_if_fail (GTK_IS_WINDOW (window));
2918
2919   info = gtk_window_get_geometry_info (window, FALSE);
2920
2921   if (width)
2922     *width = info->default_width;
2923
2924   if (height)
2925     *height = info->default_height;
2926 }
2927
2928 /**
2929  * gtk_window_resize:
2930  * @window: a #GtkWindow
2931  * @width: width in pixels to resize the window to
2932  * @height: height in pixels to resize the window to
2933  *
2934  * Resizes the window as if the user had done so, obeying geometry
2935  * constraints. The default geometry constraint is that windows may
2936  * not be smaller than their size request; to override this
2937  * constraint, call gtk_widget_set_size_request() to set the window's
2938  * request to a smaller value.
2939  *
2940  * If gtk_window_resize() is called before showing a window for the
2941  * first time, it overrides any default size set with
2942  * gtk_window_set_default_size().
2943  *
2944  * Windows may not be resized smaller than 1 by 1 pixels.
2945  * 
2946  **/
2947 void
2948 gtk_window_resize (GtkWindow *window,
2949                    gint       width,
2950                    gint       height)
2951 {
2952   GtkWindowGeometryInfo *info;
2953   
2954   g_return_if_fail (GTK_IS_WINDOW (window));
2955   g_return_if_fail (width > 0);
2956   g_return_if_fail (height > 0);
2957
2958   info = gtk_window_get_geometry_info (window, TRUE);
2959
2960   info->resize_width = width;
2961   info->resize_height = height;
2962
2963   gtk_widget_queue_resize (GTK_WIDGET (window));
2964 }
2965
2966 /**
2967  * gtk_window_get_size:
2968  * @window: a #GtkWindow
2969  * @width: return location for width, or %NULL
2970  * @height: return location for height, or %NULL
2971  *
2972  * Obtains the current size of @window. If @window is not onscreen,
2973  * it returns the size GTK+ will suggest to the <link
2974  * linkend="gtk-X11-arch">window manager</link> for the initial window
2975  * size (but this is not reliably the same as the size the window
2976  * manager will actually select). The size obtained by
2977  * gtk_window_get_size() is the last size received in a
2978  * #GdkEventConfigure, that is, GTK+ uses its locally-stored size,
2979  * rather than querying the X server for the size. As a result, if you
2980  * call gtk_window_resize() then immediately call
2981  * gtk_window_get_size(), the size won't have taken effect yet. After
2982  * the window manager processes the resize request, GTK+ receives
2983  * notification that the size has changed via a configure event, and
2984  * the size of the window gets updated.
2985  *
2986  * Note 1: Nearly any use of this function creates a race condition,
2987  * because the size of the window may change between the time that you
2988  * get the size and the time that you perform some action assuming
2989  * that size is the current size. To avoid race conditions, connect to
2990  * "configure_event" on the window and adjust your size-dependent
2991  * state to match the size delivered in the #GdkEventConfigure.
2992  *
2993  * Note 2: The returned size does <emphasis>not</emphasis> include the
2994  * size of the window manager decorations (aka the window frame or
2995  * border). Those are not drawn by GTK+ and GTK+ has no reliable
2996  * method of determining their size.
2997  *
2998  * Note 3: If you are getting a window size in order to position
2999  * the window onscreen, there may be a better way. The preferred
3000  * way is to simply set the window's semantic type with
3001  * gtk_window_set_type_hint(), which allows the window manager to
3002  * e.g. center dialogs. Also, if you set the transient parent of
3003  * dialogs with gtk_window_set_transient_for() window managers
3004  * will often center the dialog over its parent window. It's
3005  * much preferred to let the window manager handle these
3006  * things rather than doing it yourself, because all apps will
3007  * behave consistently and according to user prefs if the window
3008  * manager handles it. Also, the window manager can take the size
3009  * of the window decorations/border into account, while your
3010  * application cannot.
3011  *
3012  * In any case, if you insist on application-specified window
3013  * positioning, there's <emphasis>still</emphasis> a better way than
3014  * doing it yourself - gtk_window_set_position() will frequently
3015  * handle the details for you.
3016  * 
3017  **/
3018 void
3019 gtk_window_get_size (GtkWindow *window,
3020                      gint      *width,
3021                      gint      *height)
3022 {
3023   gint w, h;
3024   GtkWidget *widget;
3025   
3026   g_return_if_fail (GTK_IS_WINDOW (window));
3027
3028   widget = GTK_WIDGET (window);
3029   
3030   if (width == NULL && height == NULL)
3031     return;
3032
3033   if (GTK_WIDGET_MAPPED (window))
3034     {
3035       gdk_drawable_get_size (GTK_WIDGET (window)->window,
3036                              &w, &h);
3037     }
3038   else
3039     {
3040       GdkRectangle configure_request;
3041
3042       gtk_window_compute_configure_request (window,
3043                                             &configure_request,
3044                                             NULL, NULL);
3045
3046       w = configure_request.width;
3047       h = configure_request.height;
3048     }
3049   
3050   if (width)
3051     *width = w;
3052   if (height)
3053     *height = h;
3054 }
3055
3056 /**
3057  * gtk_window_move:
3058  * @window: a #GtkWindow
3059  * @x: X coordinate to move window to
3060  * @y: Y coordinate to move window to
3061  *
3062  * Asks the <link linkend="gtk-X11-arch">window manager</link> to move
3063  * @window to the given position.  Window managers are free to ignore
3064  * this; most window managers ignore requests for initial window
3065  * positions (instead using a user-defined placement algorithm) and
3066  * honor requests after the window has already been shown.
3067  *
3068  * Note: the position is the position of the gravity-determined
3069  * reference point for the window. The gravity determines two things:
3070  * first, the location of the reference point in root window
3071  * coordinates; and second, which point on the window is positioned at
3072  * the reference point.
3073  *
3074  * By default the gravity is #GDK_GRAVITY_NORTH_WEST, so the reference
3075  * point is simply the @x, @y supplied to gtk_window_move(). The
3076  * top-left corner of the window decorations (aka window frame or
3077  * border) will be placed at @x, @y.  Therefore, to position a window
3078  * at the top left of the screen, you want to use the default gravity
3079  * (which is #GDK_GRAVITY_NORTH_WEST) and move the window to 0,0.
3080  *
3081  * To position a window at the bottom right corner of the screen, you
3082  * would set #GDK_GRAVITY_SOUTH_EAST, which means that the reference
3083  * point is at @x + the window width and @y + the window height, and
3084  * the bottom-right corner of the window border will be placed at that
3085  * reference point. So, to place a window in the bottom right corner
3086  * you would first set gravity to south east, then write:
3087  * <literal>gtk_window_move (window, gdk_screen_width () - window_width,
3088  * gdk_screen_height () - window_height)</literal>.
3089  *
3090  * The extended window manager hints specification at <ulink 
3091  * url="http://www.freedesktop.org/standards/wm-spec.html">
3092  * http://www.freedesktop.org/standards/wm-spec.html</ulink> has a 
3093  * nice table of gravities in the "implementation notes" section.
3094  *
3095  * The gtk_window_get_position() documentation may also be relevant.
3096  * 
3097  **/
3098 void
3099 gtk_window_move (GtkWindow *window,
3100                  gint       x,
3101                  gint       y)
3102 {
3103   GtkWindowGeometryInfo *info;
3104   GtkWidget *widget;
3105   
3106   g_return_if_fail (GTK_IS_WINDOW (window));
3107
3108   widget = GTK_WIDGET (window);
3109
3110   info = gtk_window_get_geometry_info (window, TRUE);  
3111   
3112   if (GTK_WIDGET_MAPPED (window))
3113     {
3114       /* we have now sent a request with this position
3115        * with currently-active constraints, so toggle flag.
3116        */
3117       info->position_constraints_changed = FALSE;
3118
3119       /* we only constrain if mapped - if not mapped,
3120        * then gtk_window_compute_configure_request()
3121        * will apply the constraints later, and we
3122        * don't want to lose information about
3123        * what position the user set before then.
3124        * i.e. if you do a move() then turn off POS_CENTER
3125        * then show the window, your move() will work.
3126        */
3127       gtk_window_constrain_position (window,
3128                                      widget->allocation.width,
3129                                      widget->allocation.height,
3130                                      &x, &y);
3131       
3132       /* Note that this request doesn't go through our standard request
3133        * framework, e.g. doesn't increment configure_request_count,
3134        * doesn't set info->last, etc.; that's because
3135        * we don't save the info needed to arrive at this same request
3136        * again.
3137        *
3138        * To gtk_window_move_resize(), this will end up looking exactly
3139        * the same as the position being changed by the window
3140        * manager.
3141        */
3142       
3143       /* FIXME are we handling gravity properly for framed windows? */
3144       if (window->frame)
3145         gdk_window_move (window->frame,
3146                          x - window->frame_left,
3147                          y - window->frame_top);
3148       else
3149         gdk_window_move (GTK_WIDGET (window)->window,
3150                          x, y);
3151     }
3152   else
3153     {
3154       /* Save this position to apply on mapping */
3155       info->initial_x = x;
3156       info->initial_y = y;
3157       info->initial_pos_set = TRUE;
3158     }
3159 }
3160
3161 /**
3162  * gtk_window_get_position:
3163  * @window: a #GtkWindow
3164  * @root_x: return location for X coordinate of gravity-determined reference p\oint
3165  * @root_y: return location for Y coordinate of gravity-determined reference p\oint
3166  *
3167  * This function returns the position you need to pass to
3168  * gtk_window_move() to keep @window in its current position.  This
3169  * means that the meaning of the returned value varies with window
3170  * gravity. See gtk_window_move() for more details.
3171  * 
3172  * If you haven't changed the window gravity, its gravity will be
3173  * #GDK_GRAVITY_NORTH_WEST. This means that gtk_window_get_position()
3174  * gets the position of the top-left corner of the window manager
3175  * frame for the window. gtk_window_move() sets the position of this
3176  * same top-left corner.
3177  *
3178  * gtk_window_get_position() is not 100% reliable because the X Window System
3179  * does not specify a way to obtain the geometry of the
3180  * decorations placed on a window by the window manager.
3181  * Thus GTK+ is using a "best guess" that works with most
3182  * window managers.
3183  *
3184  * Moreover, nearly all window managers are historically broken with
3185  * respect to their handling of window gravity. So moving a window to
3186  * its current position as returned by gtk_window_get_position() tends
3187  * to result in moving the window slightly. Window managers are
3188  * slowly getting better over time.
3189  *
3190  * If a window has gravity #GDK_GRAVITY_STATIC the window manager
3191  * frame is not relevant, and thus gtk_window_get_position() will
3192  * always produce accurate results. However you can't use static
3193  * gravity to do things like place a window in a corner of the screen,
3194  * because static gravity ignores the window manager decorations.
3195  *
3196  * If you are saving and restoring your application's window
3197  * positions, you should know that it's impossible for applications to
3198  * do this without getting it somewhat wrong because applications do
3199  * not have sufficient knowledge of window manager state. The Correct
3200  * Mechanism is to support the session management protocol (see the
3201  * "GnomeClient" object in the GNOME libraries for example) and allow
3202  * the window manager to save your window sizes and positions.
3203  * 
3204  **/
3205
3206 void
3207 gtk_window_get_position (GtkWindow *window,
3208                          gint      *root_x,
3209                          gint      *root_y)
3210 {
3211   GtkWidget *widget;
3212
3213   g_return_if_fail (GTK_IS_WINDOW (window));
3214
3215   widget = GTK_WIDGET (window);
3216   
3217   if (window->gravity == GDK_GRAVITY_STATIC)
3218     {
3219       if (GTK_WIDGET_MAPPED (widget))
3220         {
3221           /* This does a server round-trip, which is sort of wrong;
3222            * but a server round-trip is inevitable for
3223            * gdk_window_get_frame_extents() in the usual
3224            * NorthWestGravity case below, so not sure what else to
3225            * do. We should likely be consistent about whether we get
3226            * the client-side info or the server-side info.
3227            */
3228           gdk_window_get_origin (widget->window, root_x, root_y);
3229         }
3230       else
3231         {
3232           GdkRectangle configure_request;
3233           
3234           gtk_window_compute_configure_request (window,
3235                                                 &configure_request,
3236                                                 NULL, NULL);
3237           
3238           *root_x = configure_request.x;
3239           *root_y = configure_request.y;
3240         }
3241     }
3242   else
3243     {
3244       GdkRectangle frame_extents;
3245       
3246       gint x, y;
3247       gint w, h;
3248       
3249       if (GTK_WIDGET_MAPPED (widget))
3250         {
3251           if (window->frame)
3252             gdk_window_get_frame_extents (window->frame, &frame_extents);
3253           else
3254             gdk_window_get_frame_extents (widget->window, &frame_extents);
3255           x = frame_extents.x;
3256           y = frame_extents.y;
3257           gtk_window_get_size (window, &w, &h);
3258         }
3259       else
3260         {
3261           /* We just say the frame has 0 size on all sides.
3262            * Not sure what else to do.
3263            */             
3264           gtk_window_compute_configure_request (window,
3265                                                 &frame_extents,
3266                                                 NULL, NULL);
3267           x = frame_extents.x;
3268           y = frame_extents.y;
3269           w = frame_extents.width;
3270           h = frame_extents.height;
3271         }
3272       
3273       switch (window->gravity)
3274         {
3275         case GDK_GRAVITY_NORTH:
3276         case GDK_GRAVITY_CENTER:
3277         case GDK_GRAVITY_SOUTH:
3278           /* Find center of frame. */
3279           x += frame_extents.width / 2;
3280           /* Center client window on that point. */
3281           x -= w / 2;
3282           break;
3283
3284         case GDK_GRAVITY_SOUTH_EAST:
3285         case GDK_GRAVITY_EAST:
3286         case GDK_GRAVITY_NORTH_EAST:
3287           /* Find right edge of frame */
3288           x += frame_extents.width;
3289           /* Align left edge of client at that point. */
3290           x -= w;
3291           break;
3292         default:
3293           break;
3294         }
3295
3296       switch (window->gravity)
3297         {
3298         case GDK_GRAVITY_WEST:
3299         case GDK_GRAVITY_CENTER:
3300         case GDK_GRAVITY_EAST:
3301           /* Find center of frame. */
3302           y += frame_extents.height / 2;
3303           /* Center client window there. */
3304           y -= h / 2;
3305           break;
3306         case GDK_GRAVITY_SOUTH_WEST:
3307         case GDK_GRAVITY_SOUTH:
3308         case GDK_GRAVITY_SOUTH_EAST:
3309           /* Find south edge of frame */
3310           y += frame_extents.height;
3311           /* Place bottom edge of client there */
3312           y -= h;
3313           break;
3314         default:
3315           break;
3316         }
3317       
3318       if (root_x)
3319         *root_x = x;
3320       if (root_y)
3321         *root_y = y;
3322     }
3323 }
3324
3325 /**
3326  * gtk_window_reshow_with_initial_size:
3327  * @window: a #GtkWindow
3328  * 
3329  * Hides @window, then reshows it, resetting the
3330  * default size and position of the window. Used
3331  * by GUI builders only.
3332  **/
3333 void
3334 gtk_window_reshow_with_initial_size (GtkWindow *window)
3335 {
3336   GtkWidget *widget;
3337   
3338   g_return_if_fail (GTK_IS_WINDOW (window));
3339
3340   widget = GTK_WIDGET (window);
3341   
3342   gtk_widget_hide (widget);
3343   gtk_widget_unrealize (widget);
3344   gtk_widget_show (widget);
3345 }
3346
3347 static void
3348 gtk_window_destroy (GtkObject *object)
3349 {
3350   GtkWindow *window = GTK_WINDOW (object);
3351   
3352   if (window->transient_parent)
3353     gtk_window_set_transient_for (window, NULL);
3354
3355   /* frees the icons */
3356   gtk_window_set_icon_list (window, NULL);
3357   
3358   if (window->has_user_ref_count)
3359     {
3360       window->has_user_ref_count = FALSE;
3361       g_object_unref (window);
3362     }
3363
3364   if (window->group)
3365     gtk_window_group_remove_window (window->group, window);
3366
3367    gtk_window_free_key_hash (window);
3368
3369    GTK_OBJECT_CLASS (parent_class)->destroy (object);
3370 }
3371
3372 static gboolean
3373 gtk_window_mnemonic_hash_remove (gpointer       key,
3374                                  gpointer       value,
3375                                  gpointer       user)
3376 {
3377   GtkWindowMnemonic *mnemonic = key;
3378   GtkWindow *window = user;
3379
3380   if (mnemonic->window == window)
3381     {
3382       if (mnemonic->targets)
3383         {
3384           gchar *name = gtk_accelerator_name (mnemonic->keyval, 0);
3385
3386           g_warning ("mnemonic \"%s\" wasn't removed for widget (%p)",
3387                      name, mnemonic->targets->data);
3388           g_free (name);
3389         }
3390       g_slist_free (mnemonic->targets);
3391       g_free (mnemonic);
3392       
3393       return TRUE;
3394     }
3395   return FALSE;
3396 }
3397
3398 static void
3399 gtk_window_private_finalize (GtkWindowPrivate  *priv)
3400 {
3401   
3402   g_free (priv);
3403 }
3404
3405 static void
3406 gtk_window_finalize (GObject *object)
3407 {
3408   GtkWindow *window = GTK_WINDOW (object);
3409
3410   toplevel_list = g_slist_remove (toplevel_list, window);
3411
3412   g_free (window->title);
3413   g_free (window->wmclass_name);
3414   g_free (window->wmclass_class);
3415   g_free (window->wm_role);
3416
3417   g_hash_table_foreach_remove (mnemonic_hash_table,
3418                                gtk_window_mnemonic_hash_remove,
3419                                window);
3420   if (window->geometry_info)
3421     {
3422       if (window->geometry_info->widget)
3423         g_signal_handlers_disconnect_by_func (window->geometry_info->widget,
3424                                               gtk_widget_destroyed,
3425                                               &window->geometry_info->widget);
3426       g_free (window->geometry_info);
3427     }
3428
3429   if (window->keys_changed_handler)
3430     {
3431       gtk_idle_remove (window->keys_changed_handler);
3432       window->keys_changed_handler = 0;
3433     }
3434
3435   G_OBJECT_CLASS (parent_class)->finalize (object);
3436 }
3437
3438 static void
3439 gtk_window_show (GtkWidget *widget)
3440 {
3441   GtkWindow *window = GTK_WINDOW (widget);
3442   GtkContainer *container = GTK_CONTAINER (window);
3443   gboolean need_resize;
3444
3445   GTK_WIDGET_SET_FLAGS (widget, GTK_VISIBLE);
3446   
3447   need_resize = container->need_resize || !GTK_WIDGET_REALIZED (widget);
3448   container->need_resize = FALSE;
3449
3450   if (need_resize)
3451     {
3452       GtkWindowGeometryInfo *info = gtk_window_get_geometry_info (window, TRUE);
3453       GtkAllocation allocation = { 0, 0 };
3454       GdkRectangle configure_request;
3455       GdkGeometry new_geometry;
3456       guint new_flags;
3457       gboolean was_realized;
3458
3459       /* We are going to go ahead and perform this configure request
3460        * and then emulate a configure notify by going ahead and
3461        * doing a size allocate. Sort of a synchronous
3462        * mini-copy of gtk_window_move_resize() here.
3463        */
3464       gtk_window_compute_configure_request (window,
3465                                             &configure_request,
3466                                             &new_geometry,
3467                                             &new_flags);
3468       
3469       /* We update this because we are going to go ahead
3470        * and gdk_window_resize() below, rather than
3471        * queuing it.
3472        */
3473       info->last.configure_request.width = configure_request.width;
3474       info->last.configure_request.height = configure_request.height;
3475       
3476       /* and allocate the window - this is normally done
3477        * in move_resize in response to configure notify
3478        */
3479       allocation.width  = configure_request.width;
3480       allocation.height = configure_request.height;
3481       gtk_widget_size_allocate (widget, &allocation);
3482
3483       /* Then we guarantee we have a realize */
3484       was_realized = FALSE;
3485       if (!GTK_WIDGET_REALIZED (widget))
3486         {
3487           gtk_widget_realize (widget);
3488           was_realized = TRUE;
3489         }
3490
3491       /* Must be done after the windows are realized,
3492        * so that the decorations can be read
3493        */
3494       gtk_decorated_window_calculate_frame_size (window);
3495
3496       /* We only send configure request if we didn't just finish
3497        * creating the window; if we just created the window
3498        * then we created it with widget->allocation anyhow.
3499        */
3500       if (!was_realized)
3501         gdk_window_resize (widget->window,
3502                            configure_request.width,
3503                            configure_request.height);
3504     }
3505   
3506   gtk_container_check_resize (container);
3507
3508   gtk_widget_map (widget);
3509
3510   /* Try to make sure that we have some focused widget
3511    */
3512 #ifdef GDK_WINDOWING_X11
3513   if (!window->focus_widget && !GTK_IS_PLUG (window))
3514 #else
3515   if (!window->focus_widget)
3516 #endif
3517     gtk_window_move_focus (window, GTK_DIR_TAB_FORWARD);
3518   
3519   if (window->modal)
3520     gtk_grab_add (widget);
3521 }
3522
3523 static void
3524 gtk_window_hide (GtkWidget *widget)
3525 {
3526   GtkWindow *window = GTK_WINDOW (widget);
3527
3528   GTK_WIDGET_UNSET_FLAGS (widget, GTK_VISIBLE);
3529   gtk_widget_unmap (widget);
3530
3531   if (window->modal)
3532     gtk_grab_remove (widget);
3533 }
3534
3535 static void
3536 gtk_window_map (GtkWidget *widget)
3537 {
3538   GtkWindow *window = GTK_WINDOW (widget);
3539   GdkWindow *toplevel;
3540   GtkWindowPrivate *priv;
3541
3542   priv = gtk_window_get_private (window);
3543   
3544   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
3545
3546   if (window->bin.child &&
3547       GTK_WIDGET_VISIBLE (window->bin.child) &&
3548       !GTK_WIDGET_MAPPED (window->bin.child))
3549     gtk_widget_map (window->bin.child);
3550
3551   if (window->frame)
3552     toplevel = window->frame;
3553   else
3554     toplevel = widget->window;
3555   
3556   if (window->maximize_initially)
3557     gdk_window_maximize (toplevel);
3558   else
3559     gdk_window_unmaximize (toplevel);
3560   
3561   if (window->stick_initially)
3562     gdk_window_stick (toplevel);
3563   else
3564     gdk_window_unstick (toplevel);
3565   
3566   if (window->iconify_initially)
3567     gdk_window_iconify (toplevel);
3568   else
3569     gdk_window_deiconify (toplevel);
3570
3571   if (priv->fullscreen_initially)
3572     gdk_window_fullscreen (toplevel);
3573   else
3574     gdk_window_unfullscreen (toplevel);
3575   
3576   /* No longer use the default settings */
3577   window->need_default_size = FALSE;
3578   window->need_default_position = FALSE;
3579   
3580   gdk_window_show (widget->window);
3581
3582   if (window->frame)
3583     gdk_window_show (window->frame);
3584
3585   if (!disable_startup_notification &&
3586       !sent_startup_notification)
3587     {
3588       sent_startup_notification = TRUE;
3589       gdk_notify_startup_complete ();
3590     }
3591 }
3592
3593 static void
3594 gtk_window_unmap (GtkWidget *widget)
3595 {
3596   GtkWindow *window = GTK_WINDOW (widget);
3597   GtkWindowGeometryInfo *info;    
3598   GdkWindowState state;
3599
3600   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
3601   if (window->frame)
3602     gdk_window_withdraw (window->frame);
3603   else 
3604     gdk_window_withdraw (widget->window);
3605   
3606   window->configure_request_count = 0;
3607   window->configure_notify_received = FALSE;
3608
3609   /* on unmap, we reset the default positioning of the window,
3610    * so it's placed again, but we don't reset the default
3611    * size of the window, so it's remembered.
3612    */
3613   window->need_default_position = TRUE;
3614
3615   info = gtk_window_get_geometry_info (window, FALSE);
3616   if (info)
3617     {
3618       info->initial_pos_set = FALSE;
3619       info->position_constraints_changed = FALSE;
3620     }
3621
3622   state = gdk_window_get_state (widget->window);
3623   window->iconify_initially = state & GDK_WINDOW_STATE_ICONIFIED;
3624   window->maximize_initially = state & GDK_WINDOW_STATE_MAXIMIZED;
3625   window->stick_initially = state & GDK_WINDOW_STATE_STICKY;
3626 }
3627
3628 static void
3629 gtk_window_realize (GtkWidget *widget)
3630 {
3631   GtkWindow *window;
3632   GdkWindow *parent_window;
3633   GdkWindowAttr attributes;
3634   gint attributes_mask;
3635   
3636   window = GTK_WINDOW (widget);
3637
3638   /* ensure widget tree is properly size allocated */
3639   if (widget->allocation.x == -1 &&
3640       widget->allocation.y == -1 &&
3641       widget->allocation.width == 1 &&
3642       widget->allocation.height == 1)
3643     {
3644       GtkRequisition requisition;
3645       GtkAllocation allocation = { 0, 0, 200, 200 };
3646
3647       gtk_widget_size_request (widget, &requisition);
3648       if (requisition.width || requisition.height)
3649         {
3650           /* non-empty window */
3651           allocation.width = requisition.width;
3652           allocation.height = requisition.height;
3653         }
3654       gtk_widget_size_allocate (widget, &allocation);
3655       
3656       _gtk_container_queue_resize (GTK_CONTAINER (widget));
3657
3658       g_return_if_fail (!GTK_WIDGET_REALIZED (widget));
3659     }
3660   
3661   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
3662   
3663   switch (window->type)
3664     {
3665     case GTK_WINDOW_TOPLEVEL:
3666       attributes.window_type = GDK_WINDOW_TOPLEVEL;
3667       break;
3668     case GTK_WINDOW_POPUP:
3669       attributes.window_type = GDK_WINDOW_TEMP;
3670       break;
3671     default:
3672       g_warning (G_STRLOC": Unknown window type %d!", window->type);
3673       break;
3674     }
3675    
3676   attributes.title = window->title;
3677   attributes.wmclass_name = window->wmclass_name;
3678   attributes.wmclass_class = window->wmclass_class;
3679   attributes.wclass = GDK_INPUT_OUTPUT;
3680   attributes.visual = gtk_widget_get_visual (widget);
3681   attributes.colormap = gtk_widget_get_colormap (widget);
3682
3683   if (window->has_frame)
3684     {
3685       attributes.width = widget->allocation.width + window->frame_left + window->frame_right;
3686       attributes.height = widget->allocation.height + window->frame_top + window->frame_bottom;
3687       attributes.event_mask = (GDK_EXPOSURE_MASK |
3688                                GDK_KEY_PRESS_MASK |
3689                                GDK_ENTER_NOTIFY_MASK |
3690                                GDK_LEAVE_NOTIFY_MASK |
3691                                GDK_FOCUS_CHANGE_MASK |
3692                                GDK_STRUCTURE_MASK |
3693                                GDK_BUTTON_MOTION_MASK |
3694                                GDK_POINTER_MOTION_HINT_MASK |
3695                                GDK_BUTTON_PRESS_MASK |
3696                                GDK_BUTTON_RELEASE_MASK);
3697       
3698       attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP;
3699       
3700       window->frame = gdk_window_new (gtk_widget_get_root_window (widget),
3701                                       &attributes, attributes_mask);
3702                                                  
3703       gdk_window_set_user_data (window->frame, widget);
3704       
3705       attributes.window_type = GDK_WINDOW_CHILD;
3706       attributes.x = window->frame_left;
3707       attributes.y = window->frame_top;
3708     
3709       attributes_mask = GDK_WA_X | GDK_WA_Y;
3710
3711       parent_window = window->frame;
3712     }
3713   else
3714     {
3715       attributes_mask = 0;
3716       parent_window = gtk_widget_get_root_window (widget);
3717     }
3718   
3719   attributes.width = widget->allocation.width;
3720   attributes.height = widget->allocation.height;
3721   attributes.event_mask = gtk_widget_get_events (widget);
3722   attributes.event_mask |= (GDK_EXPOSURE_MASK |
3723                             GDK_KEY_PRESS_MASK |
3724                             GDK_KEY_RELEASE_MASK |
3725                             GDK_ENTER_NOTIFY_MASK |
3726                             GDK_LEAVE_NOTIFY_MASK |
3727                             GDK_FOCUS_CHANGE_MASK |
3728                             GDK_STRUCTURE_MASK);
3729
3730   attributes_mask |= GDK_WA_VISUAL | GDK_WA_COLORMAP;
3731   attributes_mask |= (window->title ? GDK_WA_TITLE : 0);
3732   attributes_mask |= (window->wmclass_name ? GDK_WA_WMCLASS : 0);
3733   
3734   widget->window = gdk_window_new (parent_window, &attributes, attributes_mask);
3735     
3736   gdk_window_set_user_data (widget->window, window);
3737       
3738   widget->style = gtk_style_attach (widget->style, widget->window);
3739   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
3740   if (window->frame)
3741     gtk_style_set_background (widget->style, window->frame, GTK_STATE_NORMAL);
3742
3743   /* This is a bad hack to set the window background. */
3744   gtk_window_paint (widget, NULL);
3745   
3746   if (window->transient_parent &&
3747       GTK_WIDGET_REALIZED (window->transient_parent))
3748     gdk_window_set_transient_for (widget->window,
3749                                   GTK_WIDGET (window->transient_parent)->window);
3750
3751   if (window->wm_role)
3752     gdk_window_set_role (widget->window, window->wm_role);
3753   
3754   if (!window->decorated)
3755     gdk_window_set_decorations (widget->window, 0);
3756
3757   gdk_window_set_type_hint (widget->window, window->type_hint);
3758
3759   if (gtk_window_get_skip_pager_hint (window))
3760     gdk_window_set_skip_pager_hint (widget->window, TRUE);
3761
3762   if (gtk_window_get_skip_taskbar_hint (window))
3763     gdk_window_set_skip_taskbar_hint (widget->window, TRUE);
3764   
3765   /* transient_for must be set to allow the modal hint */
3766   if (window->transient_parent && window->modal)
3767     gdk_window_set_modal_hint (widget->window, TRUE);
3768   else
3769     gdk_window_set_modal_hint (widget->window, FALSE);
3770
3771   /* Icons */
3772   gtk_window_realize_icon (window);
3773 }
3774
3775 static void
3776 gtk_window_unrealize (GtkWidget *widget)
3777 {
3778   GtkWindow *window;
3779   GtkWindowGeometryInfo *info;
3780
3781   window = GTK_WINDOW (widget);
3782
3783   /* On unrealize, we reset the size of the window such
3784    * that we will re-apply the default sizing stuff
3785    * next time we show the window.
3786    *
3787    * Default positioning is reset on unmap, instead of unrealize.
3788    */
3789   window->need_default_size = TRUE;
3790   info = gtk_window_get_geometry_info (window, FALSE);
3791   if (info)
3792     {
3793       info->resize_width = -1;
3794       info->resize_height = -1;
3795       info->last.configure_request.x = 0;
3796       info->last.configure_request.y = 0;
3797       info->last.configure_request.width = -1;
3798       info->last.configure_request.height = -1;
3799       /* be sure we reset geom hints on re-realize */
3800       info->last.flags = 0;
3801     }
3802   
3803   if (window->frame)
3804     {
3805       gdk_window_set_user_data (window->frame, NULL);
3806       gdk_window_destroy (window->frame);
3807       window->frame = NULL;
3808     }
3809
3810   /* Icons */
3811   gtk_window_unrealize_icon (window);
3812   
3813   (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
3814 }
3815
3816 static void
3817 gtk_window_size_request (GtkWidget      *widget,
3818                          GtkRequisition *requisition)
3819 {
3820   GtkWindow *window;
3821   GtkBin *bin;
3822
3823   window = GTK_WINDOW (widget);
3824   bin = GTK_BIN (window);
3825   
3826   requisition->width = GTK_CONTAINER (window)->border_width * 2;
3827   requisition->height = GTK_CONTAINER (window)->border_width * 2;
3828
3829   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
3830     {
3831       GtkRequisition child_requisition;
3832       
3833       gtk_widget_size_request (bin->child, &child_requisition);
3834
3835       requisition->width += child_requisition.width;
3836       requisition->height += child_requisition.height;
3837     }
3838 }
3839
3840 static void
3841 gtk_window_size_allocate (GtkWidget     *widget,
3842                           GtkAllocation *allocation)
3843 {
3844   GtkWindow *window;
3845   GtkAllocation child_allocation;
3846
3847   window = GTK_WINDOW (widget);
3848   widget->allocation = *allocation;
3849
3850   if (window->bin.child && GTK_WIDGET_VISIBLE (window->bin.child))
3851     {
3852       child_allocation.x = GTK_CONTAINER (window)->border_width;
3853       child_allocation.y = GTK_CONTAINER (window)->border_width;
3854       child_allocation.width =
3855         MAX (1, (gint)allocation->width - child_allocation.x * 2);
3856       child_allocation.height =
3857         MAX (1, (gint)allocation->height - child_allocation.y * 2);
3858
3859       gtk_widget_size_allocate (window->bin.child, &child_allocation);
3860     }
3861
3862   if (GTK_WIDGET_REALIZED (widget) && window->frame)
3863     {
3864       gdk_window_resize (window->frame,
3865                          allocation->width + window->frame_left + window->frame_right,
3866                          allocation->height + window->frame_top + window->frame_bottom);
3867     }
3868 }
3869
3870 static gint
3871 gtk_window_event (GtkWidget *widget, GdkEvent *event)
3872 {
3873   GtkWindow *window;
3874   gboolean return_val;
3875
3876   window = GTK_WINDOW (widget);
3877
3878   if (window->frame && (event->any.window == window->frame))
3879     {
3880       if ((event->type != GDK_KEY_PRESS) &&
3881           (event->type != GDK_KEY_RELEASE) &&
3882           (event->type != GDK_FOCUS_CHANGE))
3883         {
3884           g_signal_stop_emission_by_name (widget, "event");
3885           return_val = FALSE;
3886           g_signal_emit (widget, window_signals[FRAME_EVENT], 0, event, &return_val);
3887           return TRUE;
3888         }
3889       else
3890         {
3891           g_object_unref (event->any.window);
3892           event->any.window = g_object_ref (widget->window);
3893         }
3894     }
3895
3896   return FALSE;
3897 }
3898
3899 static gboolean
3900 gtk_window_frame_event (GtkWindow *window, GdkEvent *event)
3901 {
3902   GdkEventConfigure *configure_event;
3903   GdkRectangle rect;
3904
3905   switch (event->type)
3906     {
3907     case GDK_CONFIGURE:
3908       configure_event = (GdkEventConfigure *)event;
3909       
3910       /* Invalidate the decorations */
3911       rect.x = 0;
3912       rect.y = 0;
3913       rect.width = configure_event->width;
3914       rect.height = configure_event->height;
3915       
3916       gdk_window_invalidate_rect (window->frame, &rect, FALSE);
3917
3918       /* Pass on the (modified) configure event */
3919       configure_event->width -= window->frame_left + window->frame_right;
3920       configure_event->height -= window->frame_top + window->frame_bottom;
3921       return gtk_window_configure_event (GTK_WIDGET (window), configure_event);
3922       break;
3923     default:
3924       break;
3925     }
3926   return FALSE;
3927 }
3928
3929 static gint
3930 gtk_window_configure_event (GtkWidget         *widget,
3931                             GdkEventConfigure *event)
3932 {
3933   GtkWindow *window = GTK_WINDOW (widget);
3934   gboolean expected_reply = window->configure_request_count > 0;
3935
3936   /* window->configure_request_count incremented for each 
3937    * configure request, and decremented to a min of 0 for
3938    * each configure notify.
3939    *
3940    * All it means is that we know we will get at least
3941    * window->configure_request_count more configure notifies.
3942    * We could get more configure notifies than that; some
3943    * of the configure notifies we get may be unrelated to
3944    * the configure requests. But we will get at least
3945    * window->configure_request_count notifies.
3946    */
3947
3948   if (window->configure_request_count > 0)
3949     window->configure_request_count -= 1;
3950   
3951   /* As an optimization, we avoid a resize when possible.
3952    *
3953    * The only times we can avoid a resize are:
3954    *   - we know only the position changed, not the size
3955    *   - we know we have made more requests and so will get more
3956    *     notifies and can wait to resize when we get them
3957    */
3958   
3959   if (!expected_reply &&
3960       (widget->allocation.width == event->width &&
3961        widget->allocation.height == event->height))
3962     return TRUE;
3963
3964   /*
3965    * If we do need to resize, we do that by:
3966    *   - filling in widget->allocation with the new size
3967    *   - setting configure_notify_received to TRUE
3968    *     for use in gtk_window_move_resize()
3969    *   - queueing a resize, leading to invocation of
3970    *     gtk_window_move_resize() in an idle handler
3971    *
3972    */
3973   
3974   window->configure_notify_received = TRUE;
3975   
3976   widget->allocation.width = event->width;
3977   widget->allocation.height = event->height;
3978   
3979   _gtk_container_queue_resize (GTK_CONTAINER (widget));
3980   
3981   return TRUE;
3982 }
3983
3984 /* the accel_key and accel_mods fields of the key have to be setup
3985  * upon calling this function. it'll then return whether that key
3986  * is at all used as accelerator, and if so will OR in the
3987  * accel_flags member of the key.
3988  */
3989 gboolean
3990 _gtk_window_query_nonaccels (GtkWindow      *window,
3991                              guint           accel_key,
3992                              GdkModifierType accel_mods)
3993 {
3994   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
3995
3996   /* movement keys are considered locked accels */
3997   if (!accel_mods)
3998     {
3999       static const guint bindings[] = {
4000         GDK_space, GDK_KP_Space, GDK_Return, GDK_KP_Enter, GDK_Up, GDK_KP_Up, GDK_Down, GDK_KP_Down,
4001         GDK_Left, GDK_KP_Left, GDK_Right, GDK_KP_Right, GDK_Tab, GDK_KP_Tab, GDK_ISO_Left_Tab,
4002       };
4003       guint i;
4004       
4005       for (i = 0; i < G_N_ELEMENTS (bindings); i++)
4006         if (bindings[i] == accel_key)
4007           return TRUE;
4008     }
4009
4010   /* mnemonics are considered locked accels */
4011   if (accel_mods == window->mnemonic_modifier)
4012     {
4013       GtkWindowMnemonic mkey;
4014
4015       mkey.window = window;
4016       mkey.keyval = accel_key;
4017       if (g_hash_table_lookup (mnemonic_hash_table, &mkey))
4018         return TRUE;
4019     }
4020
4021   return FALSE;
4022 }
4023
4024 static gint
4025 gtk_window_key_press_event (GtkWidget   *widget,
4026                             GdkEventKey *event)
4027 {
4028   GtkWindow *window;
4029   GtkWidget *focus;
4030   gboolean handled;
4031
4032   window = GTK_WINDOW (widget);
4033
4034   handled = FALSE;
4035
4036   /* Check for mnemonics and accelerators
4037    */
4038   if (!handled)
4039     handled = _gtk_window_activate_key (window, event);
4040
4041   if (!handled)
4042     {
4043       focus = window->focus_widget;
4044       if (focus)
4045         g_object_ref (focus);
4046       
4047       while (!handled &&
4048              focus && focus != widget &&
4049              gtk_widget_get_toplevel (focus) == widget)
4050         {
4051           GtkWidget *parent;
4052           
4053           if (GTK_WIDGET_IS_SENSITIVE (focus))
4054             handled = gtk_widget_event (focus, (GdkEvent*) event);
4055           
4056           parent = focus->parent;
4057           if (parent)
4058             g_object_ref (parent);
4059           
4060           g_object_unref (focus);
4061           
4062           focus = parent;
4063         }
4064
4065       if (focus)
4066         g_object_unref (focus);
4067     }
4068
4069   /* Chain up, invokes binding set */
4070   if (!handled && GTK_WIDGET_CLASS (parent_class)->key_press_event)
4071     handled = GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
4072
4073   return handled;
4074 }
4075
4076 static gint
4077 gtk_window_key_release_event (GtkWidget   *widget,
4078                               GdkEventKey *event)
4079 {
4080   GtkWindow *window;
4081   gint handled;
4082   
4083   window = GTK_WINDOW (widget);
4084   handled = FALSE;
4085   if (window->focus_widget &&
4086       window->focus_widget != widget &&
4087       GTK_WIDGET_SENSITIVE (window->focus_widget))
4088     {
4089       handled = gtk_widget_event (window->focus_widget, (GdkEvent*) event);
4090     }
4091
4092   if (!handled && GTK_WIDGET_CLASS (parent_class)->key_release_event)
4093     handled = GTK_WIDGET_CLASS (parent_class)->key_release_event (widget, event);
4094
4095   return handled;
4096 }
4097
4098 static void
4099 gtk_window_real_activate_default (GtkWindow *window)
4100 {
4101   gtk_window_activate_default (window);
4102 }
4103
4104 static void
4105 gtk_window_real_activate_focus (GtkWindow *window)
4106 {
4107   gtk_window_activate_focus (window);
4108 }
4109
4110 static void
4111 gtk_window_move_focus (GtkWindow       *window,
4112                        GtkDirectionType dir)
4113 {
4114   gtk_widget_child_focus (GTK_WIDGET (window), dir);
4115   
4116   if (!GTK_CONTAINER (window)->focus_child)
4117     gtk_window_set_focus (window, NULL);
4118 }
4119
4120 static gint
4121 gtk_window_enter_notify_event (GtkWidget        *widget,
4122                                GdkEventCrossing *event)
4123 {
4124   return FALSE;
4125 }
4126
4127 static gint
4128 gtk_window_leave_notify_event (GtkWidget        *widget,
4129                                GdkEventCrossing *event)
4130 {
4131   return FALSE;
4132 }
4133
4134 static void
4135 do_focus_change (GtkWidget *widget,
4136                  gboolean   in)
4137 {
4138   GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
4139   
4140   g_object_ref (widget);
4141   
4142   if (in)
4143     GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
4144   else
4145     GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
4146   
4147   fevent->focus_change.type = GDK_FOCUS_CHANGE;
4148   fevent->focus_change.window = widget->window;
4149   if (widget->window)
4150     g_object_ref (widget->window);
4151   fevent->focus_change.in = in;
4152   
4153   gtk_widget_event (widget, fevent);
4154   
4155   g_object_notify (G_OBJECT (widget), "has_focus");
4156
4157   g_object_unref (widget);
4158   gdk_event_free (fevent);
4159 }
4160
4161 static gint
4162 gtk_window_focus_in_event (GtkWidget     *widget,
4163                            GdkEventFocus *event)
4164 {
4165   GtkWindow *window = GTK_WINDOW (widget);
4166
4167   /* It appears spurious focus in events can occur when
4168    *  the window is hidden. So we'll just check to see if
4169    *  the window is visible before actually handling the
4170    *  event
4171    */
4172   if (GTK_WIDGET_VISIBLE (widget))
4173     {
4174       _gtk_window_set_has_toplevel_focus (window, TRUE);
4175       _gtk_window_set_is_active (window, TRUE);
4176     }
4177       
4178   return FALSE;
4179 }
4180
4181 static gint
4182 gtk_window_focus_out_event (GtkWidget     *widget,
4183                             GdkEventFocus *event)
4184 {
4185   GtkWindow *window = GTK_WINDOW (widget);
4186
4187   _gtk_window_set_has_toplevel_focus (window, FALSE);
4188   _gtk_window_set_is_active (window, FALSE);
4189
4190   return FALSE;
4191 }
4192
4193 static GdkAtom atom_rcfiles = GDK_NONE;
4194
4195 static void
4196 gtk_window_read_rcfiles (GtkWidget *widget,
4197                          GdkEventClient *event)
4198 {
4199   GList *embedded_windows;
4200
4201   embedded_windows = g_object_get_data (G_OBJECT (widget), "gtk-embedded");
4202   if (embedded_windows)
4203     {
4204       GdkEvent *send_event = gdk_event_new (GDK_CLIENT_EVENT);
4205       int i;
4206       
4207       for (i = 0; i < 5; i++)
4208         send_event->client.data.l[i] = 0;
4209       send_event->client.data_format = 32;
4210       send_event->client.message_type = atom_rcfiles;
4211       
4212       while (embedded_windows)
4213         {
4214           guint xid = GPOINTER_TO_UINT (embedded_windows->data);
4215           gdk_event_send_client_message_for_display (gtk_widget_get_display (widget), send_event, xid);
4216           embedded_windows = embedded_windows->next;
4217         }
4218
4219       gdk_event_free (send_event);
4220     }
4221
4222   gtk_rc_reparse_all_for_settings (gtk_widget_get_settings (widget), FALSE);
4223 }
4224
4225 static gint
4226 gtk_window_client_event (GtkWidget      *widget,
4227                          GdkEventClient *event)
4228 {
4229   if (!atom_rcfiles)
4230     atom_rcfiles = gdk_atom_intern ("_GTK_READ_RCFILES", FALSE);
4231
4232   if (event->message_type == atom_rcfiles) 
4233     gtk_window_read_rcfiles (widget, event);    
4234
4235   return FALSE;
4236 }
4237
4238 static void
4239 gtk_window_check_resize (GtkContainer *container)
4240 {
4241   GtkWindow *window = GTK_WINDOW (container);
4242
4243   if (GTK_WIDGET_VISIBLE (container))
4244     gtk_window_move_resize (window);
4245 }
4246
4247 static gboolean
4248 gtk_window_focus (GtkWidget        *widget,
4249                   GtkDirectionType  direction)
4250 {
4251   GtkBin *bin;
4252   GtkWindow *window;
4253   GtkContainer *container;
4254   GtkWidget *old_focus_child;
4255   GtkWidget *parent;
4256
4257   container = GTK_CONTAINER (widget);
4258   window = GTK_WINDOW (widget);
4259   bin = GTK_BIN (widget);
4260
4261   old_focus_child = container->focus_child;
4262   
4263   /* We need a special implementation here to deal properly with wrapping
4264    * around in the tab chain without the danger of going into an
4265    * infinite loop.
4266    */
4267   if (old_focus_child)
4268     {
4269       if (gtk_widget_child_focus (old_focus_child, direction))
4270         return TRUE;
4271     }
4272
4273   if (window->focus_widget)
4274     {
4275       /* Wrapped off the end, clear the focus setting for the toplpevel */
4276       parent = window->focus_widget->parent;
4277       while (parent)
4278         {
4279           gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
4280           parent = GTK_WIDGET (parent)->parent;
4281         }
4282       
4283       gtk_window_set_focus (GTK_WINDOW (container), NULL);
4284     }
4285
4286   /* Now try to focus the first widget in the window */
4287   if (bin->child)
4288     {
4289       if (gtk_widget_child_focus (bin->child, direction))
4290         return TRUE;
4291     }
4292
4293   return FALSE;
4294 }
4295
4296 static void
4297 gtk_window_real_set_focus (GtkWindow *window,
4298                            GtkWidget *focus)
4299 {
4300   GtkWidget *old_focus = window->focus_widget;
4301   gboolean def_flags = 0;
4302
4303   if (old_focus)
4304     {
4305       g_object_ref (old_focus);
4306       g_object_freeze_notify (G_OBJECT (old_focus));
4307     }
4308   if (focus)
4309     {
4310       g_object_ref (focus);
4311       g_object_freeze_notify (G_OBJECT (focus));
4312     }
4313   
4314   if (window->default_widget)
4315     def_flags = GTK_WIDGET_HAS_DEFAULT (window->default_widget);
4316   
4317   if (window->focus_widget)
4318     {
4319       if (GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget) &&
4320           (window->focus_widget != window->default_widget))
4321         {
4322           GTK_WIDGET_UNSET_FLAGS (window->focus_widget, GTK_HAS_DEFAULT);
4323
4324           if (window->default_widget)
4325             GTK_WIDGET_SET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
4326         }
4327
4328       if (window->has_focus)
4329         do_focus_change (window->focus_widget, FALSE);
4330
4331       g_object_notify (G_OBJECT (window->focus_widget), "is_focus");
4332     }
4333   
4334   window->focus_widget = focus;
4335   
4336   if (window->focus_widget)
4337     {
4338       if (GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget) &&
4339           (window->focus_widget != window->default_widget))
4340         {
4341           if (GTK_WIDGET_CAN_DEFAULT (window->focus_widget))
4342             GTK_WIDGET_SET_FLAGS (window->focus_widget, GTK_HAS_DEFAULT);
4343
4344           if (window->default_widget)
4345             GTK_WIDGET_UNSET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
4346         }
4347
4348       if (window->has_focus)
4349         do_focus_change (window->focus_widget, TRUE);
4350
4351       g_object_notify (G_OBJECT (window->focus_widget), "is_focus");
4352     }
4353   
4354   if (window->default_widget &&
4355       (def_flags != GTK_WIDGET_FLAGS (window->default_widget)))
4356     gtk_widget_queue_draw (window->default_widget);
4357
4358   if (old_focus)
4359     {
4360       g_object_thaw_notify (G_OBJECT (old_focus));
4361       g_object_unref (old_focus);
4362     }
4363   if (focus)
4364     {
4365       g_object_thaw_notify (G_OBJECT (focus));
4366       g_object_unref (focus);
4367     }
4368 }
4369
4370 /**
4371  * _gtk_window_unset_focus_and_default:
4372  * @window: a #GtkWindow
4373  * @widget: a widget inside of @window
4374  * 
4375  * Checks whether the focus and default widgets of @window are
4376  * @widget or a descendent of @widget, and if so, unset them.
4377  **/
4378 void
4379 _gtk_window_unset_focus_and_default (GtkWindow *window,
4380                                      GtkWidget *widget)
4381
4382 {
4383   GtkWidget *child;
4384       
4385   if (GTK_CONTAINER (widget->parent)->focus_child == widget)
4386     {
4387       child = window->focus_widget;
4388       
4389       while (child && child != widget)
4390         child = child->parent;
4391   
4392       if (child == widget)
4393         gtk_window_set_focus (GTK_WINDOW (window), NULL);
4394     }
4395       
4396   child = window->default_widget;
4397       
4398   while (child && child != widget)
4399     child = child->parent;
4400       
4401   if (child == widget)
4402     gtk_window_set_default (window, NULL);
4403 }
4404
4405 /*********************************
4406  * Functions related to resizing *
4407  *********************************/
4408
4409 /* This function doesn't constrain to geometry hints */
4410 static void 
4411 gtk_window_compute_configure_request_size (GtkWindow *window,
4412                                            guint     *width,
4413                                            guint     *height)
4414 {
4415   GtkRequisition requisition;
4416   GtkWindowGeometryInfo *info;
4417   GtkWidget *widget;
4418
4419   /* Preconditions:
4420    *  - we've done a size request
4421    */
4422   
4423   widget = GTK_WIDGET (window);
4424
4425   info = gtk_window_get_geometry_info (window, FALSE);
4426   
4427   if (window->need_default_size)
4428     {
4429       gtk_widget_get_child_requisition (widget, &requisition);
4430
4431       /* Default to requisition */
4432       *width = requisition.width;
4433       *height = requisition.height;
4434
4435       /* If window is empty so requests 0, default to random nonzero size */
4436        if (*width == 0 && *height == 0)
4437          {
4438            *width = 200;
4439            *height = 200;
4440          }
4441
4442        /* Override requisition with default size */
4443
4444        if (info)
4445          {
4446            gint base_width = 0;
4447            gint base_height = 0;
4448            gint width_inc = 1;
4449            gint height_inc = 1;
4450            
4451            if (info->default_is_geometry &&
4452                (info->default_width > 0 || info->default_height > 0))
4453              {
4454                GdkGeometry geometry;
4455                guint flags;
4456                
4457                gtk_window_compute_hints (window, &geometry, &flags);
4458
4459                if (flags & GDK_HINT_BASE_SIZE)
4460                  {
4461                    base_width = geometry.base_width;
4462                    base_height = geometry.base_height;
4463                  }
4464                else if (flags & GDK_HINT_MIN_SIZE)
4465                  {
4466                    base_width = geometry.min_width;
4467                    base_height = geometry.min_height;
4468                  }
4469                if (flags & GDK_HINT_RESIZE_INC)
4470                  {
4471                    width_inc = geometry.width_inc;
4472                    height_inc = geometry.height_inc;
4473                  }
4474              }
4475              
4476            if (info->default_width > 0)
4477              *width = info->default_width * width_inc + base_width;
4478            
4479            if (info->default_height > 0)
4480              *height = info->default_height * height_inc + base_height;
4481          }
4482     }
4483   else
4484     {
4485       /* Default to keeping current size */
4486       *width = widget->allocation.width;
4487       *height = widget->allocation.height;
4488     }
4489
4490   /* Override any size with gtk_window_resize() values */
4491   if (info)
4492     {
4493       if (info->resize_width > 0)
4494         *width = info->resize_width;
4495
4496       if (info->resize_height > 0)
4497         *height = info->resize_height;
4498     }
4499 }
4500
4501 static GtkWindowPosition
4502 get_effective_position (GtkWindow *window)
4503 {
4504   GtkWindowPosition pos = window->position;
4505   if (pos == GTK_WIN_POS_CENTER_ON_PARENT &&
4506       (window->transient_parent == NULL ||
4507        !GTK_WIDGET_MAPPED (window->transient_parent)))
4508     pos = GTK_WIN_POS_NONE;
4509
4510   return pos;
4511 }
4512
4513 static int
4514 get_center_monitor_of_window (GtkWindow *window)
4515 {
4516   /* We could try to sort out the relative positions of the monitors and
4517    * stuff, or we could just be losers and assume you have a row
4518    * or column of monitors.
4519    */
4520   return gdk_screen_get_n_monitors (gtk_window_check_screen (window)) / 2;
4521 }
4522
4523 static int
4524 get_monitor_containing_pointer (GtkWindow *window)
4525 {
4526   gint px, py;
4527   gint monitor_num;
4528   GdkScreen *window_screen;
4529   GdkScreen *pointer_screen;
4530
4531   window_screen = gtk_window_check_screen (window);
4532   gdk_display_get_pointer (gdk_screen_get_display (window_screen),
4533                            &pointer_screen,
4534                            &px, &py, NULL);
4535
4536   if (pointer_screen == window_screen)
4537     monitor_num = gdk_screen_get_monitor_at_point (pointer_screen, px, py);
4538   else
4539     monitor_num = -1;
4540
4541   return monitor_num;
4542 }
4543
4544 static void
4545 center_window_on_monitor (GtkWindow *window,
4546                           gint       w,
4547                           gint       h,
4548                           gint      *x,
4549                           gint      *y)
4550 {
4551   GdkRectangle monitor;
4552   int monitor_num;
4553
4554   monitor_num = get_monitor_containing_pointer (window);
4555   
4556   if (monitor_num == -1)
4557     monitor_num = get_center_monitor_of_window (window);
4558
4559   gdk_screen_get_monitor_geometry (gtk_window_check_screen (window),
4560                                    monitor_num, &monitor);
4561   
4562   *x = (monitor.width - w) / 2 + monitor.x;
4563   *y = (monitor.height - h) / 2 + monitor.y;
4564
4565   /* Be sure we aren't off the monitor, ignoring _NET_WM_STRUT
4566    * and WM decorations.
4567    */
4568   if (*x < monitor.x)
4569     *x = monitor.x;
4570   if (*y < monitor.y)
4571     *y = monitor.y;
4572 }
4573
4574 static void
4575 clamp_window_to_rectangle (gint               *x,
4576                            gint               *y,
4577                            gint                w,
4578                            gint                h,
4579                            const GdkRectangle *rect)
4580 {
4581   gint outside_w, outside_h;
4582   
4583   outside_w = (*x + w) - (rect->x + rect->width);
4584   if (outside_w > 0)
4585     *x -= outside_w;
4586
4587   outside_h = (*y + h) - (rect->y + rect->height);
4588   if (outside_h > 0)
4589     *y -= outside_h; 
4590
4591   /* if larger than the screen, center on the screen. */
4592   if (*x < rect->x)
4593     *x += (rect->x - *x) / 2;
4594   if (*y < rect->y)
4595     *y += (rect->y - *y) / 2;
4596 }
4597
4598
4599 static void
4600 gtk_window_compute_configure_request (GtkWindow    *window,
4601                                       GdkRectangle *request,
4602                                       GdkGeometry  *geometry,
4603                                       guint        *flags)
4604 {
4605   GdkGeometry new_geometry;
4606   guint new_flags;
4607   int w, h;
4608   GtkWidget *widget;
4609   GtkWindowPosition pos;
4610   GtkWidget *parent_widget;
4611   GtkWindowGeometryInfo *info;
4612   GdkScreen *screen;
4613   int x, y;
4614   
4615   widget = GTK_WIDGET (window);
4616
4617   screen = gtk_window_check_screen (window);
4618   
4619   gtk_widget_size_request (widget, NULL);
4620   gtk_window_compute_configure_request_size (window, &w, &h);
4621   
4622   gtk_window_compute_hints (window, &new_geometry, &new_flags);
4623   gtk_window_constrain_size (window,
4624                              &new_geometry, new_flags,
4625                              w, h,
4626                              &w, &h);
4627
4628   parent_widget = (GtkWidget*) window->transient_parent;
4629   
4630   pos = get_effective_position (window);
4631   info = gtk_window_get_geometry_info (window, TRUE);
4632
4633   /* by default, don't change position requested */
4634   x = info->last.configure_request.x;
4635   y = info->last.configure_request.y;
4636   
4637   if (window->need_default_position)
4638     {
4639
4640       /* FIXME this all interrelates with window gravity.
4641        * For most of them I think we want to set GRAVITY_CENTER.
4642        *
4643        * Not sure how to go about that.
4644        */
4645       
4646       switch (pos)
4647         {
4648           /* here we are only handling CENTER_ALWAYS
4649            * as it relates to default positioning,
4650            * where it's equivalent to simply CENTER
4651            */
4652         case GTK_WIN_POS_CENTER_ALWAYS:
4653         case GTK_WIN_POS_CENTER:
4654           center_window_on_monitor (window, w, h, &x, &y);
4655           break;
4656       
4657         case GTK_WIN_POS_CENTER_ON_PARENT:
4658           {
4659             gint monitor_num;
4660             GdkRectangle monitor;
4661             gint ox, oy;
4662             
4663             g_assert (GTK_WIDGET_MAPPED (parent_widget)); /* established earlier */
4664
4665             if (parent_widget->window != NULL)
4666               monitor_num = gdk_screen_get_monitor_at_window (screen,
4667                                                               parent_widget->window);
4668             else
4669               monitor_num = -1;
4670             
4671             gdk_window_get_origin (parent_widget->window,
4672                                    &ox, &oy);
4673             
4674             x = ox + (parent_widget->allocation.width - w) / 2;
4675             y = oy + (parent_widget->allocation.height - h) / 2;
4676             
4677             /* Clamp onto current monitor, ignoring _NET_WM_STRUT and
4678              * WM decorations. If parent wasn't on a monitor, just
4679              * give up.
4680              */
4681             if (monitor_num >= 0)
4682               {
4683                 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
4684                 clamp_window_to_rectangle (&x, &y, w, h, &monitor);
4685               }
4686           }
4687           break;
4688
4689         case GTK_WIN_POS_MOUSE:
4690           {
4691             gint screen_width = gdk_screen_get_width (screen);
4692             gint screen_height = gdk_screen_get_height (screen);
4693             gint monitor_num;
4694             GdkRectangle monitor;
4695             GdkScreen *pointer_screen;
4696             gint px, py;
4697             
4698             gdk_display_get_pointer (gdk_screen_get_display (screen),
4699                                      &pointer_screen,
4700                                      &px, &py, NULL);
4701
4702             if (pointer_screen == screen)
4703               monitor_num = gdk_screen_get_monitor_at_point (screen, px, py);
4704             else
4705               monitor_num = -1;
4706             
4707             x = px - w / 2;
4708             y = py - h / 2;
4709             x = CLAMP (x, 0, screen_width - w);
4710             y = CLAMP (y, 0, screen_height - h);
4711
4712             /* Clamp onto current monitor, ignoring _NET_WM_STRUT and
4713              * WM decorations. Don't try to figure out what's going
4714              * on if the mouse wasn't inside a monitor.
4715              */
4716             if (monitor_num >= 0)
4717               {
4718                 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
4719                 clamp_window_to_rectangle (&x, &y, w, h, &monitor);
4720               }
4721           }
4722           break;
4723
4724         default:
4725           break;
4726         }
4727     } /* if (window->need_default_position) */
4728
4729   if (window->need_default_position &&
4730       info->initial_pos_set)
4731     {
4732       x = info->initial_x;
4733       y = info->initial_y;
4734       gtk_window_constrain_position (window, w, h, &x, &y);
4735     }
4736   
4737   request->x = x;
4738   request->y = y;
4739   request->width = w;
4740   request->height = h;
4741
4742   if (geometry)
4743     *geometry = new_geometry;
4744   if (flags)
4745     *flags = new_flags;
4746 }
4747
4748 static void
4749 gtk_window_constrain_position (GtkWindow    *window,
4750                                gint          new_width,
4751                                gint          new_height,
4752                                gint         *x,
4753                                gint         *y)
4754 {
4755   /* See long comments in gtk_window_move_resize()
4756    * on when it's safe to call this function.
4757    */
4758   if (window->position == GTK_WIN_POS_CENTER_ALWAYS)
4759     {
4760       gint center_x, center_y;
4761
4762       center_window_on_monitor (window, new_width, new_height, &center_x, &center_y);
4763       
4764       *x = center_x;
4765       *y = center_y;
4766     }
4767 }
4768
4769 static void
4770 gtk_window_move_resize (GtkWindow *window)
4771 {
4772   /* Overview:
4773    *
4774    * First we determine whether any information has changed that would
4775    * cause us to revise our last configure request.  If we would send
4776    * a different configure request from last time, then
4777    * configure_request_size_changed = TRUE or
4778    * configure_request_pos_changed = TRUE. configure_request_size_changed
4779    * may be true due to new hints, a gtk_window_resize(), or whatever.
4780    * configure_request_pos_changed may be true due to gtk_window_set_position()
4781    * or gtk_window_move().
4782    *
4783    * If the configure request has changed, we send off a new one.  To
4784    * ensure GTK+ invariants are maintained (resize queue does what it
4785    * should), we go ahead and size_allocate the requested size in this
4786    * function.
4787    *
4788    * If the configure request has not changed, we don't ever resend
4789    * it, because it could mean fighting the user or window manager.
4790    *
4791    * 
4792    *   To prepare the configure request, we come up with a base size/pos:
4793    *      - the one from gtk_window_move()/gtk_window_resize()
4794    *      - else default_width, default_height if we haven't ever
4795    *        been mapped
4796    *      - else the size request if we haven't ever been mapped,
4797    *        as a substitute default size
4798    *      - else the current size of the window, as received from
4799    *        configure notifies (i.e. the current allocation)
4800    *
4801    *   If GTK_WIN_POS_CENTER_ALWAYS is active, we constrain
4802    *   the position request to be centered.
4803    */
4804   GtkWidget *widget;
4805   GtkContainer *container;
4806   GtkWindowGeometryInfo *info;
4807   GdkGeometry new_geometry;
4808   guint new_flags;
4809   GdkRectangle new_request;
4810   gboolean configure_request_size_changed;
4811   gboolean configure_request_pos_changed;
4812   gboolean hints_changed; /* do we need to send these again */
4813   GtkWindowLastGeometryInfo saved_last_info;
4814   
4815   widget = GTK_WIDGET (window);
4816   container = GTK_CONTAINER (widget);
4817   info = gtk_window_get_geometry_info (window, TRUE);
4818   
4819   configure_request_size_changed = FALSE;
4820   configure_request_pos_changed = FALSE;
4821   
4822   gtk_window_compute_configure_request (window, &new_request,
4823                                         &new_geometry, &new_flags);  
4824   
4825   /* This check implies the invariant that we never set info->last
4826    * without setting the hints and sending off a configure request.
4827    *
4828    * If we change info->last without sending the request, we may
4829    * miss a request.
4830    */
4831   if (info->last.configure_request.x != new_request.x ||
4832       info->last.configure_request.y != new_request.y)
4833     configure_request_pos_changed = TRUE;
4834
4835   if ((info->last.configure_request.width != new_request.width ||
4836        info->last.configure_request.height != new_request.height))
4837     configure_request_size_changed = TRUE;
4838   
4839   hints_changed = FALSE;
4840   
4841   if (!gtk_window_compare_hints (&info->last.geometry, info->last.flags,
4842                                  &new_geometry, new_flags))
4843     {
4844       hints_changed = TRUE;
4845     }
4846   
4847   /* Position Constraints
4848    * ====================
4849    * 
4850    * POS_CENTER_ALWAYS is conceptually a constraint rather than
4851    * a default. The other POS_ values are used only when the
4852    * window is shown, not after that.
4853    * 
4854    * However, we can't implement a position constraint as
4855    * "anytime the window size changes, center the window"
4856    * because this may well end up fighting the WM or user.  In
4857    * fact it gets in an infinite loop with at least one WM.
4858    *
4859    * Basically, applications are in no way in a position to
4860    * constrain the position of a window, with one exception:
4861    * override redirect windows. (Really the intended purpose
4862    * of CENTER_ALWAYS anyhow, I would think.)
4863    *
4864    * So the way we implement this "constraint" is to say that when WE
4865    * cause a move or resize, i.e. we make a configure request changing
4866    * window size, we recompute the CENTER_ALWAYS position to reflect
4867    * the new window size, and include it in our request.  Also, if we
4868    * just turned on CENTER_ALWAYS we snap to center with a new
4869    * request.  Otherwise, if we are just NOTIFIED of a move or resize
4870    * done by someone else e.g. the window manager, we do NOT send a
4871    * new configure request.
4872    *
4873    * For override redirect windows, this works fine; all window
4874    * sizes are from our configure requests. For managed windows,
4875    * it is at least semi-sane, though who knows what the
4876    * app author is thinking.
4877    */
4878
4879   /* This condition should be kept in sync with the condition later on
4880    * that determines whether we send a configure request.  i.e. we
4881    * should do this position constraining anytime we were going to
4882    * send a configure request anyhow, plus when constraints have
4883    * changed.
4884    */
4885   if (configure_request_pos_changed ||
4886       configure_request_size_changed ||
4887       hints_changed ||
4888       info->position_constraints_changed)
4889     {
4890       /* We request the constrained position if:
4891        *  - we were changing position, and need to clamp
4892        *    the change to the constraint
4893        *  - we're changing the size anyway
4894        *  - set_position() was called to toggle CENTER_ALWAYS on
4895        */
4896
4897       gtk_window_constrain_position (window,
4898                                      new_request.width,
4899                                      new_request.height,
4900                                      &new_request.x,
4901                                      &new_request.y);
4902       
4903       /* Update whether we need to request a move */
4904       if (info->last.configure_request.x != new_request.x ||
4905           info->last.configure_request.y != new_request.y)
4906         configure_request_pos_changed = TRUE;
4907       else
4908         configure_request_pos_changed = FALSE;
4909     }
4910
4911 #if 0
4912   if (window->type == GTK_WINDOW_TOPLEVEL)
4913     {
4914       int notify_x, notify_y;
4915
4916       /* this is the position from the last configure notify */
4917       gdk_window_get_position (widget->window, &notify_x, &notify_y);
4918     
4919       g_message ("--- %s ---\n"
4920                  "last  : %d,%d\t%d x %d\n"
4921                  "this  : %d,%d\t%d x %d\n"
4922                  "alloc : %d,%d\t%d x %d\n"
4923                  "req   :      \t%d x %d\n"
4924                  "resize:      \t%d x %d\n" 
4925                  "size_changed: %d pos_changed: %d hints_changed: %d\n"
4926                  "configure_notify_received: %d\n"
4927                  "configure_request_count: %d\n"
4928                  "position_constraints_changed: %d\n",
4929                  window->title ? window->title : "(no title)",
4930                  info->last.configure_request.x,
4931                  info->last.configure_request.y,
4932                  info->last.configure_request.width,
4933                  info->last.configure_request.height,
4934                  new_request.x,
4935                  new_request.y,
4936                  new_request.width,
4937                  new_request.height,
4938                  notify_x, notify_y,
4939                  widget->allocation.width,
4940                  widget->allocation.height,
4941                  widget->requisition.width,
4942                  widget->requisition.height,
4943                  info->resize_width,
4944                  info->resize_height,
4945                  configure_request_pos_changed,
4946                  configure_request_size_changed,
4947                  hints_changed,
4948                  window->configure_notify_received,
4949                  window->configure_request_count,
4950                  info->position_constraints_changed);
4951     }
4952 #endif
4953   
4954   saved_last_info = info->last;
4955   info->last.geometry = new_geometry;
4956   info->last.flags = new_flags;
4957   info->last.configure_request = new_request;
4958   
4959   /* need to set PPosition so the WM will look at our position,
4960    * but we don't want to count PPosition coming and going as a hints
4961    * change for future iterations. So we saved info->last prior to
4962    * this.
4963    */
4964   
4965   /* Also, if the initial position was explicitly set, then we always
4966    * toggle on PPosition. This makes gtk_window_move(window, 0, 0)
4967    * work.
4968    */
4969
4970   /* Also, we toggle on PPosition if GTK_WIN_POS_ is in use and
4971    * this is an initial map
4972    */
4973   
4974   if ((configure_request_pos_changed ||
4975        info->initial_pos_set ||
4976        (window->need_default_position &&
4977         get_effective_position (window) != GTK_WIN_POS_NONE)) &&
4978       (new_flags & GDK_HINT_POS) == 0)
4979     {
4980       new_flags |= GDK_HINT_POS;
4981       hints_changed = TRUE;
4982     }
4983   
4984   /* Set hints if necessary
4985    */
4986   if (hints_changed)
4987     gdk_window_set_geometry_hints (widget->window,
4988                                    &new_geometry,
4989                                    new_flags);
4990   
4991   /* handle resizing/moving and widget tree allocation
4992    */
4993   if (window->configure_notify_received)
4994     { 
4995       GtkAllocation allocation;
4996
4997       /* If we have received a configure event since
4998        * the last time in this function, we need to
4999        * accept our new size and size_allocate child widgets.
5000        * (see gtk_window_configure_event() for more details).
5001        *
5002        * 1 or more configure notifies may have been received.
5003        * Also, configure_notify_received will only be TRUE
5004        * if all expected configure notifies have been received
5005        * (one per configure request), as an optimization.
5006        *
5007        */
5008       window->configure_notify_received = FALSE;
5009
5010       /* gtk_window_configure_event() filled in widget->allocation */
5011       allocation = widget->allocation;
5012       gtk_widget_size_allocate (widget, &allocation);
5013
5014       /* If the configure request changed, it means that
5015        * we either:
5016        *   1) coincidentally changed hints or widget properties
5017        *      impacting the configure request before getting
5018        *      a configure notify, or
5019        *   2) some broken widget is changing its size request
5020        *      during size allocation, resulting in
5021        *      a false appearance of changed configure request.
5022        *
5023        * For 1), we could just go ahead and ask for the
5024        * new size right now, but doing that for 2)
5025        * might well be fighting the user (and can even
5026        * trigger a loop). Since we really don't want to
5027        * do that, we requeue a resize in hopes that
5028        * by the time it gets handled, the child has seen
5029        * the light and is willing to go along with the
5030        * new size. (this happens for the zvt widget, since
5031        * the size_allocate() above will have stored the
5032        * requisition corresponding to the new size in the
5033        * zvt widget)
5034        *
5035        * This doesn't buy us anything for 1), but it shouldn't
5036        * hurt us too badly, since it is what would have
5037        * happened if we had gotten the configure event before
5038        * the new size had been set.
5039        */
5040
5041       if (configure_request_size_changed ||
5042           configure_request_pos_changed)
5043         {
5044           /* Don't change the recorded last info after all, because we
5045            * haven't actually updated to the new info yet - we decided
5046            * to postpone our configure request until later.
5047            */
5048           info->last = saved_last_info;
5049           
5050           gtk_widget_queue_resize (widget); /* migth recurse for GTK_RESIZE_IMMEDIATE */
5051         }
5052
5053       return;                   /* Bail out, we didn't really process the move/resize */
5054     }
5055   else if ((configure_request_size_changed || hints_changed) &&
5056            (widget->allocation.width != new_request.width ||
5057             widget->allocation.height != new_request.height))
5058
5059     {
5060       /* We are in one of the following situations:
5061        * A. configure_request_size_changed
5062        *    our requisition has changed and we need a different window size,
5063        *    so we request it from the window manager.
5064        * B. !configure_request_size_changed && hints_changed
5065        *    the window manager rejects our size, but we have just changed the
5066        *    window manager hints, so there's a chance our request will
5067        *    be honoured this time, so we try again.
5068        *
5069        * However, if the new requisition is the same as the current allocation,
5070        * we don't request it again, since we won't get a ConfigureNotify back from
5071        * the window manager unless it decides to change our requisition. If
5072        * we don't get the ConfigureNotify back, the resize queue will never be run.
5073        */
5074
5075       /* Now send the configure request */
5076       if (configure_request_pos_changed)
5077         {
5078           if (window->frame)
5079             {
5080               gdk_window_move_resize (window->frame,
5081                                       new_request.x - window->frame_left,
5082                                       new_request.y - window->frame_top,
5083                                       new_request.width + window->frame_left + window->frame_right,
5084                                       new_request.height + window->frame_top + window->frame_bottom);
5085               gdk_window_resize (widget->window,
5086                                  new_request.width, new_request.height);
5087             }
5088           else
5089             gdk_window_move_resize (widget->window,
5090                                     new_request.x, new_request.y,
5091                                     new_request.width, new_request.height);
5092         }
5093       else  /* only size changed */
5094         {
5095           if (window->frame)
5096             gdk_window_resize (window->frame,
5097                                new_request.width + window->frame_left + window->frame_right,
5098                                new_request.height + window->frame_top + window->frame_bottom);
5099           gdk_window_resize (widget->window,
5100                              new_request.width, new_request.height);
5101         }
5102       
5103       /* Increment the number of have-not-yet-received-notify requests */
5104       window->configure_request_count += 1;
5105
5106       /* for GTK_RESIZE_QUEUE toplevels, we are now awaiting a new
5107        * configure event in response to our resizing request.
5108        * the configure event will cause a new resize with
5109        * ->configure_notify_received=TRUE.
5110        * until then, we want to
5111        * - discard expose events
5112        * - coalesce resizes for our children
5113        * - defer any window resizes until the configure event arrived
5114        * to achieve this, we queue a resize for the window, but remove its
5115        * resizing handler, so resizing will not be handled from the next
5116        * idle handler but when the configure event arrives.
5117        *
5118        * FIXME: we should also dequeue the pending redraws here, since
5119        * we handle those ourselves upon ->configure_notify_received==TRUE.
5120        */
5121       if (container->resize_mode == GTK_RESIZE_QUEUE)
5122         {
5123           gtk_widget_queue_resize (widget);
5124           _gtk_container_dequeue_resize_handler (container);
5125         }
5126     }
5127   else
5128     {
5129       /* Handle any position changes.
5130        */
5131       if (configure_request_pos_changed)
5132         {
5133           if (window->frame)
5134             {
5135               gdk_window_move (window->frame,
5136                                new_request.x - window->frame_left,
5137                                new_request.y - window->frame_top);
5138             }
5139           else
5140             gdk_window_move (widget->window,
5141                              new_request.x, new_request.y);
5142         }
5143
5144       /* And run the resize queue.
5145        */
5146       gtk_container_resize_children (container);
5147     }
5148   
5149   /* We have now processed a move/resize since the last position
5150    * constraint change, setting of the initial position, or resize.
5151    * (Not resetting these flags here can lead to infinite loops for
5152    * GTK_RESIZE_IMMEDIATE containers)
5153    */
5154   info->position_constraints_changed = FALSE;
5155   info->initial_pos_set = FALSE;
5156   info->resize_width = -1;
5157   info->resize_height = -1;
5158 }
5159
5160 /* Compare two sets of Geometry hints for equality.
5161  */
5162 static gboolean
5163 gtk_window_compare_hints (GdkGeometry *geometry_a,
5164                           guint        flags_a,
5165                           GdkGeometry *geometry_b,
5166                           guint        flags_b)
5167 {
5168   if (flags_a != flags_b)
5169     return FALSE;
5170   
5171   if ((flags_a & GDK_HINT_MIN_SIZE) &&
5172       (geometry_a->min_width != geometry_b->min_width ||
5173        geometry_a->min_height != geometry_b->min_height))
5174     return FALSE;
5175
5176   if ((flags_a & GDK_HINT_MAX_SIZE) &&
5177       (geometry_a->max_width != geometry_b->max_width ||
5178        geometry_a->max_height != geometry_b->max_height))
5179     return FALSE;
5180
5181   if ((flags_a & GDK_HINT_BASE_SIZE) &&
5182       (geometry_a->base_width != geometry_b->base_width ||
5183        geometry_a->base_height != geometry_b->base_height))
5184     return FALSE;
5185
5186   if ((flags_a & GDK_HINT_ASPECT) &&
5187       (geometry_a->min_aspect != geometry_b->min_aspect ||
5188        geometry_a->max_aspect != geometry_b->max_aspect))
5189     return FALSE;
5190
5191   if ((flags_a & GDK_HINT_RESIZE_INC) &&
5192       (geometry_a->width_inc != geometry_b->width_inc ||
5193        geometry_a->height_inc != geometry_b->height_inc))
5194     return FALSE;
5195
5196   if ((flags_a & GDK_HINT_WIN_GRAVITY) &&
5197       geometry_a->win_gravity != geometry_b->win_gravity)
5198     return FALSE;
5199
5200   return TRUE;
5201 }
5202
5203 void
5204 _gtk_window_constrain_size (GtkWindow   *window,
5205                             gint         width,
5206                             gint         height,
5207                             gint        *new_width,
5208                             gint        *new_height)
5209 {
5210   GtkWindowGeometryInfo *info;
5211
5212   g_return_if_fail (GTK_IS_WINDOW (window));
5213
5214   info = window->geometry_info;
5215   if (info)
5216     {
5217       GdkWindowHints flags = info->last.flags;
5218       GdkGeometry *geometry = &info->last.geometry;
5219       
5220       gtk_window_constrain_size (window,
5221                                  geometry,
5222                                  flags,
5223                                  width,
5224                                  height,
5225                                  new_width,
5226                                  new_height);
5227     }
5228 }
5229
5230 static void 
5231 gtk_window_constrain_size (GtkWindow   *window,
5232                            GdkGeometry *geometry,
5233                            guint        flags,
5234                            gint         width,
5235                            gint         height,
5236                            gint        *new_width,
5237                            gint        *new_height)
5238 {
5239   gdk_window_constrain_size (geometry, flags, width, height,
5240                              new_width, new_height);
5241 }
5242
5243 /* Compute the set of geometry hints and flags for a window
5244  * based on the application set geometry, and requisiition
5245  * of the window. gtk_widget_size_request() must have been
5246  * called first.
5247  */
5248 static void
5249 gtk_window_compute_hints (GtkWindow   *window,
5250                           GdkGeometry *new_geometry,
5251                           guint       *new_flags)
5252 {
5253   GtkWidget *widget;
5254   gint extra_width = 0;
5255   gint extra_height = 0;
5256   GtkWindowGeometryInfo *geometry_info;
5257   GtkRequisition requisition;
5258
5259   widget = GTK_WIDGET (window);
5260   
5261   gtk_widget_get_child_requisition (widget, &requisition);
5262   geometry_info = gtk_window_get_geometry_info (GTK_WINDOW (widget), FALSE);
5263
5264   if (geometry_info)
5265     {
5266       *new_flags = geometry_info->mask;
5267       *new_geometry = geometry_info->geometry;
5268     }
5269   else
5270     {
5271       *new_flags = 0;
5272     }
5273   
5274   if (geometry_info && geometry_info->widget)
5275     {
5276       GtkRequisition child_requisition;
5277
5278       /* FIXME: This really isn't right. It gets the min size wrong and forces
5279        * callers to do horrible hacks like set a huge usize on the child requisition
5280        * to get the base size right. We really want to find the answers to:
5281        *
5282        *  - If the geometry widget was infinitely big, how much extra space
5283        *    would be needed for the stuff around it.
5284        *
5285        *  - If the geometry widget was infinitely small, how big would the
5286        *    window still have to be.
5287        *
5288        * Finding these answers would be a bit of a mess here. (Bug #68668)
5289        */
5290       gtk_widget_get_child_requisition (geometry_info->widget, &child_requisition);
5291       
5292       extra_width = widget->requisition.width - child_requisition.width;
5293       extra_height = widget->requisition.height - child_requisition.height;
5294     }
5295
5296   /* We don't want to set GDK_HINT_POS in here, we just set it
5297    * in gtk_window_move_resize() when we want the position
5298    * honored.
5299    */
5300   
5301   if (*new_flags & GDK_HINT_BASE_SIZE)
5302     {
5303       new_geometry->base_width += extra_width;
5304       new_geometry->base_height += extra_height;
5305     }
5306   else if (!(*new_flags & GDK_HINT_MIN_SIZE) &&
5307            (*new_flags & GDK_HINT_RESIZE_INC) &&
5308            ((extra_width != 0) || (extra_height != 0)))
5309     {
5310       *new_flags |= GDK_HINT_BASE_SIZE;
5311       
5312       new_geometry->base_width = extra_width;
5313       new_geometry->base_height = extra_height;
5314     }
5315   
5316   if (*new_flags & GDK_HINT_MIN_SIZE)
5317     {
5318       if (new_geometry->min_width < 0)
5319         new_geometry->min_width = requisition.width;
5320       else
5321         new_geometry->min_width += extra_width;
5322
5323       if (new_geometry->min_height < 0)
5324         new_geometry->min_height = requisition.height;
5325       else
5326         new_geometry->min_height += extra_height;
5327     }
5328   else if (!window->allow_shrink)
5329     {
5330       *new_flags |= GDK_HINT_MIN_SIZE;
5331       
5332       new_geometry->min_width = requisition.width;
5333       new_geometry->min_height = requisition.height;
5334     }
5335   
5336   if (*new_flags & GDK_HINT_MAX_SIZE)
5337     {
5338       if (new_geometry->max_width < 0)
5339         new_geometry->max_width = requisition.width;
5340       else
5341         new_geometry->max_width += extra_width;
5342
5343       if (new_geometry->max_height < 0)
5344         new_geometry->max_width = requisition.height;
5345       else
5346         new_geometry->max_height += extra_height;
5347     }
5348   else if (!window->allow_grow)
5349     {
5350       *new_flags |= GDK_HINT_MAX_SIZE;
5351       
5352       new_geometry->max_width = requisition.width;
5353       new_geometry->max_height = requisition.height;
5354     }
5355
5356   *new_flags |= GDK_HINT_WIN_GRAVITY;
5357   new_geometry->win_gravity = window->gravity;
5358 }
5359
5360 /***********************
5361  * Redrawing functions *
5362  ***********************/
5363
5364 static void
5365 gtk_window_paint (GtkWidget     *widget,
5366                   GdkRectangle *area)
5367 {
5368   gtk_paint_flat_box (widget->style, widget->window, GTK_STATE_NORMAL, 
5369                       GTK_SHADOW_NONE, area, widget, "base", 0, 0, -1, -1);
5370 }
5371
5372 static gint
5373 gtk_window_expose (GtkWidget      *widget,
5374                    GdkEventExpose *event)
5375 {
5376   if (!GTK_WIDGET_APP_PAINTABLE (widget))
5377     gtk_window_paint (widget, &event->area);
5378   
5379   if (GTK_WIDGET_CLASS (parent_class)->expose_event)
5380     return GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
5381
5382   return FALSE;
5383 }
5384
5385 /**
5386  * gtk_window_set_has_frame:
5387  * @window: a #GtkWindow
5388  * @setting: a boolean
5389  *
5390  * (Note: this is a special-purpose function for the framebuffer port,
5391  *  that causes GTK+ to draw its own window border. For most applications,
5392  *  you want gtk_window_set_decorated() instead, which tells the window
5393  *  manager whether to draw the window border.)
5394  * 
5395  * If this function is called on a window with setting of %TRUE, before
5396  * it is realized or showed, it will have a "frame" window around
5397  * @window->window, accessible in @window->frame. Using the signal 
5398  * frame_event you can recieve all events targeted at the frame.
5399  * 
5400  * This function is used by the linux-fb port to implement managed
5401  * windows, but it could concievably be used by X-programs that
5402  * want to do their own window decorations.
5403  *
5404  **/
5405 void
5406 gtk_window_set_has_frame (GtkWindow *window, 
5407                           gboolean   setting)
5408 {
5409   g_return_if_fail (GTK_IS_WINDOW (window));
5410   g_return_if_fail (!GTK_WIDGET_REALIZED (window));
5411
5412   window->has_frame = setting != FALSE;
5413 }
5414
5415 /**
5416  * gtk_window_get_has_frame:
5417  * @window: a #GtkWindow
5418  * 
5419  * Accessor for whether the window has a frame window exterior to
5420  * @window->window. Gets the value set by gtk_window_set_has_frame ().
5421  *
5422  * Return value: %TRUE if a frame has been added to the window
5423  *   via gtk_window_set_has_frame().
5424  **/
5425 gboolean
5426 gtk_window_get_has_frame (GtkWindow *window)
5427 {
5428   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
5429
5430   return window->has_frame;
5431 }
5432
5433 /**
5434  * gtk_window_set_frame_dimensions:
5435  * @window: a #GtkWindow that has a frame
5436  * @left: The width of the left border
5437  * @top: The height of the top border
5438  * @right: The width of the right border
5439  * @bottom: The height of the bottom border
5440  *
5441  * (Note: this is a special-purpose function intended for the framebuffer
5442  *  port; see gtk_window_set_has_frame(). It will have no effect on the
5443  *  window border drawn by the window manager, which is the normal
5444  *  case when using the X Window system.)
5445  *
5446  * For windows with frames (see gtk_window_set_has_frame()) this function
5447  * can be used to change the size of the frame border.
5448  **/
5449 void
5450 gtk_window_set_frame_dimensions (GtkWindow *window, 
5451                                  gint       left,
5452                                  gint       top,
5453                                  gint       right,
5454                                  gint       bottom)
5455 {
5456   GtkWidget *widget;
5457
5458   g_return_if_fail (GTK_IS_WINDOW (window));
5459
5460   widget = GTK_WIDGET (window);
5461
5462   if (window->frame_left == left &&
5463       window->frame_top == top &&
5464       window->frame_right == right && 
5465       window->frame_bottom == bottom)
5466     return;
5467
5468   window->frame_left = left;
5469   window->frame_top = top;
5470   window->frame_right = right;
5471   window->frame_bottom = bottom;
5472
5473   if (GTK_WIDGET_REALIZED (widget) && window->frame)
5474     {
5475       gint width = widget->allocation.width + left + right;
5476       gint height = widget->allocation.height + top + bottom;
5477       gdk_window_resize (window->frame, width, height);
5478       gtk_decorated_window_move_resize_window (window,
5479                                                left, top,
5480                                                widget->allocation.width,
5481                                                widget->allocation.height);
5482     }
5483 }
5484
5485 /**
5486  * gtk_window_present:
5487  * @window: a #GtkWindow
5488  *
5489  * Presents a window to the user. This may mean raising the window
5490  * in the stacking order, deiconifying it, moving it to the current
5491  * desktop, and/or giving it the keyboard focus, possibly dependent
5492  * on the user's platform, window manager, and preferences.
5493  *
5494  * If @window is hidden, this function calls gtk_widget_show()
5495  * as well.
5496  * 
5497  * This function should be used when the user tries to open a window
5498  * that's already open. Say for example the preferences dialog is
5499  * currently open, and the user chooses Preferences from the menu
5500  * a second time; use gtk_window_present() to move the already-open dialog
5501  * where the user can see it.
5502  * 
5503  **/
5504 void
5505 gtk_window_present (GtkWindow *window)
5506 {
5507   GtkWidget *widget;
5508
5509   g_return_if_fail (GTK_IS_WINDOW (window));
5510
5511   widget = GTK_WIDGET (window);
5512
5513   if (GTK_WIDGET_VISIBLE (window))
5514     {
5515       g_assert (widget->window != NULL);
5516       
5517       gdk_window_show (widget->window);
5518
5519       /* note that gdk_window_focus() will also move the window to
5520        * the current desktop, for WM spec compliant window managers.
5521        */
5522       gdk_window_focus (widget->window,
5523                         gtk_get_current_event_time ());
5524     }
5525   else
5526     {
5527       gtk_widget_show (widget);
5528     }
5529 }
5530
5531 /**
5532  * gtk_window_iconify:
5533  * @window: a #GtkWindow
5534  *
5535  * Asks to iconify (i.e. minimize) the specified @window. Note that
5536  * you shouldn't assume the window is definitely iconified afterward,
5537  * because other entities (e.g. the user or <link
5538  * linkend="gtk-X11-arch">window manager</link>) could deiconify it
5539  * again, or there may not be a window manager in which case
5540  * iconification isn't possible, etc. But normally the window will end
5541  * up iconified. Just don't write code that crashes if not.
5542  *
5543  * It's permitted to call this function before showing a window,
5544  * in which case the window will be iconified before it ever appears
5545  * onscreen.
5546  *
5547  * You can track iconification via the "window_state_event" signal
5548  * on #GtkWidget.
5549  * 
5550  **/
5551 void
5552 gtk_window_iconify (GtkWindow *window)
5553 {
5554   GtkWidget *widget;
5555   GdkWindow *toplevel;
5556   
5557   g_return_if_fail (GTK_IS_WINDOW (window));
5558
5559   widget = GTK_WIDGET (window);
5560
5561   window->iconify_initially = TRUE;
5562
5563   if (window->frame)
5564     toplevel = window->frame;
5565   else
5566     toplevel = widget->window;
5567   
5568   if (toplevel != NULL)
5569     gdk_window_iconify (toplevel);
5570 }
5571
5572 /**
5573  * gtk_window_deiconify:
5574  * @window: a #GtkWindow
5575  *
5576  * Asks to deiconify (i.e. unminimize) the specified @window. Note
5577  * that you shouldn't assume the window is definitely deiconified
5578  * afterward, because other entities (e.g. the user or <link
5579  * linkend="gtk-X11-arch">window manager</link>) could iconify it
5580  * again before your code which assumes deiconification gets to run.
5581  *
5582  * You can track iconification via the "window_state_event" signal
5583  * on #GtkWidget.
5584  **/
5585 void
5586 gtk_window_deiconify (GtkWindow *window)
5587 {
5588   GtkWidget *widget;
5589   GdkWindow *toplevel;
5590   
5591   g_return_if_fail (GTK_IS_WINDOW (window));
5592
5593   widget = GTK_WIDGET (window);
5594
5595   window->iconify_initially = FALSE;
5596
5597   if (window->frame)
5598     toplevel = window->frame;
5599   else
5600     toplevel = widget->window;
5601   
5602   if (toplevel != NULL)
5603     gdk_window_deiconify (toplevel);
5604 }
5605
5606 /**
5607  * gtk_window_stick:
5608  * @window: a #GtkWindow
5609  *
5610  * Asks to stick @window, which means that it will appear on all user
5611  * desktops. Note that you shouldn't assume the window is definitely
5612  * stuck afterward, because other entities (e.g. the user or <link
5613  * linkend="gtk-X11-arch">window manager</link>) could unstick it
5614  * again, and some window managers do not support sticking
5615  * windows. But normally the window will end up stuck. Just don't
5616  * write code that crashes if not.
5617  *
5618  * It's permitted to call this function before showing a window.
5619  *
5620  * You can track stickiness via the "window_state_event" signal
5621  * on #GtkWidget.
5622  * 
5623  **/
5624 void
5625 gtk_window_stick (GtkWindow *window)
5626 {
5627   GtkWidget *widget;
5628   GdkWindow *toplevel;
5629   
5630   g_return_if_fail (GTK_IS_WINDOW (window));
5631
5632   widget = GTK_WIDGET (window);
5633
5634   window->stick_initially = TRUE;
5635
5636   if (window->frame)
5637     toplevel = window->frame;
5638   else
5639     toplevel = widget->window;
5640   
5641   if (toplevel != NULL)
5642     gdk_window_stick (toplevel);
5643 }
5644
5645 /**
5646  * gtk_window_unstick:
5647  * @window: a #GtkWindow
5648  *
5649  * Asks to unstick @window, which means that it will appear on only
5650  * one of the user's desktops. Note that you shouldn't assume the
5651  * window is definitely unstuck afterward, because other entities
5652  * (e.g. the user or <link linkend="gtk-X11-arch">window
5653  * manager</link>) could stick it again. But normally the window will
5654  * end up stuck. Just don't write code that crashes if not.
5655  *
5656  * You can track stickiness via the "window_state_event" signal
5657  * on #GtkWidget.
5658  * 
5659  **/
5660 void
5661 gtk_window_unstick (GtkWindow *window)
5662 {
5663   GtkWidget *widget;
5664   GdkWindow *toplevel;
5665   
5666   g_return_if_fail (GTK_IS_WINDOW (window));
5667
5668   widget = GTK_WIDGET (window);
5669
5670   window->stick_initially = FALSE;
5671
5672   if (window->frame)
5673     toplevel = window->frame;
5674   else
5675     toplevel = widget->window;
5676   
5677   if (toplevel != NULL)
5678     gdk_window_unstick (toplevel);
5679 }
5680
5681 /**
5682  * gtk_window_maximize:
5683  * @window: a #GtkWindow
5684  *
5685  * Asks to maximize @window, so that it becomes full-screen. Note that
5686  * you shouldn't assume the window is definitely maximized afterward,
5687  * because other entities (e.g. the user or <link
5688  * linkend="gtk-X11-arch">window manager</link>) could unmaximize it
5689  * again, and not all window managers support maximization. But
5690  * normally the window will end up maximized. Just don't write code
5691  * that crashes if not.
5692  *
5693  * It's permitted to call this function before showing a window,
5694  * in which case the window will be maximized when it appears onscreen
5695  * initially.
5696  *
5697  * You can track maximization via the "window_state_event" signal
5698  * on #GtkWidget.
5699  * 
5700  **/
5701 void
5702 gtk_window_maximize (GtkWindow *window)
5703 {
5704   GtkWidget *widget;
5705   GdkWindow *toplevel;
5706   
5707   g_return_if_fail (GTK_IS_WINDOW (window));
5708
5709   widget = GTK_WIDGET (window);
5710
5711   window->maximize_initially = TRUE;
5712
5713   if (window->frame)
5714     toplevel = window->frame;
5715   else
5716     toplevel = widget->window;
5717   
5718   if (toplevel != NULL)
5719     gdk_window_maximize (toplevel);
5720 }
5721
5722 /**
5723  * gtk_window_unmaximize:
5724  * @window: a #GtkWindow
5725  *
5726  * Asks to unmaximize @window. Note that you shouldn't assume the
5727  * window is definitely unmaximized afterward, because other entities
5728  * (e.g. the user or <link linkend="gtk-X11-arch">window
5729  * manager</link>) could maximize it again, and not all window
5730  * managers honor requests to unmaximize. But normally the window will
5731  * end up unmaximized. Just don't write code that crashes if not.
5732  *
5733  * You can track maximization via the "window_state_event" signal
5734  * on #GtkWidget.
5735  * 
5736  **/
5737 void
5738 gtk_window_unmaximize (GtkWindow *window)
5739 {
5740   GtkWidget *widget;
5741   GdkWindow *toplevel;
5742   
5743   g_return_if_fail (GTK_IS_WINDOW (window));
5744
5745   widget = GTK_WIDGET (window);
5746
5747   window->maximize_initially = FALSE;
5748
5749   if (window->frame)
5750     toplevel = window->frame;
5751   else
5752     toplevel = widget->window;
5753   
5754   if (toplevel != NULL)
5755     gdk_window_unmaximize (toplevel);
5756 }
5757
5758 /**
5759  * gtk_window_fullscreen:
5760  * @window: a #GtkWindow
5761  *
5762  * Asks to place @window in the fullscreen state. Note that you
5763  * shouldn't assume the window is definitely full screen afterward,
5764  * because other entities (e.g. the user or <link
5765  * linkend="gtk-X11-arch">window manager</link>) could unfullscreen it
5766  * again, and not all window managers honor requests to fullscreen
5767  * windows. But normally the window will end up fullscreen. Just
5768  * don't write code that crashes if not.
5769  *
5770  * You can track the fullscreen state via the "window_state_event" signal
5771  * on #GtkWidget.
5772  * 
5773  * Since: 2.2
5774  **/
5775 void
5776 gtk_window_fullscreen (GtkWindow *window)
5777 {
5778   GtkWidget *widget;
5779   GdkWindow *toplevel;
5780   GtkWindowPrivate *priv;
5781   
5782   g_return_if_fail (GTK_IS_WINDOW (window));
5783
5784   widget = GTK_WIDGET (window);
5785   priv = gtk_window_get_private (window);
5786   
5787   priv->fullscreen_initially = TRUE;
5788
5789   if (window->frame)
5790     toplevel = window->frame;
5791   else
5792     toplevel = widget->window;
5793   
5794   if (toplevel != NULL)
5795     gdk_window_fullscreen (toplevel);
5796 }
5797
5798 /**
5799  * gtk_window_unfullscreen:
5800  * @window: a #GtkWindow
5801  *
5802  * Asks to toggle off the fullscreen state for @window. Note that you
5803  * shouldn't assume the window is definitely not full screen
5804  * afterward, because other entities (e.g. the user or <link
5805  * linkend="gtk-X11-arch">window manager</link>) could fullscreen it
5806  * again, and not all window managers honor requests to unfullscreen
5807  * windows. But normally the window will end up restored to its normal
5808  * state. Just don't write code that crashes if not.
5809  *
5810  * You can track the fullscreen state via the "window_state_event" signal
5811  * on #GtkWidget.
5812  * 
5813  * Since: 2.2
5814  **/
5815 void
5816 gtk_window_unfullscreen (GtkWindow *window)
5817 {
5818   GtkWidget *widget;
5819   GdkWindow *toplevel;
5820   GtkWindowPrivate *priv;
5821   
5822   g_return_if_fail (GTK_IS_WINDOW (window));
5823
5824   widget = GTK_WIDGET (window);
5825   priv = gtk_window_get_private (window);
5826   
5827   priv->fullscreen_initially = FALSE;
5828
5829   if (window->frame)
5830     toplevel = window->frame;
5831   else
5832     toplevel = widget->window;
5833   
5834   if (toplevel != NULL)
5835     gdk_window_unfullscreen (toplevel);
5836 }
5837
5838
5839 /**
5840  * gtk_window_set_resizable:
5841  * @window: a #GtkWindow
5842  * @resizable: %TRUE if the user can resize this window
5843  *
5844  * Sets whether the user can resize a window. Windows are user resizable
5845  * by default.
5846  **/
5847 void
5848 gtk_window_set_resizable (GtkWindow *window,
5849                           gboolean   resizable)
5850 {
5851   g_return_if_fail (GTK_IS_WINDOW (window));
5852
5853   gtk_window_set_policy (window, FALSE, resizable, FALSE);
5854 }
5855
5856 /**
5857  * gtk_window_get_resizable:
5858  * @window: a #GtkWindow
5859  *
5860  * Gets the value set by gtk_window_set_resizable().
5861  *
5862  * Return value: %TRUE if the user can resize the window
5863  **/
5864 gboolean
5865 gtk_window_get_resizable (GtkWindow *window)
5866 {
5867   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
5868
5869   /* allow_grow is most likely to indicate the semantic concept we
5870    * mean by "resizable" (and will be a reliable indicator if
5871    * set_policy() hasn't been called)
5872    */
5873   return window->allow_grow;
5874 }
5875
5876 /**
5877  * gtk_window_set_gravity:
5878  * @window: a #GtkWindow
5879  * @gravity: window gravity
5880  *
5881  * Window gravity defines the meaning of coordinates passed to
5882  * gtk_window_move(). See gtk_window_move() and #GdkGravity for
5883  * more details.
5884  *
5885  * The default window gravity is #GDK_GRAVITY_NORTH_WEST which will
5886  * typically "do what you mean."
5887  *
5888  **/
5889 void
5890 gtk_window_set_gravity (GtkWindow *window,
5891                         GdkGravity gravity)
5892 {
5893   g_return_if_fail (GTK_IS_WINDOW (window));
5894
5895   if (gravity != window->gravity)
5896     {
5897       window->gravity = gravity;
5898
5899       /* gtk_window_move_resize() will adapt gravity
5900        */
5901       gtk_widget_queue_resize (GTK_WIDGET (window));
5902     }
5903 }
5904
5905 /**
5906  * gtk_window_get_gravity:
5907  * @window: a #GtkWindow
5908  *
5909  * Gets the value set by gtk_window_set_gravity().
5910  *
5911  * Return value: window gravity
5912  **/
5913 GdkGravity
5914 gtk_window_get_gravity (GtkWindow *window)
5915 {
5916   g_return_val_if_fail (GTK_IS_WINDOW (window), 0);
5917
5918   return window->gravity;
5919 }
5920
5921 /**
5922  * gtk_window_begin_resize_drag:
5923  * @window: a #GtkWindow
5924  * @button: mouse button that initiated the drag
5925  * @edge: position of the resize control
5926  * @root_x: X position where the user clicked to initiate the drag, in root window coordinates
5927  * @root_y: Y position where the user clicked to initiate the drag
5928  * @timestamp: timestamp from the click event that initiated the drag
5929  *
5930  * Starts resizing a window. This function is used if an application
5931  * has window resizing controls. When GDK can support it, the resize
5932  * will be done using the standard mechanism for the <link
5933  * linkend="gtk-X11-arch">window manager</link> or windowing
5934  * system. Otherwise, GDK will try to emulate window resizing,
5935  * potentially not all that well, depending on the windowing system.
5936  * 
5937  **/
5938 void
5939 gtk_window_begin_resize_drag  (GtkWindow    *window,
5940                                GdkWindowEdge edge,
5941                                gint          button,
5942                                gint          root_x,
5943                                gint          root_y,
5944                                guint32       timestamp)
5945 {
5946   GtkWidget *widget;
5947   GdkWindow *toplevel;
5948   
5949   g_return_if_fail (GTK_IS_WINDOW (window));
5950   g_return_if_fail (GTK_WIDGET_VISIBLE (window));
5951   
5952   widget = GTK_WIDGET (window);
5953   
5954   if (window->frame)
5955     toplevel = window->frame;
5956   else
5957     toplevel = widget->window;
5958   
5959   gdk_window_begin_resize_drag (toplevel,
5960                                 edge, button,
5961                                 root_x, root_y,
5962                                 timestamp);
5963 }
5964
5965 /**
5966  * gtk_window_get_frame_dimensions:
5967  * @window: a #GtkWindow
5968  * @left: location to store the width of the frame at the left, or %NULL
5969  * @top: location to store the height of the frame at the top, or %NULL
5970  * @right: location to store the width of the frame at the returns, or %NULL
5971  * @bottom: location to store the height of the frame at the bottom, or %NULL
5972  *
5973  * (Note: this is a special-purpose function intended for the
5974  *  framebuffer port; see gtk_window_set_has_frame(). It will not
5975  *  return the size of the window border drawn by the <link
5976  *  linkend="gtk-X11-arch">window manager</link>, which is the normal
5977  *  case when using a windowing system.  See
5978  *  gdk_window_get_frame_extents() to get the standard window border
5979  *  extents.)
5980  * 
5981  * Retrieves the dimensions of the frame window for this toplevel.
5982  * See gtk_window_set_has_frame(), gtk_window_set_frame_dimensions().
5983  **/
5984 void
5985 gtk_window_get_frame_dimensions (GtkWindow *window,
5986                                  gint      *left,
5987                                  gint      *top,
5988                                  gint      *right,
5989                                  gint      *bottom)
5990 {
5991   g_return_if_fail (GTK_IS_WINDOW (window));
5992
5993   if (left)
5994     *left = window->frame_left;
5995   if (top)
5996     *top = window->frame_top;
5997   if (right)
5998     *right = window->frame_right;
5999   if (bottom)
6000     *bottom = window->frame_bottom;
6001 }
6002
6003 /**
6004  * gtk_window_begin_move_drag:
6005  * @window: a #GtkWindow
6006  * @button: mouse button that initiated the drag
6007  * @root_x: X position where the user clicked to initiate the drag, in root window coordinates
6008  * @root_y: Y position where the user clicked to initiate the drag
6009  * @timestamp: timestamp from the click event that initiated the drag
6010  *
6011  * Starts moving a window. This function is used if an application has
6012  * window movement grips. When GDK can support it, the window movement
6013  * will be done using the standard mechanism for the <link
6014  * linkend="gtk-X11-arch">window manager</link> or windowing
6015  * system. Otherwise, GDK will try to emulate window movement,
6016  * potentially not all that well, depending on the windowing system.
6017  * 
6018  **/
6019 void
6020 gtk_window_begin_move_drag  (GtkWindow *window,
6021                              gint       button,
6022                              gint       root_x,
6023                              gint       root_y,
6024                              guint32    timestamp)
6025 {
6026   GtkWidget *widget;
6027   GdkWindow *toplevel;
6028   
6029   g_return_if_fail (GTK_IS_WINDOW (window));
6030   g_return_if_fail (GTK_WIDGET_VISIBLE (window));
6031   
6032   widget = GTK_WIDGET (window);
6033   
6034   if (window->frame)
6035     toplevel = window->frame;
6036   else
6037     toplevel = widget->window;
6038   
6039   gdk_window_begin_move_drag (toplevel,
6040                               button,
6041                               root_x, root_y,
6042                               timestamp);
6043 }
6044
6045 /** 
6046  * gtk_window_set_screen:
6047  * @window: a #GtkWindow.
6048  * @screen: a #GdkScreen.
6049  *
6050  * Sets the #GdkScreen where the @window is displayed; if
6051  * the window is already mapped, it will be unmapped, and
6052  * then remapped on the new screen.
6053  *
6054  * Since: 2.2
6055  */
6056 void
6057 gtk_window_set_screen (GtkWindow *window,
6058                        GdkScreen *screen)
6059 {
6060   GtkWidget *widget;
6061   GdkScreen *previous_screen;
6062   gboolean was_mapped;
6063   
6064   g_return_if_fail (GTK_IS_WINDOW (window));
6065   g_return_if_fail (GDK_IS_SCREEN (screen));
6066
6067   if (screen == window->screen)
6068     return;
6069
6070   widget = GTK_WIDGET (window);
6071
6072   previous_screen = window->screen;
6073   was_mapped = GTK_WIDGET_MAPPED (widget);
6074
6075   if (was_mapped)
6076     gtk_widget_unmap (widget);
6077   if (GTK_WIDGET_REALIZED (widget))
6078     gtk_widget_unrealize (widget);
6079       
6080   gtk_window_free_key_hash (window);
6081   window->screen = screen;
6082   gtk_widget_reset_rc_styles (widget);
6083   if (screen != previous_screen)
6084     _gtk_widget_propagate_screen_changed (widget, previous_screen);
6085   g_object_notify (G_OBJECT (window), "screen");
6086
6087   if (was_mapped)
6088     gtk_widget_map (widget);
6089 }
6090
6091 static GdkScreen *
6092 gtk_window_check_screen (GtkWindow *window)
6093 {
6094   if (window->screen)
6095     return window->screen;
6096   else
6097     {
6098       g_warning ("Screen for GtkWindow not set; you must always set\n"
6099                  "a screen for a GtkWindow before using the window");
6100       return NULL;
6101     }
6102 }
6103
6104 /** 
6105  * gtk_window_get_screen:
6106  * @window: a #GtkWindow.
6107  *
6108  * Returns the #GdkScreen associated with @window.
6109  *
6110  * Return value: a #GdkScreen.
6111  *
6112  * Since: 2.2
6113  */
6114 GdkScreen*
6115 gtk_window_get_screen (GtkWindow *window)
6116 {
6117    g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
6118    
6119    return window->screen;
6120 }
6121
6122
6123 static void
6124 gtk_window_group_class_init (GtkWindowGroupClass *klass)
6125 {
6126 }
6127
6128 GType
6129 gtk_window_group_get_type (void)
6130 {
6131   static GType window_group_type = 0;
6132
6133   if (!window_group_type)
6134     {
6135       static const GTypeInfo window_group_info =
6136       {
6137         sizeof (GtkWindowGroupClass),
6138         NULL,           /* base_init */
6139         NULL,           /* base_finalize */
6140         (GClassInitFunc) gtk_window_group_class_init,
6141         NULL,           /* class_finalize */
6142         NULL,           /* class_data */
6143         sizeof (GtkWindowGroup),
6144         16,             /* n_preallocs */
6145         (GInstanceInitFunc) NULL,
6146       };
6147
6148       window_group_type = g_type_register_static (G_TYPE_OBJECT, "GtkWindowGroup", &window_group_info, 0);
6149     }
6150
6151   return window_group_type;
6152 }
6153
6154 /**
6155  * gtk_window_group_new:
6156  * 
6157  * Creates a new #GtkWindowGroup object. Grabs added with
6158  * gtk_grab_add() only affect windows within the same #GtkWindowGroup.
6159  * 
6160  * Return value: a new #GtkWindowGroup. 
6161  **/
6162 GtkWindowGroup *
6163 gtk_window_group_new (void)
6164 {
6165   return g_object_new (GTK_TYPE_WINDOW_GROUP, NULL);
6166 }
6167
6168 static void
6169 window_group_cleanup_grabs (GtkWindowGroup *group,
6170                             GtkWindow      *window)
6171 {
6172   GSList *tmp_list;
6173   GSList *to_remove = NULL;
6174
6175   tmp_list = group->grabs;
6176   while (tmp_list)
6177     {
6178       if (gtk_widget_get_toplevel (tmp_list->data) == (GtkWidget*) window)
6179         to_remove = g_slist_prepend (to_remove, g_object_ref (tmp_list->data));
6180       tmp_list = tmp_list->next;
6181     }
6182
6183   while (to_remove)
6184     {
6185       gtk_grab_remove (to_remove->data);
6186       g_object_unref (to_remove->data);
6187       to_remove = g_slist_delete_link (to_remove, to_remove);
6188     }
6189 }
6190
6191 /**
6192  * gtk_window_group_add_window:
6193  * @window_group: a #GtkWindowGroup
6194  * @window: the #GtkWindow to add
6195  * 
6196  * Adds a window to a #GtkWindowGroup. 
6197  **/
6198 void
6199 gtk_window_group_add_window (GtkWindowGroup *window_group,
6200                              GtkWindow      *window)
6201 {
6202   g_return_if_fail (GTK_IS_WINDOW_GROUP (window_group));
6203   g_return_if_fail (GTK_IS_WINDOW (window));
6204
6205   if (window->group != window_group)
6206     {
6207       g_object_ref (window);
6208       g_object_ref (window_group);
6209       
6210       if (window->group)
6211         gtk_window_group_remove_window (window->group, window);
6212       else
6213         window_group_cleanup_grabs (_gtk_window_get_group (NULL), window);
6214
6215       window->group = window_group;
6216
6217       g_object_unref (window);
6218     }
6219 }
6220
6221 /**
6222  * gtk_window_group_remove_window:
6223  * @window_group: a #GtkWindowGroup
6224  * @window: the #GtkWindow to remove
6225  * 
6226  * Removes a window from a #GtkWindowGroup.
6227  **/
6228 void
6229 gtk_window_group_remove_window (GtkWindowGroup *window_group,
6230                                 GtkWindow      *window)
6231 {
6232   g_return_if_fail (GTK_IS_WINDOW_GROUP (window_group));
6233   g_return_if_fail (GTK_IS_WIDGET (window));
6234   g_return_if_fail (window->group == window_group);
6235
6236   g_object_ref (window);
6237
6238   window_group_cleanup_grabs (window_group, window);
6239   window->group = NULL;
6240   
6241   g_object_unref (window_group);
6242   g_object_unref (window);
6243 }
6244
6245 /* Return the group for the window or the default group
6246  */
6247 GtkWindowGroup *
6248 _gtk_window_get_group (GtkWindow *window)
6249 {
6250   if (window && window->group)
6251     return window->group;
6252   else
6253     {
6254       static GtkWindowGroup *default_group = NULL;
6255
6256       if (!default_group)
6257         default_group = gtk_window_group_new ();
6258
6259       return default_group;
6260     }
6261 }
6262
6263
6264 /*
6265   Derived from XParseGeometry() in XFree86  
6266
6267   Copyright 1985, 1986, 1987,1998  The Open Group
6268
6269   All Rights Reserved.
6270
6271   The above copyright notice and this permission notice shall be included
6272   in all copies or substantial portions of the Software.
6273
6274   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
6275   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
6276   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
6277   IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
6278   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
6279   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
6280   OTHER DEALINGS IN THE SOFTWARE.
6281
6282   Except as contained in this notice, the name of The Open Group shall
6283   not be used in advertising or otherwise to promote the sale, use or
6284   other dealings in this Software without prior written authorization
6285   from The Open Group.
6286 */
6287
6288
6289 /*
6290  *    XParseGeometry parses strings of the form
6291  *   "=<width>x<height>{+-}<xoffset>{+-}<yoffset>", where
6292  *   width, height, xoffset, and yoffset are unsigned integers.
6293  *   Example:  "=80x24+300-49"
6294  *   The equal sign is optional.
6295  *   It returns a bitmask that indicates which of the four values
6296  *   were actually found in the string.  For each value found,
6297  *   the corresponding argument is updated;  for each value
6298  *   not found, the corresponding argument is left unchanged. 
6299  */
6300
6301 /* The following code is from Xlib, and is minimally modified, so we
6302  * can track any upstream changes if required.  Don't change this
6303  * code. Or if you do, put in a huge comment marking which thing
6304  * changed.
6305  */
6306
6307 static int
6308 read_int (gchar   *string,
6309           gchar  **next)
6310 {
6311   int result = 0;
6312   int sign = 1;
6313   
6314   if (*string == '+')
6315     string++;
6316   else if (*string == '-')
6317     {
6318       string++;
6319       sign = -1;
6320     }
6321
6322   for (; (*string >= '0') && (*string <= '9'); string++)
6323     {
6324       result = (result * 10) + (*string - '0');
6325     }
6326
6327   *next = string;
6328
6329   if (sign >= 0)
6330     return (result);
6331   else
6332     return (-result);
6333 }
6334
6335 /* 
6336  * Bitmask returned by XParseGeometry().  Each bit tells if the corresponding
6337  * value (x, y, width, height) was found in the parsed string.
6338  */
6339 #define NoValue         0x0000
6340 #define XValue          0x0001
6341 #define YValue          0x0002
6342 #define WidthValue      0x0004
6343 #define HeightValue     0x0008
6344 #define AllValues       0x000F
6345 #define XNegative       0x0010
6346 #define YNegative       0x0020
6347
6348 /* Try not to reformat/modify, so we can compare/sync with X sources */
6349 static int
6350 gtk_XParseGeometry (const char   *string,
6351                     int          *x,
6352                     int          *y,
6353                     unsigned int *width,   
6354                     unsigned int *height)  
6355 {
6356   int mask = NoValue;
6357   char *strind;
6358   unsigned int tempWidth, tempHeight;
6359   int tempX, tempY;
6360   char *nextCharacter;
6361
6362   /* These initializations are just to silence gcc */
6363   tempWidth = 0;
6364   tempHeight = 0;
6365   tempX = 0;
6366   tempY = 0;
6367   
6368   if ( (string == NULL) || (*string == '\0')) return(mask);
6369   if (*string == '=')
6370     string++;  /* ignore possible '=' at beg of geometry spec */
6371
6372   strind = (char *)string;
6373   if (*strind != '+' && *strind != '-' && *strind != 'x') {
6374     tempWidth = read_int(strind, &nextCharacter);
6375     if (strind == nextCharacter) 
6376       return (0);
6377     strind = nextCharacter;
6378     mask |= WidthValue;
6379   }
6380
6381   if (*strind == 'x' || *strind == 'X') {       
6382     strind++;
6383     tempHeight = read_int(strind, &nextCharacter);
6384     if (strind == nextCharacter)
6385       return (0);
6386     strind = nextCharacter;
6387     mask |= HeightValue;
6388   }
6389
6390   if ((*strind == '+') || (*strind == '-')) {
6391     if (*strind == '-') {
6392       strind++;
6393       tempX = -read_int(strind, &nextCharacter);
6394       if (strind == nextCharacter)
6395         return (0);
6396       strind = nextCharacter;
6397       mask |= XNegative;
6398
6399     }
6400     else
6401       { strind++;
6402       tempX = read_int(strind, &nextCharacter);
6403       if (strind == nextCharacter)
6404         return(0);
6405       strind = nextCharacter;
6406       }
6407     mask |= XValue;
6408     if ((*strind == '+') || (*strind == '-')) {
6409       if (*strind == '-') {
6410         strind++;
6411         tempY = -read_int(strind, &nextCharacter);
6412         if (strind == nextCharacter)
6413           return(0);
6414         strind = nextCharacter;
6415         mask |= YNegative;
6416
6417       }
6418       else
6419         {
6420           strind++;
6421           tempY = read_int(strind, &nextCharacter);
6422           if (strind == nextCharacter)
6423             return(0);
6424           strind = nextCharacter;
6425         }
6426       mask |= YValue;
6427     }
6428   }
6429         
6430   /* If strind isn't at the end of the string the it's an invalid
6431                 geometry specification. */
6432
6433   if (*strind != '\0') return (0);
6434
6435   if (mask & XValue)
6436     *x = tempX;
6437   if (mask & YValue)
6438     *y = tempY;
6439   if (mask & WidthValue)
6440     *width = tempWidth;
6441   if (mask & HeightValue)
6442     *height = tempHeight;
6443   return (mask);
6444 }
6445
6446 /**
6447  * gtk_window_parse_geometry:
6448  * @window: a #GtkWindow
6449  * @geometry: geometry string
6450  * 
6451  * Parses a standard X Window System geometry string - see the
6452  * manual page for X (type 'man X') for details on this.
6453  * gtk_window_parse_geometry() does work on all GTK+ ports
6454  * including Win32 but is primarily intended for an X environment.
6455  *
6456  * If either a size or a position can be extracted from the
6457  * geometry string, gtk_window_parse_geometry() returns %TRUE
6458  * and calls gtk_window_set_default_size() and/or gtk_window_move()
6459  * to resize/move the window.
6460  *
6461  * If gtk_window_parse_geometry() returns %TRUE, it will also
6462  * set the #GDK_HINT_USER_POS and/or #GDK_HINT_USER_SIZE hints
6463  * indicating to the window manager that the size/position of
6464  * the window was user-specified. This causes most window
6465  * managers to honor the geometry.
6466  * 
6467  * Return value: %TRUE if string was parsed successfully
6468  **/
6469 gboolean
6470 gtk_window_parse_geometry (GtkWindow   *window,
6471                            const gchar *geometry)
6472 {
6473   gint result, x, y;
6474   guint w, h;
6475   GdkGravity grav;
6476   gboolean size_set, pos_set;
6477   GdkScreen *screen;
6478   
6479   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
6480   g_return_val_if_fail (geometry != NULL, FALSE);
6481
6482   screen = gtk_window_check_screen (window);
6483   
6484   result = gtk_XParseGeometry (geometry, &x, &y, &w, &h);
6485
6486   if ((result & WidthValue) == 0 ||
6487       w < 0)
6488     w = -1;
6489   if ((result & HeightValue) == 0 ||
6490       h < 0)
6491     h = -1;
6492
6493   size_set = FALSE;
6494   if ((result & WidthValue) || (result & HeightValue))
6495     {
6496       gtk_window_set_default_size_internal (window, TRUE, w, TRUE, h, TRUE);
6497       size_set = TRUE;
6498     }
6499
6500   gtk_window_get_size (window, &w, &h);
6501   
6502   grav = GDK_GRAVITY_NORTH_WEST;
6503
6504   if ((result & XNegative) && (result & YNegative))
6505     grav = GDK_GRAVITY_SOUTH_EAST;
6506   else if (result & XNegative)
6507     grav = GDK_GRAVITY_NORTH_EAST;
6508   else if (result & YNegative)
6509     grav = GDK_GRAVITY_SOUTH_WEST;
6510
6511   if ((result & XValue) == 0)
6512     x = 0;
6513
6514   if ((result & YValue) == 0)
6515     y = 0;
6516
6517   if (grav == GDK_GRAVITY_SOUTH_WEST ||
6518       grav == GDK_GRAVITY_SOUTH_EAST)
6519     y = gdk_screen_get_height (screen) - h + y;
6520
6521   if (grav == GDK_GRAVITY_SOUTH_EAST ||
6522       grav == GDK_GRAVITY_NORTH_EAST)
6523     x = gdk_screen_get_width (screen) - w + x;
6524
6525   /* we don't let you put a window offscreen; maybe some people would
6526    * prefer to be able to, but it's kind of a bogus thing to do.
6527    */
6528   if (y < 0)
6529     y = 0;
6530
6531   if (x < 0)
6532     x = 0;
6533
6534   pos_set = FALSE;
6535   if ((result & XValue) || (result & YValue))
6536     {
6537       gtk_window_set_gravity (window, grav);
6538       gtk_window_move (window, x, y);
6539       pos_set = TRUE;
6540     }
6541
6542   if (size_set || pos_set)
6543     {
6544       /* Set USSize, USPosition hints */
6545       GtkWindowGeometryInfo *info;
6546
6547       info = gtk_window_get_geometry_info (window, TRUE);
6548
6549       if (pos_set)
6550         info->mask |= GDK_HINT_USER_POS;
6551       if (size_set)
6552         info->mask |= GDK_HINT_USER_SIZE;
6553     }
6554   
6555   return result != 0;
6556 }
6557
6558 static void
6559 gtk_window_mnemonic_hash_foreach (gpointer key,
6560                                   gpointer value,
6561                                   gpointer data)
6562 {
6563   struct {
6564     GtkWindow *window;
6565     GtkWindowKeysForeachFunc func;
6566     gpointer func_data;
6567   } *info = data;
6568
6569   GtkWindowMnemonic *mnemonic = value;
6570
6571   if (mnemonic->window == info->window)
6572     (*info->func) (info->window, mnemonic->keyval, info->window->mnemonic_modifier, TRUE, info->func_data);
6573 }
6574
6575 void
6576 _gtk_window_keys_foreach (GtkWindow                *window,
6577                           GtkWindowKeysForeachFunc func,
6578                           gpointer                 func_data)
6579 {
6580   GSList *groups;
6581
6582   struct {
6583     GtkWindow *window;
6584     GtkWindowKeysForeachFunc func;
6585     gpointer func_data;
6586   } info;
6587
6588   info.window = window;
6589   info.func = func;
6590   info.func_data = func_data;
6591
6592   g_hash_table_foreach (mnemonic_hash_table,
6593                         gtk_window_mnemonic_hash_foreach,
6594                         &info);
6595
6596   groups = gtk_accel_groups_from_object (G_OBJECT (window));
6597   while (groups)
6598     {
6599       GtkAccelGroup *group = groups->data;
6600       gint i;
6601
6602       for (i = 0; i < group->n_accels; i++)
6603         {
6604           GtkAccelKey *key = &group->priv_accels[i].key;
6605           
6606           if (key->accel_key)
6607             (*func) (window, key->accel_key, key->accel_mods, FALSE, func_data);
6608         }
6609       
6610       groups = groups->next;
6611     }
6612 }
6613
6614 static void
6615 gtk_window_keys_changed (GtkWindow *window)
6616 {
6617   gtk_window_free_key_hash (window);
6618   gtk_window_get_key_hash (window);
6619 }
6620
6621 typedef struct _GtkWindowKeyEntry GtkWindowKeyEntry;
6622
6623 struct _GtkWindowKeyEntry
6624 {
6625   guint keyval;
6626   guint modifiers;
6627   gboolean is_mnemonic;
6628 };
6629
6630 static void
6631 add_to_key_hash (GtkWindow      *window,
6632                  guint           keyval,
6633                  GdkModifierType modifiers,
6634                  gboolean        is_mnemonic,
6635                  gpointer        data)
6636 {
6637   GtkKeyHash *key_hash = data;
6638
6639   GtkWindowKeyEntry *entry = g_new (GtkWindowKeyEntry, 1);
6640
6641   entry->keyval = keyval;
6642   entry->modifiers = modifiers;
6643   entry->is_mnemonic = is_mnemonic;
6644
6645   /* GtkAccelGroup stores lowercased accelerators. To deal
6646    * with this, if <Shift> was specified, uppercase.
6647    */
6648   if (modifiers & GDK_SHIFT_MASK)
6649     {
6650       if (keyval == GDK_Tab)
6651         keyval = GDK_ISO_Left_Tab;
6652       else
6653         keyval = gdk_keyval_to_upper (keyval);
6654     }
6655   
6656   _gtk_key_hash_add_entry (key_hash, keyval, entry->modifiers, entry);
6657 }
6658
6659 static GtkKeyHash *
6660 gtk_window_get_key_hash (GtkWindow *window)
6661 {
6662   GdkScreen *screen = gtk_window_check_screen (window);
6663   GtkKeyHash *key_hash = g_object_get_data (G_OBJECT (window), "gtk-window-key-hash");
6664   
6665   if (key_hash)
6666     return key_hash;
6667   
6668   key_hash = _gtk_key_hash_new (gdk_keymap_get_for_display (gdk_screen_get_display (screen)),
6669                                 (GDestroyNotify)g_free);
6670   _gtk_window_keys_foreach (window, add_to_key_hash, key_hash);
6671   g_object_set_data (G_OBJECT (window), "gtk-window-key-hash", key_hash);
6672
6673   return key_hash;
6674 }
6675
6676 static void
6677 gtk_window_free_key_hash (GtkWindow *window)
6678 {
6679   GtkKeyHash *key_hash = g_object_get_data (G_OBJECT (window), "gtk-window-key-hash");
6680   if (key_hash)
6681     {
6682       _gtk_key_hash_free (key_hash);
6683       g_object_set_data (G_OBJECT (window), "gtk-window-key-hash", NULL);
6684     }
6685 }
6686
6687 /**
6688  * _gtk_window_activate_key:
6689  * @window: a #GtkWindow
6690  * @event: a #GdkEventKey
6691  * 
6692  * Activates mnemonics and accelerators for this #GtKWindow
6693  * 
6694  * Return value: %TRUE if a mnemonic or accelerator was found and activated.
6695  **/
6696 gboolean
6697 _gtk_window_activate_key (GtkWindow   *window,
6698                           GdkEventKey *event)
6699 {
6700   GtkKeyHash *key_hash = g_object_get_data (G_OBJECT (window), "gtk-window-key-hash");
6701   GtkWindowKeyEntry *found_entry = NULL;
6702
6703   if (!key_hash)
6704     {
6705       gtk_window_keys_changed (window);
6706       key_hash = g_object_get_data (G_OBJECT (window), "gtk-window-key-hash");
6707     }
6708   
6709   if (key_hash)
6710     {
6711       GSList *entries = _gtk_key_hash_lookup (key_hash,
6712                                               event->hardware_keycode,
6713                                               event->state & gtk_accelerator_get_default_mod_mask (),
6714                                               event->group);
6715       GSList *tmp_list;
6716
6717       for (tmp_list = entries; tmp_list; tmp_list = tmp_list->next)
6718         {
6719           GtkWindowKeyEntry *entry = tmp_list->data;
6720           if (entry->is_mnemonic)
6721             {
6722               found_entry = entry;
6723               break;
6724             }
6725         }
6726       
6727       if (!found_entry && entries)
6728         found_entry = entries->data;
6729
6730       g_slist_free (entries);
6731     }
6732
6733   if (found_entry)
6734     {
6735       if (found_entry->is_mnemonic)
6736         return gtk_window_mnemonic_activate (window, found_entry->keyval, found_entry->modifiers);
6737       else
6738         return gtk_accel_groups_activate (G_OBJECT (window), found_entry->keyval, found_entry->modifiers);
6739     }
6740   else
6741     return FALSE;
6742 }
6743
6744 static void
6745 window_update_has_focus (GtkWindow *window)
6746 {
6747   GtkWidget *widget = GTK_WIDGET (window);
6748   gboolean has_focus = window->has_toplevel_focus && window->is_active;
6749   
6750   if (has_focus != window->has_focus)
6751     {
6752       window->has_focus = has_focus;
6753       
6754       if (has_focus)
6755         {
6756           if (window->focus_widget &&
6757               window->focus_widget != widget &&
6758               !GTK_WIDGET_HAS_FOCUS (window->focus_widget))
6759             do_focus_change (window->focus_widget, TRUE);       
6760         }
6761       else
6762         {
6763           if (window->focus_widget &&
6764               window->focus_widget != widget &&
6765               GTK_WIDGET_HAS_FOCUS (window->focus_widget))
6766             do_focus_change (window->focus_widget, FALSE);
6767         }
6768     }
6769 }
6770
6771 /**
6772  * _gtk_window_set_is_active:
6773  * @window: a #GtkWindow
6774  * @is_active: %TRUE if the window is in the currently active toplevel
6775  * 
6776  * Internal function that sets whether the #GtkWindow is part
6777  * of the currently active toplevel window (taking into account inter-process
6778  * embedding.)
6779  **/
6780 void
6781 _gtk_window_set_is_active (GtkWindow *window,
6782                            gboolean   is_active)
6783 {
6784   g_return_if_fail (GTK_IS_WINDOW (window));
6785
6786   is_active = is_active != FALSE;
6787
6788   if (is_active != window->is_active)
6789     {
6790       window->is_active = is_active;
6791       window_update_has_focus (window);
6792
6793       g_object_notify (G_OBJECT (window), "is_active");
6794     }
6795 }
6796
6797 /**
6798  * _gtk_window_set_has_toplevel_focus:
6799  * @window: a #GtkWindow
6800  * @has_toplevel_focus: %TRUE if the in
6801  * 
6802  * Internal function that sets whether the keyboard focus for the
6803  * toplevel window (taking into account inter-process embedding.)
6804  **/
6805 void
6806 _gtk_window_set_has_toplevel_focus (GtkWindow *window,
6807                                    gboolean   has_toplevel_focus)
6808 {
6809   g_return_if_fail (GTK_IS_WINDOW (window));
6810   
6811   has_toplevel_focus = has_toplevel_focus != FALSE;
6812
6813   if (has_toplevel_focus != window->has_toplevel_focus)
6814     {
6815       window->has_toplevel_focus = has_toplevel_focus;
6816       window_update_has_focus (window);
6817
6818       g_object_notify (G_OBJECT (window), "has_toplevel_focus");
6819     }
6820 }
6821
6822 /**
6823  * gtk_window_set_auto_startup_notification:
6824  * @setting: %TRUE to automatically do startup notification
6825  *
6826  * By default, after showing the first #GtkWindow for each #GdkScreen,
6827  * GTK+ calls gdk_screen_notify_startup_complete().  Call this
6828  * function to disable the automatic startup notification. You might
6829  * do this if your first window is a splash screen, and you want to
6830  * delay notification until after your real main window has been
6831  * shown, for example.
6832  *
6833  * In that example, you would disable startup notification
6834  * temporarily, show your splash screen, then re-enable it so that
6835  * showing the main window would automatically result in notification.
6836  * 
6837  * Since: 2.2
6838  **/
6839 void
6840 gtk_window_set_auto_startup_notification (gboolean setting)
6841 {
6842   disable_startup_notification = !setting;
6843 }