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