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