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