]> Pileus Git - ~andy/gtk/blob - gtk/gtkwindow.c
Only optimize out the full configure handling if we got a gratuitous
[~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
3209   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
3210   if (window->frame)
3211     gdk_window_withdraw (window->frame);
3212   else 
3213     gdk_window_withdraw (widget->window);
3214   
3215   window->configure_request_count = 0;
3216   window->configure_notify_received = FALSE;
3217
3218   /* on unmap, we reset the default positioning of the window,
3219    * so it's placed again, but we don't reset the default
3220    * size of the window, so it's remembered.
3221    */
3222   window->need_default_position = TRUE;
3223
3224   info = gtk_window_get_geometry_info (window, FALSE);
3225   if (info)
3226     {
3227       info->initial_pos_set = FALSE;
3228       info->position_constraints_changed = FALSE;
3229     }
3230 }
3231
3232 static void
3233 gtk_window_realize (GtkWidget *widget)
3234 {
3235   GtkWindow *window;
3236   GdkWindow *parent_window;
3237   GdkWindowAttr attributes;
3238   gint attributes_mask;
3239   
3240   window = GTK_WINDOW (widget);
3241
3242   /* ensure widget tree is properly size allocated */
3243   if (widget->allocation.x == -1 &&
3244       widget->allocation.y == -1 &&
3245       widget->allocation.width == 1 &&
3246       widget->allocation.height == 1)
3247     {
3248       GtkRequisition requisition;
3249       GtkAllocation allocation = { 0, 0, 200, 200 };
3250
3251       gtk_widget_size_request (widget, &requisition);
3252       if (requisition.width || requisition.height)
3253         {
3254           /* non-empty window */
3255           allocation.width = requisition.width;
3256           allocation.height = requisition.height;
3257         }
3258       gtk_widget_size_allocate (widget, &allocation);
3259       
3260       _gtk_container_queue_resize (GTK_CONTAINER (widget));
3261
3262       g_return_if_fail (!GTK_WIDGET_REALIZED (widget));
3263     }
3264   
3265   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
3266   
3267   switch (window->type)
3268     {
3269     case GTK_WINDOW_TOPLEVEL:
3270       attributes.window_type = GDK_WINDOW_TOPLEVEL;
3271       break;
3272     case GTK_WINDOW_POPUP:
3273       attributes.window_type = GDK_WINDOW_TEMP;
3274       break;
3275     default:
3276       g_warning (G_STRLOC": Unknown window type %d!", window->type);
3277       break;
3278     }
3279    
3280   attributes.title = window->title;
3281   attributes.wmclass_name = window->wmclass_name;
3282   attributes.wmclass_class = window->wmclass_class;
3283   attributes.wclass = GDK_INPUT_OUTPUT;
3284   attributes.visual = gtk_widget_get_visual (widget);
3285   attributes.colormap = gtk_widget_get_colormap (widget);
3286
3287   if (window->has_frame)
3288     {
3289       attributes.width = widget->allocation.width + window->frame_left + window->frame_right;
3290       attributes.height = widget->allocation.height + window->frame_top + window->frame_bottom;
3291       attributes.event_mask = (GDK_EXPOSURE_MASK |
3292                                GDK_KEY_PRESS_MASK |
3293                                GDK_ENTER_NOTIFY_MASK |
3294                                GDK_LEAVE_NOTIFY_MASK |
3295                                GDK_FOCUS_CHANGE_MASK |
3296                                GDK_STRUCTURE_MASK |
3297                                GDK_BUTTON_MOTION_MASK |
3298                                GDK_POINTER_MOTION_HINT_MASK |
3299                                GDK_BUTTON_PRESS_MASK |
3300                                GDK_BUTTON_RELEASE_MASK);
3301       
3302       attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP;
3303       
3304       window->frame = gdk_window_new (gtk_widget_get_root_window (widget),
3305                                       &attributes, attributes_mask);
3306                                                  
3307       gdk_window_set_user_data (window->frame, widget);
3308       
3309       attributes.window_type = GDK_WINDOW_CHILD;
3310       attributes.x = window->frame_left;
3311       attributes.y = window->frame_top;
3312     
3313       attributes_mask = GDK_WA_X | GDK_WA_Y;
3314
3315       parent_window = window->frame;
3316     }
3317   else
3318     {
3319       attributes_mask = 0;
3320       parent_window = gtk_widget_get_root_window (widget);
3321     }
3322   
3323   attributes.width = widget->allocation.width;
3324   attributes.height = widget->allocation.height;
3325   attributes.event_mask = gtk_widget_get_events (widget);
3326   attributes.event_mask |= (GDK_EXPOSURE_MASK |
3327                             GDK_KEY_PRESS_MASK |
3328                             GDK_KEY_RELEASE_MASK |
3329                             GDK_ENTER_NOTIFY_MASK |
3330                             GDK_LEAVE_NOTIFY_MASK |
3331                             GDK_FOCUS_CHANGE_MASK |
3332                             GDK_STRUCTURE_MASK);
3333
3334   attributes_mask |= GDK_WA_VISUAL | GDK_WA_COLORMAP;
3335   attributes_mask |= (window->title ? GDK_WA_TITLE : 0);
3336   attributes_mask |= (window->wmclass_name ? GDK_WA_WMCLASS : 0);
3337   
3338   widget->window = gdk_window_new (parent_window, &attributes, attributes_mask);
3339     
3340   gdk_window_set_user_data (widget->window, window);
3341       
3342   widget->style = gtk_style_attach (widget->style, widget->window);
3343   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
3344   if (window->frame)
3345     gtk_style_set_background (widget->style, window->frame, GTK_STATE_NORMAL);
3346
3347   /* This is a bad hack to set the window background. */
3348   gtk_window_paint (widget, NULL);
3349   
3350   if (window->transient_parent &&
3351       GTK_WIDGET_REALIZED (window->transient_parent))
3352     gdk_window_set_transient_for (widget->window,
3353                                   GTK_WIDGET (window->transient_parent)->window);
3354
3355   if (window->wm_role)
3356     gdk_window_set_role (widget->window, window->wm_role);
3357   
3358   if (!window->decorated)
3359     gdk_window_set_decorations (widget->window, 0);
3360
3361   gdk_window_set_type_hint (widget->window, window->type_hint);
3362
3363   /* transient_for must be set to allow the modal hint */
3364   if (window->transient_parent && window->modal)
3365     gdk_window_set_modal_hint (widget->window, TRUE);
3366   else
3367     gdk_window_set_modal_hint (widget->window, FALSE);
3368
3369   /* Icons */
3370   gtk_window_realize_icon (window);
3371 }
3372
3373 static void
3374 gtk_window_unrealize (GtkWidget *widget)
3375 {
3376   GtkWindow *window;
3377   GtkWindowGeometryInfo *info;
3378
3379   window = GTK_WINDOW (widget);
3380
3381   /* On unrealize, we reset the size of the window such
3382    * that we will re-apply the default sizing stuff
3383    * next time we show the window.
3384    *
3385    * Default positioning is reset on unmap, instead of unrealize.
3386    */
3387   window->need_default_size = TRUE;
3388   info = gtk_window_get_geometry_info (window, FALSE);
3389   if (info)
3390     {
3391       info->resize_width = -1;
3392       info->resize_height = -1;
3393       info->last.configure_request.x = 0;
3394       info->last.configure_request.y = 0;
3395       info->last.configure_request.width = -1;
3396       info->last.configure_request.height = -1;
3397       /* be sure we reset geom hints on re-realize */
3398       info->last.flags = 0;
3399     }
3400   
3401   if (window->frame)
3402     {
3403       gdk_window_set_user_data (window->frame, NULL);
3404       gdk_window_destroy (window->frame);
3405       window->frame = NULL;
3406     }
3407
3408   /* Icons */
3409   gtk_window_unrealize_icon (window);
3410   
3411   (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
3412 }
3413
3414 static void
3415 gtk_window_size_request (GtkWidget      *widget,
3416                          GtkRequisition *requisition)
3417 {
3418   GtkWindow *window;
3419   GtkBin *bin;
3420
3421   window = GTK_WINDOW (widget);
3422   bin = GTK_BIN (window);
3423   
3424   requisition->width = GTK_CONTAINER (window)->border_width * 2;
3425   requisition->height = GTK_CONTAINER (window)->border_width * 2;
3426
3427   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
3428     {
3429       GtkRequisition child_requisition;
3430       
3431       gtk_widget_size_request (bin->child, &child_requisition);
3432
3433       requisition->width += child_requisition.width;
3434       requisition->height += child_requisition.height;
3435     }
3436 }
3437
3438 static void
3439 gtk_window_size_allocate (GtkWidget     *widget,
3440                           GtkAllocation *allocation)
3441 {
3442   GtkWindow *window;
3443   GtkAllocation child_allocation;
3444
3445   window = GTK_WINDOW (widget);
3446   widget->allocation = *allocation;
3447
3448   if (window->bin.child && GTK_WIDGET_VISIBLE (window->bin.child))
3449     {
3450       child_allocation.x = GTK_CONTAINER (window)->border_width;
3451       child_allocation.y = GTK_CONTAINER (window)->border_width;
3452       child_allocation.width =
3453         MAX (1, (gint)allocation->width - child_allocation.x * 2);
3454       child_allocation.height =
3455         MAX (1, (gint)allocation->height - child_allocation.y * 2);
3456
3457       gtk_widget_size_allocate (window->bin.child, &child_allocation);
3458     }
3459
3460   if (GTK_WIDGET_REALIZED (widget) && window->frame)
3461     {
3462       gdk_window_resize (window->frame,
3463                          allocation->width + window->frame_left + window->frame_right,
3464                          allocation->height + window->frame_top + window->frame_bottom);
3465     }
3466 }
3467
3468 static gint
3469 gtk_window_event (GtkWidget *widget, GdkEvent *event)
3470 {
3471   GtkWindow *window;
3472   gboolean return_val;
3473
3474   window = GTK_WINDOW (widget);
3475
3476   if (window->frame && (event->any.window == window->frame))
3477     {
3478       if ((event->type != GDK_KEY_PRESS) &&
3479           (event->type != GDK_KEY_RELEASE) &&
3480           (event->type != GDK_FOCUS_CHANGE))
3481         {
3482           gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "event");
3483           return_val = FALSE;
3484           gtk_signal_emit (GTK_OBJECT (widget), window_signals[FRAME_EVENT], event, &return_val);
3485           return TRUE;
3486         }
3487       else
3488         {
3489           g_object_unref (event->any.window);
3490           event->any.window = g_object_ref (widget->window);
3491         }
3492     }
3493
3494   return FALSE;
3495 }
3496
3497 static gboolean
3498 gtk_window_frame_event (GtkWindow *window, GdkEvent *event)
3499 {
3500   GdkEventConfigure *configure_event;
3501   GdkRectangle rect;
3502
3503   switch (event->type)
3504     {
3505     case GDK_CONFIGURE:
3506       configure_event = (GdkEventConfigure *)event;
3507       
3508       /* Invalidate the decorations */
3509       rect.x = 0;
3510       rect.y = 0;
3511       rect.width = configure_event->width;
3512       rect.height = configure_event->height;
3513       
3514       gdk_window_invalidate_rect (window->frame, &rect, FALSE);
3515
3516       /* Pass on the (modified) configure event */
3517       configure_event->width -= window->frame_left + window->frame_right;
3518       configure_event->height -= window->frame_top + window->frame_bottom;
3519       return gtk_window_configure_event (GTK_WIDGET (window), configure_event);
3520       break;
3521     default:
3522       break;
3523     }
3524   return FALSE;
3525 }
3526
3527 static gint
3528 gtk_window_configure_event (GtkWidget         *widget,
3529                             GdkEventConfigure *event)
3530 {
3531   GtkWindow *window = GTK_WINDOW (widget);
3532   gboolean expected_reply = window->configure_request_count > 0;
3533
3534   /* window->configure_request_count incremented for each 
3535    * configure request, and decremented to a min of 0 for
3536    * each configure notify.
3537    *
3538    * All it means is that we know we will get at least
3539    * window->configure_request_count more configure notifies.
3540    * We could get more configure notifies than that; some
3541    * of the configure notifies we get may be unrelated to
3542    * the configure requests. But we will get at least
3543    * window->configure_request_count notifies.
3544    */
3545
3546   if (window->configure_request_count > 0)
3547     window->configure_request_count -= 1;
3548   
3549   /* As an optimization, we avoid a resize when possible.
3550    *
3551    * The only times we can avoid a resize are:
3552    *   - we know only the position changed, not the size
3553    *   - we know we have made more requests and so will get more
3554    *     notifies and can wait to resize when we get them
3555    */
3556   
3557   if (!expected_reply &&
3558       (widget->allocation.width == event->width &&
3559        widget->allocation.height == event->height))
3560     return TRUE;
3561
3562   /*
3563    * If we do need to resize, we do that by:
3564    *   - filling in widget->allocation with the new size
3565    *   - setting configure_notify_received to TRUE
3566    *     for use in gtk_window_move_resize()
3567    *   - queueing a resize, leading to invocation of
3568    *     gtk_window_move_resize() in an idle handler
3569    *
3570    */
3571   
3572   window->configure_notify_received = TRUE;
3573   
3574   widget->allocation.width = event->width;
3575   widget->allocation.height = event->height;
3576   
3577   _gtk_container_queue_resize (GTK_CONTAINER (widget));
3578   
3579   return TRUE;
3580 }
3581
3582 /* the accel_key and accel_mods fields of the key have to be setup
3583  * upon calling this function. it'll then return whether that key
3584  * is at all used as accelerator, and if so will OR in the
3585  * accel_flags member of the key.
3586  */
3587 gboolean
3588 _gtk_window_query_nonaccels (GtkWindow      *window,
3589                              guint           accel_key,
3590                              GdkModifierType accel_mods)
3591 {
3592   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
3593
3594   /* movement keys are considered locked accels */
3595   if (!accel_mods)
3596     {
3597       static const guint bindings[] = {
3598         GDK_space, GDK_KP_Space, GDK_Return, GDK_KP_Enter, GDK_Up, GDK_KP_Up, GDK_Down, GDK_KP_Down,
3599         GDK_Left, GDK_KP_Left, GDK_Right, GDK_KP_Right, GDK_Tab, GDK_KP_Tab, GDK_ISO_Left_Tab,
3600       };
3601       guint i;
3602       
3603       for (i = 0; i < G_N_ELEMENTS (bindings); i++)
3604         if (bindings[i] == accel_key)
3605           return TRUE;
3606     }
3607
3608   /* mnemonics are considered locked accels */
3609   if (accel_mods == window->mnemonic_modifier)
3610     {
3611       GtkWindowMnemonic mkey;
3612
3613       mkey.window = window;
3614       mkey.keyval = accel_key;
3615       if (g_hash_table_lookup (mnemonic_hash_table, &mkey))
3616         return TRUE;
3617     }
3618
3619   return FALSE;
3620 }
3621
3622 static gint
3623 gtk_window_key_press_event (GtkWidget   *widget,
3624                             GdkEventKey *event)
3625 {
3626   GtkWindow *window;
3627   GtkWidget *focus;
3628   gboolean handled;
3629
3630   window = GTK_WINDOW (widget);
3631
3632   handled = FALSE;
3633
3634   /* Check for mnemonics and accelerators
3635    */
3636   if (!handled)
3637     handled = _gtk_window_activate_key (window, event);
3638
3639   if (!handled)
3640     {
3641       focus = window->focus_widget;
3642       if (focus)
3643         g_object_ref (focus);
3644       
3645       while (!handled &&
3646              focus && focus != widget &&
3647              gtk_widget_get_toplevel (focus) == widget)
3648         {
3649           GtkWidget *parent;
3650           
3651           if (GTK_WIDGET_IS_SENSITIVE (focus))
3652             handled = gtk_widget_event (focus, (GdkEvent*) event);
3653           
3654           parent = focus->parent;
3655           if (parent)
3656             g_object_ref (parent);
3657           
3658           g_object_unref (focus);
3659           
3660           focus = parent;
3661         }
3662
3663       if (focus)
3664         g_object_unref (focus);
3665     }
3666
3667   /* Chain up, invokes binding set */
3668   if (!handled && GTK_WIDGET_CLASS (parent_class)->key_press_event)
3669     handled = GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
3670
3671   return handled;
3672 }
3673
3674 static gint
3675 gtk_window_key_release_event (GtkWidget   *widget,
3676                               GdkEventKey *event)
3677 {
3678   GtkWindow *window;
3679   gint handled;
3680   
3681   window = GTK_WINDOW (widget);
3682   handled = FALSE;
3683   if (window->focus_widget &&
3684       window->focus_widget != widget &&
3685       GTK_WIDGET_SENSITIVE (window->focus_widget))
3686     {
3687       handled = gtk_widget_event (window->focus_widget, (GdkEvent*) event);
3688     }
3689
3690   if (!handled && GTK_WIDGET_CLASS (parent_class)->key_release_event)
3691     handled = GTK_WIDGET_CLASS (parent_class)->key_release_event (widget, event);
3692
3693   return handled;
3694 }
3695
3696 static void
3697 gtk_window_real_activate_default (GtkWindow *window)
3698 {
3699   gtk_window_activate_default (window);
3700 }
3701
3702 static void
3703 gtk_window_real_activate_focus (GtkWindow *window)
3704 {
3705   gtk_window_activate_focus (window);
3706 }
3707
3708 static void
3709 gtk_window_move_focus (GtkWindow       *window,
3710                        GtkDirectionType dir)
3711 {
3712   gtk_widget_child_focus (GTK_WIDGET (window), dir);
3713   
3714   if (!GTK_CONTAINER (window)->focus_child)
3715     gtk_window_set_focus (window, NULL);
3716 }
3717
3718 static gint
3719 gtk_window_enter_notify_event (GtkWidget        *widget,
3720                                GdkEventCrossing *event)
3721 {
3722   return FALSE;
3723 }
3724
3725 static gint
3726 gtk_window_leave_notify_event (GtkWidget        *widget,
3727                                GdkEventCrossing *event)
3728 {
3729   return FALSE;
3730 }
3731
3732 static void
3733 do_focus_change (GtkWidget *widget,
3734                  gboolean   in)
3735 {
3736   GdkEventFocus fevent;
3737
3738   g_object_ref (widget);
3739    
3740  if (in)
3741     GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
3742   else
3743     GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
3744
3745   fevent.type = GDK_FOCUS_CHANGE;
3746   fevent.window = widget->window;
3747   fevent.in = in;
3748   
3749   gtk_widget_event (widget, (GdkEvent*) &fevent);
3750   
3751   g_object_notify (G_OBJECT (widget), "has_focus");
3752
3753   g_object_unref (widget);
3754 }
3755
3756 static gint
3757 gtk_window_focus_in_event (GtkWidget     *widget,
3758                            GdkEventFocus *event)
3759 {
3760   GtkWindow *window = GTK_WINDOW (widget);
3761
3762   /* It appears spurious focus in events can occur when
3763    *  the window is hidden. So we'll just check to see if
3764    *  the window is visible before actually handling the
3765    *  event
3766    */
3767   if (GTK_WIDGET_VISIBLE (widget))
3768     {
3769       window->has_focus = TRUE;
3770       
3771       if (window->focus_widget &&
3772           window->focus_widget != widget &&
3773           !GTK_WIDGET_HAS_FOCUS (window->focus_widget))
3774         do_focus_change (window->focus_widget, TRUE);   
3775     }
3776
3777   return FALSE;
3778 }
3779
3780 static gint
3781 gtk_window_focus_out_event (GtkWidget     *widget,
3782                             GdkEventFocus *event)
3783 {
3784   GtkWindow *window = GTK_WINDOW (widget);
3785
3786   window->has_focus = FALSE;
3787   
3788   if (window->focus_widget &&
3789       window->focus_widget != widget &&
3790       GTK_WIDGET_HAS_FOCUS (window->focus_widget))
3791     do_focus_change (window->focus_widget, FALSE);
3792
3793   return FALSE;
3794 }
3795
3796 static GdkAtom atom_rcfiles = GDK_NONE;
3797
3798 static void
3799 gtk_window_read_rcfiles (GtkWidget *widget,
3800                          GdkEventClient *event)
3801 {
3802   GList *embedded_windows;
3803
3804   embedded_windows = gtk_object_get_data (GTK_OBJECT (widget), "gtk-embedded");
3805   if (embedded_windows)
3806     {
3807       GdkEventClient sev;
3808       int i;
3809       
3810       for (i = 0; i < 5; i++)
3811         sev.data.l[i] = 0;
3812       sev.data_format = 32;
3813       sev.message_type = atom_rcfiles;
3814       
3815       while (embedded_windows)
3816         {
3817           guint xid = GPOINTER_TO_UINT (embedded_windows->data);
3818           gdk_event_send_client_message_for_display (gtk_widget_get_display (widget), (GdkEvent *) &sev, xid);
3819           embedded_windows = embedded_windows->next;
3820         }
3821     }
3822
3823   gtk_rc_reparse_all_for_settings (gtk_widget_get_settings (widget), FALSE);
3824 }
3825
3826 static gint
3827 gtk_window_client_event (GtkWidget      *widget,
3828                          GdkEventClient *event)
3829 {
3830   if (!atom_rcfiles)
3831     atom_rcfiles = gdk_atom_intern ("_GTK_READ_RCFILES", FALSE);
3832
3833   if (event->message_type == atom_rcfiles) 
3834     gtk_window_read_rcfiles (widget, event);    
3835
3836   return FALSE;
3837 }
3838
3839 static void
3840 gtk_window_check_resize (GtkContainer *container)
3841 {
3842   GtkWindow *window = GTK_WINDOW (container);
3843
3844   if (GTK_WIDGET_VISIBLE (container))
3845     gtk_window_move_resize (window);
3846 }
3847
3848 static gboolean
3849 gtk_window_focus (GtkWidget        *widget,
3850                   GtkDirectionType  direction)
3851 {
3852   GtkBin *bin;
3853   GtkWindow *window;
3854   GtkContainer *container;
3855   GtkWidget *old_focus_child;
3856   GtkWidget *parent;
3857
3858   container = GTK_CONTAINER (widget);
3859   window = GTK_WINDOW (widget);
3860   bin = GTK_BIN (widget);
3861
3862   old_focus_child = container->focus_child;
3863   
3864   /* We need a special implementation here to deal properly with wrapping
3865    * around in the tab chain without the danger of going into an
3866    * infinite loop.
3867    */
3868   if (old_focus_child)
3869     {
3870       if (gtk_widget_child_focus (old_focus_child, direction))
3871         return TRUE;
3872     }
3873
3874   if (window->focus_widget)
3875     {
3876       /* Wrapped off the end, clear the focus setting for the toplpevel */
3877       parent = window->focus_widget->parent;
3878       while (parent)
3879         {
3880           gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
3881           parent = GTK_WIDGET (parent)->parent;
3882         }
3883       
3884       gtk_window_set_focus (GTK_WINDOW (container), NULL);
3885     }
3886
3887   /* Now try to focus the first widget in the window */
3888   if (bin->child)
3889     {
3890       if (gtk_widget_child_focus (bin->child, direction))
3891         return TRUE;
3892     }
3893
3894   return FALSE;
3895 }
3896
3897 static void
3898 gtk_window_real_set_focus (GtkWindow *window,
3899                            GtkWidget *focus)
3900 {
3901   GtkWidget *old_focus = window->focus_widget;
3902   gboolean def_flags = 0;
3903
3904   if (old_focus)
3905     {
3906       g_object_ref (old_focus);
3907       g_object_freeze_notify (G_OBJECT (old_focus));
3908     }
3909   if (focus)
3910     {
3911       g_object_ref (focus);
3912       g_object_freeze_notify (G_OBJECT (focus));
3913     }
3914   
3915   if (window->default_widget)
3916     def_flags = GTK_WIDGET_HAS_DEFAULT (window->default_widget);
3917   
3918   if (window->focus_widget)
3919     {
3920       if (GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget) &&
3921           (window->focus_widget != window->default_widget))
3922         {
3923           GTK_WIDGET_UNSET_FLAGS (window->focus_widget, GTK_HAS_DEFAULT);
3924
3925           if (window->default_widget)
3926             GTK_WIDGET_SET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
3927         }
3928
3929       if (window->has_focus)
3930         do_focus_change (window->focus_widget, FALSE);
3931     }
3932   
3933   window->focus_widget = focus;
3934   
3935   if (window->focus_widget)
3936     {
3937       if (GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget) &&
3938           (window->focus_widget != window->default_widget))
3939         {
3940           if (GTK_WIDGET_CAN_DEFAULT (window->focus_widget))
3941             GTK_WIDGET_SET_FLAGS (window->focus_widget, GTK_HAS_DEFAULT);
3942
3943           if (window->default_widget)
3944             GTK_WIDGET_UNSET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
3945         }
3946
3947       if (window->has_focus)
3948         do_focus_change (window->focus_widget, TRUE);
3949     }
3950   
3951   if (window->default_widget &&
3952       (def_flags != GTK_WIDGET_FLAGS (window->default_widget)))
3953     gtk_widget_queue_draw (window->default_widget);
3954
3955   if (old_focus)
3956     {
3957       g_object_thaw_notify (G_OBJECT (old_focus));
3958       g_object_unref (old_focus);
3959     }
3960   if (focus)
3961     {
3962       g_object_thaw_notify (G_OBJECT (focus));
3963       g_object_unref (focus);
3964     }
3965 }
3966
3967 /*********************************
3968  * Functions related to resizing *
3969  *********************************/
3970
3971 /* This function doesn't constrain to geometry hints */
3972 static void 
3973 gtk_window_compute_configure_request_size (GtkWindow *window,
3974                                            guint     *width,
3975                                            guint     *height)
3976 {
3977   GtkRequisition requisition;
3978   GtkWindowGeometryInfo *info;
3979   GtkWidget *widget;
3980
3981   /* Preconditions:
3982    *  - we've done a size request
3983    */
3984   
3985   widget = GTK_WIDGET (window);
3986
3987   info = gtk_window_get_geometry_info (window, FALSE);
3988   
3989   if (window->need_default_size)
3990     {
3991       gtk_widget_get_child_requisition (widget, &requisition);
3992
3993       /* Default to requisition */
3994       *width = requisition.width;
3995       *height = requisition.height;
3996
3997       /* If window is empty so requests 0, default to random nonzero size */
3998        if (*width == 0 && *height == 0)
3999          {
4000            *width = 200;
4001            *height = 200;
4002          }
4003
4004        /* Override requisition with default size */
4005
4006        if (info)
4007          {
4008            gint base_width = 0;
4009            gint base_height = 0;
4010            gint width_inc = 1;
4011            gint height_inc = 1;
4012            
4013            if (info->default_is_geometry &&
4014                (info->default_width > 0 || info->default_height > 0))
4015              {
4016                GdkGeometry geometry;
4017                guint flags;
4018                
4019                gtk_window_compute_hints (window, &geometry, &flags);
4020
4021                if (flags & GDK_HINT_BASE_SIZE)
4022                  {
4023                    base_width = geometry.base_width;
4024                    base_height = geometry.base_height;
4025                  }
4026                else if (flags & GDK_HINT_MIN_SIZE)
4027                  {
4028                    base_width = geometry.min_width;
4029                    base_height = geometry.min_height;
4030                  }
4031                if (flags & GDK_HINT_RESIZE_INC)
4032                  {
4033                    width_inc = geometry.width_inc;
4034                    height_inc = geometry.height_inc;
4035                  }
4036              }
4037              
4038            if (info->default_width > 0)
4039              *width = info->default_width * width_inc + base_width;
4040            
4041            if (info->default_height > 0)
4042              *height = info->default_height * height_inc + base_height;
4043          }
4044     }
4045   else
4046     {
4047       /* Default to keeping current size */
4048       *width = widget->allocation.width;
4049       *height = widget->allocation.height;
4050     }
4051
4052   /* Override any size with gtk_window_resize() values */
4053   if (info)
4054     {
4055       if (info->resize_width > 0)
4056         *width = info->resize_width;
4057
4058       if (info->resize_height > 0)
4059         *height = info->resize_height;
4060     }
4061 }
4062
4063 static void
4064 gtk_window_compute_configure_request (GtkWindow    *window,
4065                                       GdkRectangle *request,
4066                                       GdkGeometry  *geometry,
4067                                       guint        *flags)
4068 {
4069   GdkGeometry new_geometry;
4070   guint new_flags;
4071   int w, h;
4072   GtkWidget *widget;
4073   GtkWindowPosition pos;
4074   GtkWidget *parent_widget;
4075   GtkWindowGeometryInfo *info;
4076   int x, y;
4077   
4078   widget = GTK_WIDGET (window);
4079   
4080   gtk_widget_size_request (widget, NULL);
4081   gtk_window_compute_configure_request_size (window, &w, &h);
4082   
4083   gtk_window_compute_hints (window, &new_geometry, &new_flags);
4084   gtk_window_constrain_size (window,
4085                              &new_geometry, new_flags,
4086                              w, h,
4087                              &w, &h);
4088
4089   parent_widget = (GtkWidget*) window->transient_parent;
4090   
4091   pos = window->position;
4092   if (pos == GTK_WIN_POS_CENTER_ON_PARENT &&
4093       (parent_widget == NULL ||
4094        !GTK_WIDGET_MAPPED (parent_widget)))
4095     pos = GTK_WIN_POS_NONE;
4096
4097   info = gtk_window_get_geometry_info (window, TRUE);
4098
4099   /* by default, don't change position requested */
4100   x = info->last.configure_request.x;
4101   y = info->last.configure_request.y;
4102   
4103   if (window->need_default_position)
4104     {
4105
4106       /* FIXME this all interrelates with window gravity.
4107        * For most of them I think we want to set GRAVITY_CENTER.
4108        *
4109        * Not sure how to go about that.
4110        */
4111       
4112       switch (pos)
4113         {
4114           /* here we are only handling CENTER_ALWAYS
4115            * as it relates to default positioning,
4116            * where it's equivalent to simply CENTER
4117            */
4118         case GTK_WIN_POS_CENTER_ALWAYS:
4119         case GTK_WIN_POS_CENTER:
4120           {
4121             gint px, py, monitor_num;
4122             GdkRectangle monitor;
4123
4124             gdk_window_get_pointer (gdk_screen_get_root_window (window->screen),
4125                                     &px, &py, NULL);
4126             
4127             monitor_num = gdk_screen_get_monitor_at_point (window->screen, px, py);
4128             if (monitor_num == -1)
4129               monitor_num = 0;
4130             
4131             gdk_screen_get_monitor_geometry (window->screen, monitor_num, &monitor);
4132             
4133             x = (monitor.width - w) / 2 + monitor.x;
4134             y = (monitor.height - h) / 2 + monitor.y;
4135           }
4136           break;
4137       
4138         case GTK_WIN_POS_CENTER_ON_PARENT:
4139           {
4140             gint ox, oy;
4141             
4142             g_assert (GTK_WIDGET_MAPPED (parent_widget)); /* established earlier */
4143             
4144             gdk_window_get_origin (parent_widget->window,
4145                                    &ox, &oy);
4146             
4147             x = ox + (parent_widget->allocation.width - w) / 2;
4148             y = oy + (parent_widget->allocation.height - h) / 2;
4149           }
4150           break;
4151
4152         case GTK_WIN_POS_MOUSE:
4153           {
4154             gint screen_width = gdk_screen_get_width (window->screen);
4155             gint screen_height = gdk_screen_get_height (window->screen);
4156             int px, py;
4157             
4158             gdk_window_get_pointer (NULL, &px, &py, NULL);
4159             x = px - w / 2;
4160             y = py - h / 2;
4161             x = CLAMP (x, 0, screen_width - w);
4162             y = CLAMP (y, 0, screen_height - h);
4163           }
4164           break;
4165
4166         default:
4167           break;
4168         }
4169     } /* if (window->need_default_position) */
4170
4171   if (window->need_default_position &&
4172       info->initial_pos_set)
4173     {
4174       x = info->initial_x;
4175       y = info->initial_y;
4176       gtk_window_constrain_position (window, w, h, &x, &y);
4177     }
4178   
4179   request->x = x;
4180   request->y = y;
4181   request->width = w;
4182   request->height = h;
4183
4184   if (geometry)
4185     *geometry = new_geometry;
4186   if (flags)
4187     *flags = new_flags;
4188 }
4189
4190 static void
4191 gtk_window_constrain_position (GtkWindow    *window,
4192                                gint          new_width,
4193                                gint          new_height,
4194                                gint         *x,
4195                                gint         *y)
4196 {
4197   /* See long comments in gtk_window_move_resize()
4198    * on when it's safe to call this function.
4199    */
4200   if (window->position == GTK_WIN_POS_CENTER_ALWAYS)
4201     {
4202       gint center_x, center_y;
4203       gint screen_width = gdk_screen_get_width (window->screen);
4204       gint screen_height = gdk_screen_get_height (window->screen);
4205       
4206       center_x = (screen_width - new_width) / 2;
4207       center_y = (screen_height - new_height) / 2;
4208       
4209       *x = center_x;
4210       *y = center_y;
4211     }
4212 }
4213
4214 static void
4215 gtk_window_move_resize (GtkWindow *window)
4216 {
4217   /* Overview:
4218    *
4219    * First we determine whether any information has changed that would
4220    * cause us to revise our last configure request.  If we would send
4221    * a different configure request from last time, then
4222    * configure_request_size_changed = TRUE or
4223    * configure_request_pos_changed = TRUE. configure_request_size_changed
4224    * may be true due to new hints, a gtk_window_resize(), or whatever.
4225    * configure_request_pos_changed may be true due to gtk_window_set_position()
4226    * or gtk_window_move().
4227    *
4228    * If the configure request has changed, we send off a new one.  To
4229    * ensure GTK+ invariants are maintained (resize queue does what it
4230    * should), we go ahead and size_allocate the requested size in this
4231    * function.
4232    *
4233    * If the configure request has not changed, we don't ever resend
4234    * it, because it could mean fighting the user or window manager.
4235    *
4236    * 
4237    *   To prepare the configure request, we come up with a base size/pos:
4238    *      - the one from gtk_window_move()/gtk_window_resize()
4239    *      - else default_width, default_height if we haven't ever
4240    *        been mapped
4241    *      - else the size request if we haven't ever been mapped,
4242    *        as a substitute default size
4243    *      - else the current size of the window, as received from
4244    *        configure notifies (i.e. the current allocation)
4245    *
4246    *   If GTK_WIN_POS_CENTER_ALWAYS is active, we constrain
4247    *   the position request to be centered.
4248    */
4249   GtkWidget *widget;
4250   GtkContainer *container;
4251   GtkWindowGeometryInfo *info;
4252   GdkGeometry new_geometry;
4253   guint new_flags;
4254   GdkRectangle new_request;
4255   gboolean configure_request_size_changed;
4256   gboolean configure_request_pos_changed;
4257   gboolean hints_changed; /* do we need to send these again */
4258   GtkWindowLastGeometryInfo saved_last_info;
4259   
4260   widget = GTK_WIDGET (window);
4261   container = GTK_CONTAINER (widget);
4262   info = gtk_window_get_geometry_info (window, TRUE);
4263   
4264   configure_request_size_changed = FALSE;
4265   configure_request_pos_changed = FALSE;
4266   
4267   gtk_window_compute_configure_request (window, &new_request,
4268                                         &new_geometry, &new_flags);  
4269   
4270   /* This check implies the invariant that we never set info->last
4271    * without setting the hints and sending off a configure request.
4272    *
4273    * If we change info->last without sending the request, we may
4274    * miss a request.
4275    */
4276   if (info->last.configure_request.x != new_request.x ||
4277       info->last.configure_request.y != new_request.y)
4278     configure_request_pos_changed = TRUE;
4279
4280   if ((info->last.configure_request.width != new_request.width ||
4281        info->last.configure_request.height != new_request.height))
4282     configure_request_size_changed = TRUE;
4283   
4284   hints_changed = FALSE;
4285   
4286   if (!gtk_window_compare_hints (&info->last.geometry, info->last.flags,
4287                                  &new_geometry, new_flags))
4288     {
4289       hints_changed = TRUE;
4290     }
4291   
4292   /* Position Constraints
4293    * ====================
4294    * 
4295    * POS_CENTER_ALWAYS is conceptually a constraint rather than
4296    * a default. The other POS_ values are used only when the
4297    * window is shown, not after that.
4298    * 
4299    * However, we can't implement a position constraint as
4300    * "anytime the window size changes, center the window"
4301    * because this may well end up fighting the WM or user.  In
4302    * fact it gets in an infinite loop with at least one WM.
4303    *
4304    * Basically, applications are in no way in a position to
4305    * constrain the position of a window, with one exception:
4306    * override redirect windows. (Really the intended purpose
4307    * of CENTER_ALWAYS anyhow, I would think.)
4308    *
4309    * So the way we implement this "constraint" is to say that when WE
4310    * cause a move or resize, i.e. we make a configure request changing
4311    * window size, we recompute the CENTER_ALWAYS position to reflect
4312    * the new window size, and include it in our request.  Also, if we
4313    * just turned on CENTER_ALWAYS we snap to center with a new
4314    * request.  Otherwise, if we are just NOTIFIED of a move or resize
4315    * done by someone else e.g. the window manager, we do NOT send a
4316    * new configure request.
4317    *
4318    * For override redirect windows, this works fine; all window
4319    * sizes are from our configure requests. For managed windows,
4320    * it is at least semi-sane, though who knows what the
4321    * app author is thinking.
4322    */
4323
4324   /* This condition should be kept in sync with the condition later on
4325    * that determines whether we send a configure request.  i.e. we
4326    * should do this position constraining anytime we were going to
4327    * send a configure request anyhow, plus when constraints have
4328    * changed.
4329    */
4330   if (configure_request_pos_changed ||
4331       configure_request_size_changed ||
4332       hints_changed ||
4333       info->position_constraints_changed)
4334     {
4335       /* We request the constrained position if:
4336        *  - we were changing position, and need to clamp
4337        *    the change to the constraint
4338        *  - we're changing the size anyway
4339        *  - set_position() was called to toggle CENTER_ALWAYS on
4340        */
4341
4342       gtk_window_constrain_position (window,
4343                                      new_request.width,
4344                                      new_request.height,
4345                                      &new_request.x,
4346                                      &new_request.y);
4347       
4348       /* Update whether we need to request a move */
4349       if (info->last.configure_request.x != new_request.x ||
4350           info->last.configure_request.y != new_request.y)
4351         configure_request_pos_changed = TRUE;
4352       else
4353         configure_request_pos_changed = FALSE;
4354     }
4355
4356 #if 0
4357   if (window->type == GTK_WINDOW_TOPLEVEL)
4358     {
4359       int notify_x, notify_y;
4360
4361       /* this is the position from the last configure notify */
4362       gdk_window_get_position (widget->window, &notify_x, &notify_y);
4363     
4364       g_message ("--- %s ---\n"
4365                  "last  : %d,%d\t%d x %d\n"
4366                  "this  : %d,%d\t%d x %d\n"
4367                  "alloc : %d,%d\t%d x %d\n"
4368                  "req   :      \t%d x %d\n"
4369                  "resize:      \t%d x %d\n" 
4370                  "size_changed: %d pos_changed: %d hints_changed: %d\n"
4371                  "configure_notify_received: %d\n"
4372                  "configure_request_count: %d\n"
4373                  "position_constraints_changed: %d\n",
4374                  window->title ? window->title : "(no title)",
4375                  info->last.configure_request.x,
4376                  info->last.configure_request.y,
4377                  info->last.configure_request.width,
4378                  info->last.configure_request.height,
4379                  new_request.x,
4380                  new_request.y,
4381                  new_request.width,
4382                  new_request.height,
4383                  notify_x, notify_y,
4384                  widget->allocation.width,
4385                  widget->allocation.height,
4386                  widget->requisition.width,
4387                  widget->requisition.height,
4388                  info->resize_width,
4389                  info->resize_height,
4390                  configure_request_pos_changed,
4391                  configure_request_size_changed,
4392                  hints_changed,
4393                  window->configure_notify_received,
4394                  window->configure_request_count,
4395                  info->position_constraints_changed);
4396     }
4397 #endif
4398   
4399   saved_last_info = info->last;
4400   info->last.geometry = new_geometry;
4401   info->last.flags = new_flags;
4402   info->last.configure_request = new_request;
4403   
4404   /* need to set PPosition so the WM will look at our position,
4405    * but we don't want to count PPosition coming and going as a hints
4406    * change for future iterations. So we saved info->last prior to
4407    * this.
4408    */
4409   
4410   /* Also, if the initial position was explicitly set, then we always
4411    * toggle on PPosition. This makes gtk_window_move(window, 0, 0)
4412    * work.
4413    */
4414
4415   /* Also, we toggle on PPosition if GTK_WIN_POS_ is in use and
4416    * this is an initial map
4417    */
4418   
4419   if ((configure_request_pos_changed ||
4420        info->initial_pos_set ||
4421        (window->need_default_position &&
4422         window->position != GTK_WIN_POS_NONE)) &&
4423       (new_flags & GDK_HINT_POS) == 0)
4424     {
4425       new_flags |= GDK_HINT_POS;
4426       hints_changed = TRUE;
4427     }
4428   
4429   /* Set hints if necessary
4430    */
4431   if (hints_changed)
4432     gdk_window_set_geometry_hints (widget->window,
4433                                    &new_geometry,
4434                                    new_flags);
4435   
4436   /* handle resizing/moving and widget tree allocation
4437    */
4438   if (window->configure_notify_received)
4439     { 
4440       GtkAllocation allocation;
4441
4442       /* If we have received a configure event since
4443        * the last time in this function, we need to
4444        * accept our new size and size_allocate child widgets.
4445        * (see gtk_window_configure_event() for more details).
4446        *
4447        * 1 or more configure notifies may have been received.
4448        * Also, configure_notify_received will only be TRUE
4449        * if all expected configure notifies have been received
4450        * (one per configure request), as an optimization.
4451        *
4452        */
4453       window->configure_notify_received = FALSE;
4454
4455       /* gtk_window_configure_event() filled in widget->allocation */
4456       allocation = widget->allocation;
4457       gtk_widget_size_allocate (widget, &allocation);
4458
4459       /* If the configure request changed, it means that
4460        * we either:
4461        *   1) coincidentally changed hints or widget properties
4462        *      impacting the configure request before getting
4463        *      a configure notify, or
4464        *   2) some broken widget is changing its size request
4465        *      during size allocation, resulting in
4466        *      a false appearance of changed configure request.
4467        *
4468        * For 1), we could just go ahead and ask for the
4469        * new size right now, but doing that for 2)
4470        * might well be fighting the user (and can even
4471        * trigger a loop). Since we really don't want to
4472        * do that, we requeue a resize in hopes that
4473        * by the time it gets handled, the child has seen
4474        * the light and is willing to go along with the
4475        * new size. (this happens for the zvt widget, since
4476        * the size_allocate() above will have stored the
4477        * requisition corresponding to the new size in the
4478        * zvt widget)
4479        *
4480        * This doesn't buy us anything for 1), but it shouldn't
4481        * hurt us too badly, since it is what would have
4482        * happened if we had gotten the configure event before
4483        * the new size had been set.
4484        */
4485
4486       if (configure_request_size_changed ||
4487           configure_request_pos_changed)
4488         {
4489           /* Don't change the recorded last info after all, because we
4490            * haven't actually updated to the new info yet - we decided
4491            * to postpone our configure request until later.
4492            */
4493           info->last = saved_last_info;
4494           
4495           gtk_widget_queue_resize (widget); /* migth recurse for GTK_RESIZE_IMMEDIATE */
4496         }
4497     }
4498   else if ((configure_request_size_changed || hints_changed) &&
4499            (widget->allocation.width != new_request.width ||
4500             widget->allocation.height != new_request.height))
4501
4502     {
4503       /* We are in one of the following situations:
4504        * A. configure_request_size_changed
4505        *    our requisition has changed and we need a different window size,
4506        *    so we request it from the window manager.
4507        * B. !configure_request_size_changed && hints_changed
4508        *    the window manager rejects our size, but we have just changed the
4509        *    window manager hints, so there's a chance our request will
4510        *    be honoured this time, so we try again.
4511        *
4512        * However, if the new requisition is the same as the current allocation,
4513        * we don't request it again, since we won't get a ConfigureNotify back from
4514        * the window manager unless it decides to change our requisition. If
4515        * we don't get the ConfigureNotify back, the resize queue will never be run.
4516        */
4517
4518       /* Now send the configure request */
4519       if (configure_request_pos_changed)
4520         {
4521           if (window->frame)
4522             {
4523               gdk_window_move_resize (window->frame,
4524                                       new_request.x - window->frame_left,
4525                                       new_request.y - window->frame_top,
4526                                       new_request.width + window->frame_left + window->frame_right,
4527                                       new_request.height + window->frame_top + window->frame_bottom);
4528               gdk_window_resize (widget->window,
4529                                  new_request.width, new_request.height);
4530             }
4531           else
4532             if (widget->window)
4533               gdk_window_move_resize (widget->window,
4534                                       new_request.x, new_request.y,
4535                                       new_request.width, new_request.height);
4536         }
4537       else  /* only size changed */
4538         {
4539           if (window->frame)
4540             gdk_window_resize (window->frame,
4541                                new_request.width + window->frame_left + window->frame_right,
4542                                new_request.height + window->frame_top + window->frame_bottom);
4543           if (widget->window)
4544             gdk_window_resize (widget->window,
4545                                new_request.width, new_request.height);
4546         }
4547       
4548       /* Increment the number of have-not-yet-received-notify requests */
4549       window->configure_request_count += 1;
4550
4551       /* We have now sent a request since the last position constraint
4552        * change and definitely don't need a an initial size again (not
4553        * resetting this here can lead to infinite loops for
4554        * GTK_RESIZE_IMMEDIATE containers)
4555        */
4556       info->position_constraints_changed = FALSE;
4557       info->initial_pos_set = FALSE;
4558       info->resize_width = -1;
4559       info->resize_height = -1;
4560
4561       /* for GTK_RESIZE_QUEUE toplevels, we are now awaiting a new
4562        * configure event in response to our resizing request.
4563        * the configure event will cause a new resize with
4564        * ->configure_notify_received=TRUE.
4565        * until then, we want to
4566        * - discard expose events
4567        * - coalesce resizes for our children
4568        * - defer any window resizes until the configure event arrived
4569        * to achieve this, we queue a resize for the window, but remove its
4570        * resizing handler, so resizing will not be handled from the next
4571        * idle handler but when the configure event arrives.
4572        *
4573        * FIXME: we should also dequeue the pending redraws here, since
4574        * we handle those ourselves upon ->configure_notify_received==TRUE.
4575        */
4576       if (container->resize_mode == GTK_RESIZE_QUEUE)
4577         {
4578           gtk_widget_queue_resize (widget);
4579           _gtk_container_dequeue_resize_handler (container);
4580         }
4581     }
4582   else
4583     {
4584       /* Handle any position changes.
4585        */
4586       if (configure_request_pos_changed)
4587         {
4588           if (window->frame)
4589             {
4590               gdk_window_move (window->frame,
4591                                new_request.x - window->frame_left,
4592                                new_request.y - window->frame_top);
4593             }
4594           else
4595             gdk_window_move (widget->window,
4596                              new_request.x, new_request.y);
4597         }
4598       
4599       /* And run the resize queue.
4600        */
4601       gtk_container_resize_children (container);
4602     }
4603 }
4604
4605 /* Compare two sets of Geometry hints for equality.
4606  */
4607 static gboolean
4608 gtk_window_compare_hints (GdkGeometry *geometry_a,
4609                           guint        flags_a,
4610                           GdkGeometry *geometry_b,
4611                           guint        flags_b)
4612 {
4613   if (flags_a != flags_b)
4614     return FALSE;
4615   
4616   if ((flags_a & GDK_HINT_MIN_SIZE) &&
4617       (geometry_a->min_width != geometry_b->min_width ||
4618        geometry_a->min_height != geometry_b->min_height))
4619     return FALSE;
4620
4621   if ((flags_a & GDK_HINT_MAX_SIZE) &&
4622       (geometry_a->max_width != geometry_b->max_width ||
4623        geometry_a->max_height != geometry_b->max_height))
4624     return FALSE;
4625
4626   if ((flags_a & GDK_HINT_BASE_SIZE) &&
4627       (geometry_a->base_width != geometry_b->base_width ||
4628        geometry_a->base_height != geometry_b->base_height))
4629     return FALSE;
4630
4631   if ((flags_a & GDK_HINT_ASPECT) &&
4632       (geometry_a->min_aspect != geometry_b->min_aspect ||
4633        geometry_a->max_aspect != geometry_b->max_aspect))
4634     return FALSE;
4635
4636   if ((flags_a & GDK_HINT_RESIZE_INC) &&
4637       (geometry_a->width_inc != geometry_b->width_inc ||
4638        geometry_a->height_inc != geometry_b->height_inc))
4639     return FALSE;
4640
4641   if ((flags_a & GDK_HINT_WIN_GRAVITY) &&
4642       geometry_a->win_gravity != geometry_b->win_gravity)
4643     return FALSE;
4644
4645   return TRUE;
4646 }
4647
4648 void
4649 _gtk_window_constrain_size (GtkWindow   *window,
4650                             gint         width,
4651                             gint         height,
4652                             gint        *new_width,
4653                             gint        *new_height)
4654 {
4655   GtkWindowGeometryInfo *info;
4656
4657   g_return_if_fail (GTK_IS_WINDOW (window));
4658
4659   info = window->geometry_info;
4660   if (info)
4661     {
4662       GdkWindowHints flags = info->last.flags;
4663       GdkGeometry *geometry = &info->last.geometry;
4664       
4665       gtk_window_constrain_size (window,
4666                                  geometry,
4667                                  flags,
4668                                  width,
4669                                  height,
4670                                  new_width,
4671                                  new_height);
4672     }
4673 }
4674
4675 static void 
4676 gtk_window_constrain_size (GtkWindow   *window,
4677                            GdkGeometry *geometry,
4678                            guint        flags,
4679                            gint         width,
4680                            gint         height,
4681                            gint        *new_width,
4682                            gint        *new_height)
4683 {
4684   gdk_window_constrain_size (geometry, flags, width, height,
4685                              new_width, new_height);
4686 }
4687
4688 /* Compute the set of geometry hints and flags for a window
4689  * based on the application set geometry, and requisiition
4690  * of the window. gtk_widget_size_request() must have been
4691  * called first.
4692  */
4693 static void
4694 gtk_window_compute_hints (GtkWindow   *window,
4695                           GdkGeometry *new_geometry,
4696                           guint       *new_flags)
4697 {
4698   GtkWidget *widget;
4699   gint extra_width = 0;
4700   gint extra_height = 0;
4701   GtkWindowGeometryInfo *geometry_info;
4702   GtkRequisition requisition;
4703
4704   widget = GTK_WIDGET (window);
4705   
4706   gtk_widget_get_child_requisition (widget, &requisition);
4707   geometry_info = gtk_window_get_geometry_info (GTK_WINDOW (widget), FALSE);
4708
4709   if (geometry_info)
4710     {
4711       *new_flags = geometry_info->mask;
4712       *new_geometry = geometry_info->geometry;
4713     }
4714   else
4715     {
4716       *new_flags = 0;
4717     }
4718   
4719   if (geometry_info && geometry_info->widget)
4720     {
4721       GtkRequisition child_requisition;
4722
4723       /* FIXME: This really isn't right. It gets the min size wrong and forces
4724        * callers to do horrible hacks like set a huge usize on the child requisition
4725        * to get the base size right. We really want to find the answers to:
4726        *
4727        *  - If the geometry widget was infinitely big, how much extra space
4728        *    would be needed for the stuff around it.
4729        *
4730        *  - If the geometry widget was infinitely small, how big would the
4731        *    window still have to be.
4732        *
4733        * Finding these answers would be a bit of a mess here. (Bug #68668)
4734        */
4735       gtk_widget_get_child_requisition (geometry_info->widget, &child_requisition);
4736       
4737       extra_width = widget->requisition.width - child_requisition.width;
4738       extra_height = widget->requisition.height - child_requisition.height;
4739     }
4740
4741   /* We don't want to set GDK_HINT_POS in here, we just set it
4742    * in gtk_window_move_resize() when we want the position
4743    * honored.
4744    */
4745   
4746   if (*new_flags & GDK_HINT_BASE_SIZE)
4747     {
4748       new_geometry->base_width += extra_width;
4749       new_geometry->base_height += extra_height;
4750     }
4751   else if (!(*new_flags & GDK_HINT_MIN_SIZE) &&
4752            (*new_flags & GDK_HINT_RESIZE_INC) &&
4753            ((extra_width != 0) || (extra_height != 0)))
4754     {
4755       *new_flags |= GDK_HINT_BASE_SIZE;
4756       
4757       new_geometry->base_width = extra_width;
4758       new_geometry->base_height = extra_height;
4759     }
4760   
4761   if (*new_flags & GDK_HINT_MIN_SIZE)
4762     {
4763       if (new_geometry->min_width < 0)
4764         new_geometry->min_width = requisition.width;
4765       else
4766         new_geometry->min_width += extra_width;
4767
4768       if (new_geometry->min_height < 0)
4769         new_geometry->min_height = requisition.height;
4770       else
4771         new_geometry->min_height += extra_height;
4772     }
4773   else if (!window->allow_shrink)
4774     {
4775       *new_flags |= GDK_HINT_MIN_SIZE;
4776       
4777       new_geometry->min_width = requisition.width;
4778       new_geometry->min_height = requisition.height;
4779     }
4780   
4781   if (*new_flags & GDK_HINT_MAX_SIZE)
4782     {
4783       if (new_geometry->max_width < 0)
4784         new_geometry->max_width = requisition.width;
4785       else
4786         new_geometry->max_width += extra_width;
4787
4788       if (new_geometry->max_height < 0)
4789         new_geometry->max_width = requisition.height;
4790       else
4791         new_geometry->max_height += extra_height;
4792     }
4793   else if (!window->allow_grow)
4794     {
4795       *new_flags |= GDK_HINT_MAX_SIZE;
4796       
4797       new_geometry->max_width = requisition.width;
4798       new_geometry->max_height = requisition.height;
4799     }
4800
4801   *new_flags |= GDK_HINT_WIN_GRAVITY;
4802   new_geometry->win_gravity = window->gravity;
4803 }
4804
4805 /***********************
4806  * Redrawing functions *
4807  ***********************/
4808
4809 static void
4810 gtk_window_paint (GtkWidget     *widget,
4811                   GdkRectangle *area)
4812 {
4813   gtk_paint_flat_box (widget->style, widget->window, GTK_STATE_NORMAL, 
4814                       GTK_SHADOW_NONE, area, widget, "base", 0, 0, -1, -1);
4815 }
4816
4817 static gint
4818 gtk_window_expose (GtkWidget      *widget,
4819                    GdkEventExpose *event)
4820 {
4821   if (!GTK_WIDGET_APP_PAINTABLE (widget))
4822     gtk_window_paint (widget, &event->area);
4823   
4824   if (GTK_WIDGET_CLASS (parent_class)->expose_event)
4825     return GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
4826
4827   return FALSE;
4828 }
4829
4830 /**
4831  * gtk_window_set_has_frame:
4832  * @window: a #GtkWindow
4833  * @setting: a boolean
4834  *
4835  * (Note: this is a special-purpose function for the framebuffer port,
4836  *  that causes GTK+ to draw its own window border. For most applications,
4837  *  you want gtk_window_set_decorated() instead, which tells the window
4838  *  manager whether to draw the window border.)
4839  * 
4840  * If this function is called on a window with setting of %TRUE, before
4841  * it is realized or showed, it will have a "frame" window around
4842  * @window->window, accessible in @window->frame. Using the signal 
4843  * frame_event you can recieve all events targeted at the frame.
4844  * 
4845  * This function is used by the linux-fb port to implement managed
4846  * windows, but it could concievably be used by X-programs that
4847  * want to do their own window decorations.
4848  *
4849  **/
4850 void
4851 gtk_window_set_has_frame (GtkWindow *window, 
4852                           gboolean   setting)
4853 {
4854   g_return_if_fail (GTK_IS_WINDOW (window));
4855   g_return_if_fail (!GTK_WIDGET_REALIZED (window));
4856
4857   window->has_frame = setting != FALSE;
4858 }
4859
4860 /**
4861  * gtk_window_get_has_frame:
4862  * @window: a #GtkWindow
4863  * 
4864  * Accessor for whether the window has a frame window exterior to
4865  * @window->window. Gets the value set by gtk_window_set_has_frame ().
4866  *
4867  * Return value: %TRUE if a frame has been added to the window
4868  *   via gtk_window_set_has_frame().
4869  **/
4870 gboolean
4871 gtk_window_get_has_frame (GtkWindow *window)
4872 {
4873   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
4874
4875   return window->has_frame;
4876 }
4877
4878 /**
4879  * gtk_window_set_frame_dimensions:
4880  * @window: a #GtkWindow that has a frame
4881  * @left: The width of the left border
4882  * @top: The height of the top border
4883  * @right: The width of the right border
4884  * @bottom: The height of the bottom border
4885  *
4886  * (Note: this is a special-purpose function intended for the framebuffer
4887  *  port; see gtk_window_set_has_frame(). It will have no effect on the
4888  *  window border drawn by the window manager, which is the normal
4889  *  case when using the X Window system.)
4890  *
4891  * For windows with frames (see gtk_window_set_has_frame()) this function
4892  * can be used to change the size of the frame border.
4893  **/
4894 void
4895 gtk_window_set_frame_dimensions (GtkWindow *window, 
4896                                  gint       left,
4897                                  gint       top,
4898                                  gint       right,
4899                                  gint       bottom)
4900 {
4901   GtkWidget *widget;
4902
4903   g_return_if_fail (GTK_IS_WINDOW (window));
4904
4905   widget = GTK_WIDGET (window);
4906
4907   if (window->frame_left == left &&
4908       window->frame_top == top &&
4909       window->frame_right == right && 
4910       window->frame_bottom == bottom)
4911     return;
4912
4913   window->frame_left = left;
4914   window->frame_top = top;
4915   window->frame_right = right;
4916   window->frame_bottom = bottom;
4917
4918   if (GTK_WIDGET_REALIZED (widget) && window->frame)
4919     {
4920       gint width = widget->allocation.width + left + right;
4921       gint height = widget->allocation.height + top + bottom;
4922       gdk_window_resize (window->frame, width, height);
4923       gtk_decorated_window_move_resize_window (window,
4924                                                left, top,
4925                                                widget->allocation.width,
4926                                                widget->allocation.height);
4927     }
4928 }
4929
4930 /**
4931  * gtk_window_present:
4932  * @window: a #GtkWindow
4933  *
4934  * Presents a window to the user. This may mean raising the window
4935  * in the stacking order, deiconifying it, moving it to the current
4936  * desktop, and/or giving it the keyboard focus, possibly dependent
4937  * on the user's platform, window manager, and preferences.
4938  *
4939  * If @window is hidden, this function calls gtk_widget_show()
4940  * as well.
4941  * 
4942  * This function should be used when the user tries to open a window
4943  * that's already open. Say for example the preferences dialog is
4944  * currently open, and the user chooses Preferences from the menu
4945  * a second time; use gtk_window_present() to move the already-open dialog
4946  * where the user can see it.
4947  * 
4948  **/
4949 void
4950 gtk_window_present (GtkWindow *window)
4951 {
4952   GtkWidget *widget;
4953
4954   g_return_if_fail (GTK_IS_WINDOW (window));
4955
4956   widget = GTK_WIDGET (window);
4957
4958   if (GTK_WIDGET_VISIBLE (window))
4959     {
4960       g_assert (widget->window != NULL);
4961       
4962       gdk_window_show (widget->window);
4963
4964       /* note that gdk_window_focus() will also move the window to
4965        * the current desktop, for WM spec compliant window managers.
4966        */
4967       gdk_window_focus (widget->window,
4968                         gtk_get_current_event_time ());
4969     }
4970   else
4971     {
4972       gtk_widget_show (widget);
4973     }
4974 }
4975
4976 /**
4977  * gtk_window_iconify:
4978  * @window: a #GtkWindow
4979  *
4980  * Asks to iconify (i.e. minimize) the specified @window. Note that
4981  * you shouldn't assume the window is definitely iconified afterward,
4982  * because other entities (e.g. the user or <link
4983  * linkend="gtk-X11-arch">window manager</link>) could deiconify it
4984  * again, or there may not be a window manager in which case
4985  * iconification isn't possible, etc. But normally the window will end
4986  * up iconified. Just don't write code that crashes if not.
4987  *
4988  * It's permitted to call this function before showing a window,
4989  * in which case the window will be iconified before it ever appears
4990  * onscreen.
4991  *
4992  * You can track iconification via the "window_state_event" signal
4993  * on #GtkWidget.
4994  * 
4995  **/
4996 void
4997 gtk_window_iconify (GtkWindow *window)
4998 {
4999   GtkWidget *widget;
5000   GdkWindow *toplevel;
5001   
5002   g_return_if_fail (GTK_IS_WINDOW (window));
5003
5004   widget = GTK_WIDGET (window);
5005
5006   window->iconify_initially = TRUE;
5007
5008   if (window->frame)
5009     toplevel = window->frame;
5010   else
5011     toplevel = widget->window;
5012   
5013   if (toplevel != NULL)
5014     gdk_window_iconify (toplevel);
5015 }
5016
5017 /**
5018  * gtk_window_deiconify:
5019  * @window: a #GtkWindow
5020  *
5021  * Asks to deiconify (i.e. unminimize) the specified @window. Note
5022  * that you shouldn't assume the window is definitely deiconified
5023  * afterward, because other entities (e.g. the user or <link
5024  * linkend="gtk-X11-arch">window manager</link>) could iconify it
5025  * again before your code which assumes deiconification gets to run.
5026  *
5027  * You can track iconification via the "window_state_event" signal
5028  * on #GtkWidget.
5029  **/
5030 void
5031 gtk_window_deiconify (GtkWindow *window)
5032 {
5033   GtkWidget *widget;
5034   GdkWindow *toplevel;
5035   
5036   g_return_if_fail (GTK_IS_WINDOW (window));
5037
5038   widget = GTK_WIDGET (window);
5039
5040   window->iconify_initially = FALSE;
5041
5042   if (window->frame)
5043     toplevel = window->frame;
5044   else
5045     toplevel = widget->window;
5046   
5047   if (toplevel != NULL)
5048     gdk_window_deiconify (toplevel);
5049 }
5050
5051 /**
5052  * gtk_window_stick:
5053  * @window: a #GtkWindow
5054  *
5055  * Asks to stick @window, which means that it will appear on all user
5056  * desktops. Note that you shouldn't assume the window is definitely
5057  * stuck afterward, because other entities (e.g. the user or <link
5058  * linkend="gtk-X11-arch">window manager</link>) could unstick it
5059  * again, and some window managers do not support sticking
5060  * windows. But normally the window will end up stuck. Just don't
5061  * write code that crashes if not.
5062  *
5063  * It's permitted to call this function before showing a window.
5064  *
5065  * You can track stickiness via the "window_state_event" signal
5066  * on #GtkWidget.
5067  * 
5068  **/
5069 void
5070 gtk_window_stick (GtkWindow *window)
5071 {
5072   GtkWidget *widget;
5073   GdkWindow *toplevel;
5074   
5075   g_return_if_fail (GTK_IS_WINDOW (window));
5076
5077   widget = GTK_WIDGET (window);
5078
5079   window->stick_initially = TRUE;
5080
5081   if (window->frame)
5082     toplevel = window->frame;
5083   else
5084     toplevel = widget->window;
5085   
5086   if (toplevel != NULL)
5087     gdk_window_stick (toplevel);
5088 }
5089
5090 /**
5091  * gtk_window_unstick:
5092  * @window: a #GtkWindow
5093  *
5094  * Asks to unstick @window, which means that it will appear on only
5095  * one of the user's desktops. Note that you shouldn't assume the
5096  * window is definitely unstuck afterward, because other entities
5097  * (e.g. the user or <link linkend="gtk-X11-arch">window
5098  * manager</link>) could stick it again. But normally the window will
5099  * end up stuck. Just don't write code that crashes if not.
5100  *
5101  * You can track stickiness via the "window_state_event" signal
5102  * on #GtkWidget.
5103  * 
5104  **/
5105 void
5106 gtk_window_unstick (GtkWindow *window)
5107 {
5108   GtkWidget *widget;
5109   GdkWindow *toplevel;
5110   
5111   g_return_if_fail (GTK_IS_WINDOW (window));
5112
5113   widget = GTK_WIDGET (window);
5114
5115   window->stick_initially = FALSE;
5116
5117   if (window->frame)
5118     toplevel = window->frame;
5119   else
5120     toplevel = widget->window;
5121   
5122   if (toplevel != NULL)
5123     gdk_window_unstick (toplevel);
5124 }
5125
5126 /**
5127  * gtk_window_maximize:
5128  * @window: a #GtkWindow
5129  *
5130  * Asks to maximize @window, so that it becomes full-screen. Note that
5131  * you shouldn't assume the window is definitely maximized afterward,
5132  * because other entities (e.g. the user or <link
5133  * linkend="gtk-X11-arch">window manager</link>) could unmaximize it
5134  * again, and not all window managers support maximization. But
5135  * normally the window will end up maximized. Just don't write code
5136  * that crashes if not.
5137  *
5138  * It's permitted to call this function before showing a window,
5139  * in which case the window will be maximized when it appears onscreen
5140  * initially.
5141  *
5142  * You can track maximization via the "window_state_event" signal
5143  * on #GtkWidget.
5144  * 
5145  **/
5146 void
5147 gtk_window_maximize (GtkWindow *window)
5148 {
5149   GtkWidget *widget;
5150   GdkWindow *toplevel;
5151   
5152   g_return_if_fail (GTK_IS_WINDOW (window));
5153
5154   widget = GTK_WIDGET (window);
5155
5156   window->maximize_initially = TRUE;
5157
5158   if (window->frame)
5159     toplevel = window->frame;
5160   else
5161     toplevel = widget->window;
5162   
5163   if (toplevel != NULL)
5164     gdk_window_maximize (toplevel);
5165 }
5166
5167 /**
5168  * gtk_window_unmaximize:
5169  * @window: a #GtkWindow
5170  *
5171  * Asks to unmaximize @window. Note that you shouldn't assume the
5172  * window is definitely unmaximized afterward, because other entities
5173  * (e.g. the user or <link linkend="gtk-X11-arch">window
5174  * manager</link>) could maximize it again, and not all window
5175  * managers honor requests to unmaximize. But normally the window will
5176  * end up unmaximized. Just don't write code that crashes if not.
5177  *
5178  * You can track maximization via the "window_state_event" signal
5179  * on #GtkWidget.
5180  * 
5181  **/
5182 void
5183 gtk_window_unmaximize (GtkWindow *window)
5184 {
5185   GtkWidget *widget;
5186   GdkWindow *toplevel;
5187   
5188   g_return_if_fail (GTK_IS_WINDOW (window));
5189
5190   widget = GTK_WIDGET (window);
5191
5192   window->maximize_initially = FALSE;
5193
5194   if (window->frame)
5195     toplevel = window->frame;
5196   else
5197     toplevel = widget->window;
5198   
5199   if (toplevel != NULL)
5200     gdk_window_unmaximize (toplevel);
5201 }
5202
5203 /**
5204  * gtk_window_set_resizable:
5205  * @window: a #GtkWindow
5206  * @resizable: %TRUE if the user can resize this window
5207  *
5208  * Sets whether the user can resize a window. Windows are user resizable
5209  * by default.
5210  **/
5211 void
5212 gtk_window_set_resizable (GtkWindow *window,
5213                           gboolean   resizable)
5214 {
5215   g_return_if_fail (GTK_IS_WINDOW (window));
5216
5217   gtk_window_set_policy (window, FALSE, resizable, FALSE);
5218 }
5219
5220 /**
5221  * gtk_window_get_resizable:
5222  * @window: a #GtkWindow
5223  *
5224  * Gets the value set by gtk_window_set_resizable().
5225  *
5226  * Return value: %TRUE if the user can resize the window
5227  **/
5228 gboolean
5229 gtk_window_get_resizable (GtkWindow *window)
5230 {
5231   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
5232
5233   /* allow_grow is most likely to indicate the semantic concept we
5234    * mean by "resizable" (and will be a reliable indicator if
5235    * set_policy() hasn't been called)
5236    */
5237   return window->allow_grow;
5238 }
5239
5240 /**
5241  * gtk_window_set_gravity:
5242  * @window: a #GtkWindow
5243  * @gravity: window gravity
5244  *
5245  * Window gravity defines the meaning of coordinates passed to
5246  * gtk_window_move(). See gtk_window_move() and #GdkGravity for
5247  * more details.
5248  *
5249  * The default window gravity is #GDK_GRAVITY_NORTH_WEST which will
5250  * typically "do what you mean."
5251  *
5252  **/
5253 void
5254 gtk_window_set_gravity (GtkWindow *window,
5255                         GdkGravity gravity)
5256 {
5257   g_return_if_fail (GTK_IS_WINDOW (window));
5258
5259   if (gravity != window->gravity)
5260     {
5261       window->gravity = gravity;
5262
5263       /* gtk_window_move_resize() will adapt gravity
5264        */
5265       gtk_widget_queue_resize (GTK_WIDGET (window));
5266     }
5267 }
5268
5269 /**
5270  * gtk_window_get_gravity:
5271  * @window: a #GtkWindow
5272  *
5273  * Gets the value set by gtk_window_set_gravity().
5274  *
5275  * Return value: window gravity
5276  **/
5277 GdkGravity
5278 gtk_window_get_gravity (GtkWindow *window)
5279 {
5280   g_return_val_if_fail (GTK_IS_WINDOW (window), 0);
5281
5282   return window->gravity;
5283 }
5284
5285 /**
5286  * gtk_window_begin_resize_drag:
5287  * @window: a #GtkWindow
5288  * @button: mouse button that initiated the drag
5289  * @edge: position of the resize control
5290  * @root_x: X position where the user clicked to initiate the drag, in root window coordinates
5291  * @root_y: Y position where the user clicked to initiate the drag
5292  * @timestamp: timestamp from the click event that initiated the drag
5293  *
5294  * Starts resizing a window. This function is used if an application
5295  * has window resizing controls. When GDK can support it, the resize
5296  * will be done using the standard mechanism for the <link
5297  * linkend="gtk-X11-arch">window manager</link> or windowing
5298  * system. Otherwise, GDK will try to emulate window resizing,
5299  * potentially not all that well, depending on the windowing system.
5300  * 
5301  **/
5302 void
5303 gtk_window_begin_resize_drag  (GtkWindow    *window,
5304                                GdkWindowEdge edge,
5305                                gint          button,
5306                                gint          root_x,
5307                                gint          root_y,
5308                                guint32       timestamp)
5309 {
5310   GtkWidget *widget;
5311   GdkWindow *toplevel;
5312   
5313   g_return_if_fail (GTK_IS_WINDOW (window));
5314   g_return_if_fail (GTK_WIDGET_VISIBLE (window));
5315   
5316   widget = GTK_WIDGET (window);
5317   
5318   if (window->frame)
5319     toplevel = window->frame;
5320   else
5321     toplevel = widget->window;
5322   
5323   gdk_window_begin_resize_drag (toplevel,
5324                                 edge, button,
5325                                 root_x, root_y,
5326                                 timestamp);
5327 }
5328
5329 /**
5330  * gtk_window_get_frame_dimensions:
5331  * @window: a #GtkWindow
5332  * @left: location to store the width of the frame at the left, or %NULL
5333  * @top: location to store the height of the frame at the top, or %NULL
5334  * @right: location to store the width of the frame at the returns, or %NULL
5335  * @bottom: location to store the height of the frame at the bottom, or %NULL
5336  *
5337  * (Note: this is a special-purpose function intended for the
5338  *  framebuffer port; see gtk_window_set_has_frame(). It will not
5339  *  return the size of the window border drawn by the <link
5340  *  linkend="gtk-X11-arch">window manager</link>, which is the normal
5341  *  case when using a windowing system.  See
5342  *  gdk_window_get_frame_extents() to get the standard window border
5343  *  extents.)
5344  * 
5345  * Retrieves the dimensions of the frame window for this toplevel.
5346  * See gtk_window_set_has_frame(), gtk_window_set_frame_dimensions().
5347  **/
5348 void
5349 gtk_window_get_frame_dimensions (GtkWindow *window,
5350                                  gint      *left,
5351                                  gint      *top,
5352                                  gint      *right,
5353                                  gint      *bottom)
5354 {
5355   g_return_if_fail (GTK_IS_WINDOW (window));
5356
5357   if (left)
5358     *left = window->frame_left;
5359   if (top)
5360     *top = window->frame_top;
5361   if (right)
5362     *right = window->frame_right;
5363   if (bottom)
5364     *bottom = window->frame_bottom;
5365 }
5366
5367 /**
5368  * gtk_window_begin_move_drag:
5369  * @window: a #GtkWindow
5370  * @button: mouse button that initiated the drag
5371  * @root_x: X position where the user clicked to initiate the drag, in root window coordinates
5372  * @root_y: Y position where the user clicked to initiate the drag
5373  * @timestamp: timestamp from the click event that initiated the drag
5374  *
5375  * Starts moving a window. This function is used if an application has
5376  * window movement grips. When GDK can support it, the window movement
5377  * will be done using the standard mechanism for the <link
5378  * linkend="gtk-X11-arch">window manager</link> or windowing
5379  * system. Otherwise, GDK will try to emulate window movement,
5380  * potentially not all that well, depending on the windowing system.
5381  * 
5382  **/
5383 void
5384 gtk_window_begin_move_drag  (GtkWindow *window,
5385                              gint       button,
5386                              gint       root_x,
5387                              gint       root_y,
5388                              guint32    timestamp)
5389 {
5390   GtkWidget *widget;
5391   GdkWindow *toplevel;
5392   
5393   g_return_if_fail (GTK_IS_WINDOW (window));
5394   g_return_if_fail (GTK_WIDGET_VISIBLE (window));
5395   
5396   widget = GTK_WIDGET (window);
5397   
5398   if (window->frame)
5399     toplevel = window->frame;
5400   else
5401     toplevel = widget->window;
5402   
5403   gdk_window_begin_move_drag (toplevel,
5404                               button,
5405                               root_x, root_y,
5406                               timestamp);
5407 }
5408
5409 /** 
5410  * gtk_window_set_screen:
5411  * @window: a #GtkWindow.
5412  * @screen: a #GdkScreen.
5413  *
5414  * Sets the #GdkScreen where the @window is displayed; if
5415  * the window is already mapped, it will be unmapped, and
5416  * then remapped on the new screen.
5417  */
5418 void
5419 gtk_window_set_screen (GtkWindow *window,
5420                        GdkScreen *screen)
5421 {
5422   GtkWidget *widget;
5423   gboolean was_mapped;
5424   
5425   g_return_if_fail (GTK_IS_WINDOW (window));
5426   g_return_if_fail (GDK_IS_SCREEN (screen));
5427
5428   if (screen == window->screen)
5429     return;
5430
5431   widget = GTK_WIDGET (window);
5432   
5433   was_mapped = GTK_WIDGET_MAPPED (widget);
5434
5435   if (was_mapped)
5436     gtk_widget_unmap (widget);
5437   if (GTK_WIDGET_REALIZED (widget))
5438     gtk_widget_unrealize (widget);
5439   
5440   gtk_window_free_key_hash (window);
5441   window->screen = screen;
5442   gtk_widget_reset_rc_styles (widget);
5443   g_object_notify (G_OBJECT (window), "screen");
5444
5445   if (was_mapped)
5446     gtk_widget_map (widget);
5447 }
5448
5449 /** 
5450  * gtk_window_get_screen:
5451  * @window: a #GtkWindow.
5452  *
5453  * Returns the #GdkScreen associated with @window.
5454  *
5455  * Return value: a #GdkScreen.
5456  */
5457 GdkScreen*
5458 gtk_window_get_screen (GtkWindow *window)
5459 {
5460    g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
5461    
5462    return window->screen;
5463 }
5464
5465
5466 static void
5467 gtk_window_group_class_init (GtkWindowGroupClass *klass)
5468 {
5469 }
5470
5471 GtkType
5472 gtk_window_group_get_type (void)
5473 {
5474   static GtkType window_group_type = 0;
5475
5476   if (!window_group_type)
5477     {
5478       static const GTypeInfo window_group_info =
5479       {
5480         sizeof (GtkWindowGroupClass),
5481         NULL,           /* base_init */
5482         NULL,           /* base_finalize */
5483         (GClassInitFunc) gtk_window_group_class_init,
5484         NULL,           /* class_finalize */
5485         NULL,           /* class_data */
5486         sizeof (GtkWindowGroup),
5487         16,             /* n_preallocs */
5488         (GInstanceInitFunc) NULL,
5489       };
5490
5491       window_group_type = g_type_register_static (G_TYPE_OBJECT, "GtkWindowGroup", &window_group_info, 0);
5492     }
5493
5494   return window_group_type;
5495 }
5496
5497 /**
5498  * gtk_window_group_new:
5499  * 
5500  * Creates a new #GtkWindowGroup object. Grabs added with
5501  * gtk_grab_add() only affect windows within the same #GtkWindowGroup.
5502  * 
5503  * Return value: a new #GtkWindowGroup. 
5504  **/
5505 GtkWindowGroup *
5506 gtk_window_group_new (void)
5507 {
5508   return g_object_new (GTK_TYPE_WINDOW_GROUP, NULL);
5509 }
5510
5511 static void
5512 window_group_cleanup_grabs (GtkWindowGroup *group,
5513                             GtkWindow      *window)
5514 {
5515   GSList *tmp_list;
5516   GSList *to_remove = NULL;
5517
5518   tmp_list = group->grabs;
5519   while (tmp_list)
5520     {
5521       if (gtk_widget_get_toplevel (tmp_list->data) == (GtkWidget*) window)
5522         to_remove = g_slist_prepend (to_remove, g_object_ref (tmp_list->data));
5523       tmp_list = tmp_list->next;
5524     }
5525
5526   while (to_remove)
5527     {
5528       gtk_grab_remove (to_remove->data);
5529       g_object_unref (to_remove->data);
5530       to_remove = g_slist_delete_link (to_remove, to_remove);
5531     }
5532 }
5533
5534 /**
5535  * gtk_window_group_add_window:
5536  * @window_group: a #GtkWindowGroup
5537  * @window: the #GtkWindow to add
5538  * 
5539  * Adds a window to a #GtkWindowGroup. 
5540  **/
5541 void
5542 gtk_window_group_add_window (GtkWindowGroup *window_group,
5543                              GtkWindow      *window)
5544 {
5545   g_return_if_fail (GTK_IS_WINDOW_GROUP (window_group));
5546   g_return_if_fail (GTK_IS_WINDOW (window));
5547
5548   if (window->group != window_group)
5549     {
5550       g_object_ref (window);
5551       g_object_ref (window_group);
5552       
5553       if (window->group)
5554         gtk_window_group_remove_window (window->group, window);
5555       else
5556         window_group_cleanup_grabs (_gtk_window_get_group (NULL), window);
5557
5558       window->group = window_group;
5559
5560       g_object_unref (window);
5561     }
5562 }
5563
5564 /**
5565  * gtk_window_group_remove_window:
5566  * @window_group: a #GtkWindowGroup
5567  * @window: the #GtkWindow to remove
5568  * 
5569  * Removes a window from a #GtkWindowGroup.
5570  **/
5571 void
5572 gtk_window_group_remove_window (GtkWindowGroup *window_group,
5573                                 GtkWindow      *window)
5574 {
5575   g_return_if_fail (GTK_IS_WINDOW_GROUP (window_group));
5576   g_return_if_fail (GTK_IS_WIDGET (window));
5577   g_return_if_fail (window->group == window_group);
5578
5579   g_object_ref (window);
5580
5581   window_group_cleanup_grabs (window_group, window);
5582   window->group = NULL;
5583   
5584   g_object_unref (G_OBJECT (window_group));
5585   g_object_unref (window);
5586 }
5587
5588 /* Return the group for the window or the default group
5589  */
5590 GtkWindowGroup *
5591 _gtk_window_get_group (GtkWindow *window)
5592 {
5593   if (window && window->group)
5594     return window->group;
5595   else
5596     {
5597       static GtkWindowGroup *default_group = NULL;
5598
5599       if (!default_group)
5600         default_group = gtk_window_group_new ();
5601
5602       return default_group;
5603     }
5604 }
5605
5606
5607 /*
5608   Derived from XParseGeometry() in XFree86  
5609
5610   Copyright 1985, 1986, 1987,1998  The Open Group
5611
5612   All Rights Reserved.
5613
5614   The above copyright notice and this permission notice shall be included
5615   in all copies or substantial portions of the Software.
5616
5617   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
5618   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
5619   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
5620   IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
5621   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
5622   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
5623   OTHER DEALINGS IN THE SOFTWARE.
5624
5625   Except as contained in this notice, the name of The Open Group shall
5626   not be used in advertising or otherwise to promote the sale, use or
5627   other dealings in this Software without prior written authorization
5628   from The Open Group.
5629 */
5630
5631
5632 /*
5633  *    XParseGeometry parses strings of the form
5634  *   "=<width>x<height>{+-}<xoffset>{+-}<yoffset>", where
5635  *   width, height, xoffset, and yoffset are unsigned integers.
5636  *   Example:  "=80x24+300-49"
5637  *   The equal sign is optional.
5638  *   It returns a bitmask that indicates which of the four values
5639  *   were actually found in the string.  For each value found,
5640  *   the corresponding argument is updated;  for each value
5641  *   not found, the corresponding argument is left unchanged. 
5642  */
5643
5644 /* The following code is from Xlib, and is minimally modified, so we
5645  * can track any upstream changes if required.  Don't change this
5646  * code. Or if you do, put in a huge comment marking which thing
5647  * changed.
5648  */
5649
5650 static int
5651 read_int (gchar   *string,
5652           gchar  **next)
5653 {
5654   int result = 0;
5655   int sign = 1;
5656   
5657   if (*string == '+')
5658     string++;
5659   else if (*string == '-')
5660     {
5661       string++;
5662       sign = -1;
5663     }
5664
5665   for (; (*string >= '0') && (*string <= '9'); string++)
5666     {
5667       result = (result * 10) + (*string - '0');
5668     }
5669
5670   *next = string;
5671
5672   if (sign >= 0)
5673     return (result);
5674   else
5675     return (-result);
5676 }
5677
5678 /* 
5679  * Bitmask returned by XParseGeometry().  Each bit tells if the corresponding
5680  * value (x, y, width, height) was found in the parsed string.
5681  */
5682 #define NoValue         0x0000
5683 #define XValue          0x0001
5684 #define YValue          0x0002
5685 #define WidthValue      0x0004
5686 #define HeightValue     0x0008
5687 #define AllValues       0x000F
5688 #define XNegative       0x0010
5689 #define YNegative       0x0020
5690
5691 /* Try not to reformat/modify, so we can compare/sync with X sources */
5692 static int
5693 gtk_XParseGeometry (const char   *string,
5694                     int          *x,
5695                     int          *y,
5696                     unsigned int *width,   
5697                     unsigned int *height)  
5698 {
5699   int mask = NoValue;
5700   char *strind;
5701   unsigned int tempWidth, tempHeight;
5702   int tempX, tempY;
5703   char *nextCharacter;
5704
5705   /* These initializations are just to silence gcc */
5706   tempWidth = 0;
5707   tempHeight = 0;
5708   tempX = 0;
5709   tempY = 0;
5710   
5711   if ( (string == NULL) || (*string == '\0')) return(mask);
5712   if (*string == '=')
5713     string++;  /* ignore possible '=' at beg of geometry spec */
5714
5715   strind = (char *)string;
5716   if (*strind != '+' && *strind != '-' && *strind != 'x') {
5717     tempWidth = read_int(strind, &nextCharacter);
5718     if (strind == nextCharacter) 
5719       return (0);
5720     strind = nextCharacter;
5721     mask |= WidthValue;
5722   }
5723
5724   if (*strind == 'x' || *strind == 'X') {       
5725     strind++;
5726     tempHeight = read_int(strind, &nextCharacter);
5727     if (strind == nextCharacter)
5728       return (0);
5729     strind = nextCharacter;
5730     mask |= HeightValue;
5731   }
5732
5733   if ((*strind == '+') || (*strind == '-')) {
5734     if (*strind == '-') {
5735       strind++;
5736       tempX = -read_int(strind, &nextCharacter);
5737       if (strind == nextCharacter)
5738         return (0);
5739       strind = nextCharacter;
5740       mask |= XNegative;
5741
5742     }
5743     else
5744       { strind++;
5745       tempX = read_int(strind, &nextCharacter);
5746       if (strind == nextCharacter)
5747         return(0);
5748       strind = nextCharacter;
5749       }
5750     mask |= XValue;
5751     if ((*strind == '+') || (*strind == '-')) {
5752       if (*strind == '-') {
5753         strind++;
5754         tempY = -read_int(strind, &nextCharacter);
5755         if (strind == nextCharacter)
5756           return(0);
5757         strind = nextCharacter;
5758         mask |= YNegative;
5759
5760       }
5761       else
5762         {
5763           strind++;
5764           tempY = read_int(strind, &nextCharacter);
5765           if (strind == nextCharacter)
5766             return(0);
5767           strind = nextCharacter;
5768         }
5769       mask |= YValue;
5770     }
5771   }
5772         
5773   /* If strind isn't at the end of the string the it's an invalid
5774                 geometry specification. */
5775
5776   if (*strind != '\0') return (0);
5777
5778   if (mask & XValue)
5779     *x = tempX;
5780   if (mask & YValue)
5781     *y = tempY;
5782   if (mask & WidthValue)
5783     *width = tempWidth;
5784   if (mask & HeightValue)
5785     *height = tempHeight;
5786   return (mask);
5787 }
5788
5789 /**
5790  * gtk_window_parse_geometry:
5791  * @window: a #GtkWindow
5792  * @geometry: geometry string
5793  * 
5794  * Parses a standard X Window System geometry string - see the
5795  * manual page for X (type 'man X') for details on this.
5796  * gtk_window_parse_geometry() does work on all GTK+ ports
5797  * including Win32 but is primarily intended for an X environment.
5798  *
5799  * If either a size or a position can be extracted from the
5800  * geometry string, gtk_window_parse_geometry() returns %TRUE
5801  * and calls gtk_window_set_default_size() and/or gtk_window_move()
5802  * to resize/move the window.
5803  *
5804  * If gtk_window_parse_geometry() returns %TRUE, it will also
5805  * set the #GDK_HINT_USER_POS and/or #GDK_HINT_USER_SIZE hints
5806  * indicating to the window manager that the size/position of
5807  * the window was user-specified. This causes most window
5808  * managers to honor the geometry.
5809  * 
5810  * Return value: %TRUE if string was parsed successfully
5811  **/
5812 gboolean
5813 gtk_window_parse_geometry (GtkWindow   *window,
5814                            const gchar *geometry)
5815 {
5816   gint result, x, y;
5817   guint w, h;
5818   GdkGravity grav;
5819   gboolean size_set, pos_set;
5820   
5821   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
5822   g_return_val_if_fail (geometry != NULL, FALSE);
5823   
5824   result = gtk_XParseGeometry (geometry, &x, &y, &w, &h);
5825
5826   if ((result & WidthValue) == 0 ||
5827       w < 0)
5828     w = -1;
5829   if ((result & HeightValue) == 0 ||
5830       h < 0)
5831     h = -1;
5832
5833   size_set = FALSE;
5834   if ((result & WidthValue) || (result & HeightValue))
5835     {
5836       gtk_window_set_default_size_internal (window, TRUE, w, TRUE, h, TRUE);
5837       size_set = TRUE;
5838     }
5839
5840   gtk_window_get_size (window, &w, &h);
5841   
5842   grav = GDK_GRAVITY_NORTH_WEST;
5843
5844   if ((result & XNegative) && (result & YNegative))
5845     grav = GDK_GRAVITY_SOUTH_EAST;
5846   else if (result & XNegative)
5847     grav = GDK_GRAVITY_NORTH_EAST;
5848   else if (result & YNegative)
5849     grav = GDK_GRAVITY_SOUTH_WEST;
5850
5851   if ((result & XValue) == 0)
5852     x = 0;
5853
5854   if ((result & YValue) == 0)
5855     y = 0;
5856
5857   if (grav == GDK_GRAVITY_SOUTH_WEST ||
5858       grav == GDK_GRAVITY_SOUTH_EAST)
5859     y = gdk_screen_get_height (window->screen) - h + y;
5860
5861   if (grav == GDK_GRAVITY_SOUTH_EAST ||
5862       grav == GDK_GRAVITY_NORTH_EAST)
5863     x = gdk_screen_get_width (window->screen) - w + x;
5864
5865   /* we don't let you put a window offscreen; maybe some people would
5866    * prefer to be able to, but it's kind of a bogus thing to do.
5867    */
5868   if (y < 0)
5869     y = 0;
5870
5871   if (x < 0)
5872     x = 0;
5873
5874   pos_set = FALSE;
5875   if ((result & XValue) || (result & YValue))
5876     {
5877       gtk_window_set_gravity (window, grav);
5878       gtk_window_move (window, x, y);
5879       pos_set = TRUE;
5880     }
5881
5882   if (size_set || pos_set)
5883     {
5884       /* Set USSize, USPosition hints */
5885       GtkWindowGeometryInfo *info;
5886
5887       info = gtk_window_get_geometry_info (window, TRUE);
5888
5889       if (pos_set)
5890         info->mask |= GDK_HINT_USER_POS;
5891       if (size_set)
5892         info->mask |= GDK_HINT_USER_SIZE;
5893     }
5894   
5895   return result != 0;
5896 }
5897
5898 static void
5899 gtk_window_mnemonic_hash_foreach (gpointer key,
5900                                   gpointer value,
5901                                   gpointer data)
5902 {
5903   struct {
5904     GtkWindow *window;
5905     GtkWindowKeysForeachFunc func;
5906     gpointer func_data;
5907   } *info = data;
5908
5909   GtkWindowMnemonic *mnemonic = value;
5910
5911   if (mnemonic->window == info->window)
5912     (*info->func) (info->window, mnemonic->keyval, info->window->mnemonic_modifier, TRUE, info->func_data);
5913 }
5914
5915 void
5916 _gtk_window_keys_foreach (GtkWindow                *window,
5917                           GtkWindowKeysForeachFunc func,
5918                           gpointer                 func_data)
5919 {
5920   GSList *groups;
5921
5922   struct {
5923     GtkWindow *window;
5924     GtkWindowKeysForeachFunc func;
5925     gpointer func_data;
5926   } info;
5927
5928   info.window = window;
5929   info.func = func;
5930   info.func_data = func_data;
5931
5932   g_hash_table_foreach (mnemonic_hash_table,
5933                         gtk_window_mnemonic_hash_foreach,
5934                         &info);
5935
5936   groups = gtk_accel_groups_from_object (G_OBJECT (window));
5937   while (groups)
5938     {
5939       GtkAccelGroup *group = groups->data;
5940       gint i;
5941
5942       for (i = 0; i < group->n_accels; i++)
5943         {
5944           GtkAccelKey *key = &group->priv_accels[i].key;
5945           
5946           if (key->accel_key)
5947             (*func) (window, key->accel_key, key->accel_mods, FALSE, func_data);
5948         }
5949       
5950       groups = groups->next;
5951     }
5952 }
5953
5954 static void
5955 gtk_window_keys_changed (GtkWindow *window)
5956 {
5957   gtk_window_free_key_hash (window);
5958   gtk_window_get_key_hash (window);
5959 }
5960
5961 typedef struct _GtkWindowKeyEntry GtkWindowKeyEntry;
5962
5963 struct _GtkWindowKeyEntry
5964 {
5965   guint keyval;
5966   guint modifiers;
5967   gboolean is_mnemonic;
5968 };
5969
5970 static void
5971 add_to_key_hash (GtkWindow      *window,
5972                  guint           keyval,
5973                  GdkModifierType modifiers,
5974                  gboolean        is_mnemonic,
5975                  gpointer        data)
5976 {
5977   GtkKeyHash *key_hash = data;
5978
5979   GtkWindowKeyEntry *entry = g_new (GtkWindowKeyEntry, 1);
5980
5981   entry->keyval = keyval;
5982   entry->modifiers = modifiers;
5983   entry->is_mnemonic = is_mnemonic;
5984
5985   /* GtkAccelGroup stores lowercased accelerators. To deal
5986    * with this, if <Shift> was specified, uppercase.
5987    */
5988   if (modifiers & GDK_SHIFT_MASK)
5989     {
5990       if (keyval == GDK_Tab)
5991         keyval = GDK_ISO_Left_Tab;
5992       else
5993         keyval = gdk_keyval_to_upper (keyval);
5994     }
5995   
5996   _gtk_key_hash_add_entry (key_hash, keyval, entry->modifiers, entry);
5997 }
5998
5999 static GtkKeyHash *
6000 gtk_window_get_key_hash (GtkWindow *window)
6001 {
6002   GtkKeyHash *key_hash = g_object_get_data (G_OBJECT (window), "gtk-window-key-hash");
6003   if (key_hash)
6004     return key_hash;
6005   
6006   key_hash = _gtk_key_hash_new (gdk_keymap_get_for_display (gdk_screen_get_display (window->screen)),
6007                                 (GDestroyNotify)g_free);
6008   _gtk_window_keys_foreach (window, add_to_key_hash, key_hash);
6009   g_object_set_data (G_OBJECT (window), "gtk-window-key-hash", key_hash);
6010
6011   return key_hash;
6012 }
6013
6014 static void
6015 gtk_window_free_key_hash (GtkWindow *window)
6016 {
6017   GtkKeyHash *key_hash = g_object_get_data (G_OBJECT (window), "gtk-window-key-hash");
6018   if (key_hash)
6019     {
6020       _gtk_key_hash_free (key_hash);
6021       g_object_set_data (G_OBJECT (window), "gtk-window-key-hash", NULL);
6022     }
6023 }
6024
6025 /**
6026  * _gtk_window_activate_key:
6027  * @window: a #GtkWindow
6028  * @event: a #GdkEventKey
6029  * 
6030  * Activates mnemonics and accelerators for this #GtKWindow
6031  * 
6032  * Return value: %TRUE if a mnemonic or accelerator was found and activated.
6033  **/
6034 gboolean
6035 _gtk_window_activate_key (GtkWindow   *window,
6036                           GdkEventKey *event)
6037 {
6038   GtkKeyHash *key_hash = g_object_get_data (G_OBJECT (window), "gtk-window-key-hash");
6039   GtkWindowKeyEntry *found_entry = NULL;
6040
6041   if (!key_hash)
6042     {
6043       gtk_window_keys_changed (window);
6044       key_hash = g_object_get_data (G_OBJECT (window), "gtk-window-key-hash");
6045     }
6046   
6047   if (key_hash)
6048     {
6049       GSList *entries = _gtk_key_hash_lookup (key_hash,
6050                                               event->hardware_keycode,
6051                                               event->state & gtk_accelerator_get_default_mod_mask (),
6052                                               event->group);
6053       GSList *tmp_list;
6054
6055       for (tmp_list = entries; tmp_list; tmp_list = tmp_list->next)
6056         {
6057           GtkWindowKeyEntry *entry = tmp_list->data;
6058           if (entry->is_mnemonic)
6059             {
6060               found_entry = entry;
6061               break;
6062             }
6063         }
6064       
6065       if (!found_entry && entries)
6066         found_entry = entries->data;
6067
6068       g_slist_free (entries);
6069     }
6070
6071   if (found_entry)
6072     {
6073       if (found_entry->is_mnemonic)
6074         return gtk_window_mnemonic_activate (window, found_entry->keyval, found_entry->modifiers);
6075       else
6076         return gtk_accel_groups_activate (G_OBJECT (window), found_entry->keyval, found_entry->modifiers);
6077     }
6078   else
6079     return FALSE;
6080 }