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