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