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