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