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