]> Pileus Git - ~andy/gtk/blob - gtk/gtkwindow.c
Sanity check default font family name and size.
[~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  * For some uses, gtk_window_resize() is a more appropriate function.
2409  * gtk_window_resize() changes the current size of the window, rather
2410  * than the size to be used on initial display. gtk_window_resize() always
2411  * affects the window itself, not the geometry widget.
2412  *
2413  * The default size of a window only affects the first time a window is
2414  * shown; if a window is hidden and re-shown, it will remember the size
2415  * it had prior to hiding, rather than using the default size.
2416  *
2417  * Windows can't actually be 0x0 in size, they must be at least 1x1, but
2418  * passing 0 for @width and @height is OK, resulting in a 1x1 default size.
2419  **/
2420 void       
2421 gtk_window_set_default_size (GtkWindow   *window,
2422                              gint         width,
2423                              gint         height)
2424 {
2425   g_return_if_fail (GTK_IS_WINDOW (window));
2426   g_return_if_fail (width >= -1);
2427   g_return_if_fail (height >= -1);
2428
2429   gtk_window_set_default_size_internal (window, TRUE, width, TRUE, height);
2430 }
2431
2432 /**
2433  * gtk_window_get_default_size:
2434  * @window: a #GtkWindow
2435  * @width: location to store the default width, or %NULL
2436  * @height: location to store the default height, or %NULL
2437  *
2438  * Gets the default size of the window. A value of -1 for the width or
2439  * height indicates that a default size has not been explicitly set
2440  * for that dimension, so the "natural" size of the window will be
2441  * used.
2442  * 
2443  **/
2444 void
2445 gtk_window_get_default_size (GtkWindow *window,
2446                              gint      *width,
2447                              gint      *height)
2448 {
2449   GtkWindowGeometryInfo *info;
2450
2451   g_return_if_fail (GTK_IS_WINDOW (window));
2452
2453   info = gtk_window_get_geometry_info (window, FALSE);
2454
2455   if (width)
2456     *width = info->default_width;
2457
2458   if (height)
2459     *height = info->default_height;
2460 }
2461
2462 /**
2463  * gtk_window_resize:
2464  * @window: a #GtkWindow
2465  * @width: width in pixels to resize the window to
2466  * @height: height in pixels to resize the window to
2467  *
2468  * Resizes the window as if the user had done so, obeying geometry
2469  * constraints. The default geometry constraint is that windows may
2470  * not be smaller than their size request; to override this
2471  * constraint, call gtk_widget_set_size_request() to set the window's
2472  * request to a smaller value.
2473  *
2474  * If gtk_window_resize() is called before showing a window for the
2475  * first time, it overrides any default size set with
2476  * gtk_window_set_default_size().
2477  *
2478  * Windows may not be resized smaller than 1 by 1 pixels.
2479  * 
2480  **/
2481 void
2482 gtk_window_resize (GtkWindow *window,
2483                    gint       width,
2484                    gint       height)
2485 {
2486   GtkWindowGeometryInfo *info;
2487   
2488   g_return_if_fail (GTK_IS_WINDOW (window));
2489   g_return_if_fail (width > 0);
2490   g_return_if_fail (height > 0);
2491
2492   info = gtk_window_get_geometry_info (window, TRUE);
2493
2494   info->resize_width = width;
2495   info->resize_height = height;
2496
2497   gtk_widget_queue_resize (GTK_WIDGET (window));
2498 }
2499
2500 /**
2501  * gtk_window_get_size:
2502  * @window: a #GtkWindow
2503  * @width: return location for width, or %NULL
2504  * @height: return location for height, or %NULL
2505  *
2506  * Obtains the current size of @window. If @window is not onscreen,
2507  * it returns the size GTK+ will suggest to the <link
2508  * linkend="gtk-X11-arch">window manager</link> for the initial window
2509  * size (but this is not reliably the same as the size the window
2510  * manager will actually select). The size obtained by
2511  * gtk_window_get_size() is the last size received in a
2512  * #GdkEventConfigure, that is, GTK+ uses its locally-stored size,
2513  * rather than querying the X server for the size. As a result, if you
2514  * call gtk_window_resize() then immediately call
2515  * gtk_window_get_size(), the size won't have taken effect yet. After
2516  * the window manager processes the resize request, GTK+ receives
2517  * notification that the size has changed via a configure event, and
2518  * the size of the window gets updated.
2519  *
2520  * Note 1: Nearly any use of this function creates a race condition,
2521  * because the size of the window may change between the time that you
2522  * get the size and the time that you perform some action assuming
2523  * that size is the current size. To avoid race conditions, connect to
2524  * "configure_event" on the window and adjust your size-dependent
2525  * state to match the size delivered in the #GdkEventConfigure.
2526  *
2527  * Note 2: The returned size does <emphasis>not</emphasis> include the
2528  * size of the window manager decorations (aka the window frame or
2529  * border). Those are not drawn by GTK+ and GTK+ has no reliable
2530  * method of determining their size.
2531  *
2532  * Note 3: If you are getting a window size in order to position
2533  * the window onscreen, there may be a better way. The preferred
2534  * way is to simply set the window's semantic type with
2535  * gtk_window_set_type_hint(), which allows the window manager to
2536  * e.g. center dialogs. Also, if you set the transient parent of
2537  * dialogs with gtk_window_set_transient_for() window managers
2538  * will often center the dialog over its parent window. It's
2539  * much preferred to let the window manager handle these
2540  * things rather than doing it yourself, because all apps will
2541  * behave consistently and according to user prefs if the window
2542  * manager handles it. Also, the window manager can take the size
2543  * of the window decorations/border into account, while your
2544  * application cannot.
2545  *
2546  * In any case, if you insist on application-specified window
2547  * positioning, there's <emphasis>still</emphasis> a better way than
2548  * doing it yourself - gtk_window_set_position() will frequently
2549  * handle the details for you.
2550  * 
2551  **/
2552 void
2553 gtk_window_get_size (GtkWindow *window,
2554                      gint      *width,
2555                      gint      *height)
2556 {
2557   gint w, h;
2558   GtkWidget *widget;
2559   
2560   g_return_if_fail (GTK_IS_WINDOW (window));
2561
2562   widget = GTK_WIDGET (window);
2563   
2564   if (width == NULL && height == NULL)
2565     return;
2566
2567   if (GTK_WIDGET_MAPPED (window))
2568     {
2569       gdk_drawable_get_size (GTK_WIDGET (window)->window,
2570                              &w, &h);
2571     }
2572   else
2573     {
2574       GdkRectangle configure_request;
2575
2576       gtk_window_compute_configure_request (window,
2577                                             &configure_request,
2578                                             NULL, NULL);
2579
2580       w = configure_request.width;
2581       h = configure_request.height;
2582     }
2583   
2584   if (width)
2585     *width = w;
2586   if (height)
2587     *height = h;
2588 }
2589
2590 /**
2591  * gtk_window_move:
2592  * @window: a #GtkWindow
2593  * @x: X coordinate to move window to
2594  * @y: Y coordinate to move window to
2595  *
2596  * Asks the <link linkend="gtk-X11-arch">window manager</link> to move
2597  * @window to the given position.  Window managers are free to ignore
2598  * this; most window managers ignore requests for initial window
2599  * positions (instead using a user-defined placement algorithm) and
2600  * honor requests after the window has already been shown.
2601  *
2602  * Note: the position is the position of the gravity-determined
2603  * reference point for the window. The gravity determines two things:
2604  * first, the location of the reference point in root window
2605  * coordinates; and second, which point on the window is positioned at
2606  * the reference point.
2607  *
2608  * By default the gravity is #GDK_GRAVITY_NORTH_WEST, so the reference
2609  * point is simply the @x, @y supplied to gtk_window_move(). The
2610  * top-left corner of the window decorations (aka window frame or
2611  * border) will be placed at @x, @y.  Therefore, to position a window
2612  * at the top left of the screen, you want to use the default gravity
2613  * (which is #GDK_GRAVITY_NORTH_WEST) and move the window to 0,0.
2614  *
2615  * To position a window at the bottom right corner of the screen, you
2616  * would set #GDK_GRAVITY_SOUTH_EAST, which means that the reference
2617  * point is at @x + the window width and @y + the window height, and
2618  * the bottom-right corner of the window border will be placed at that
2619  * reference point. So, to place a window in the bottom right corner
2620  * you would first set gravity to south east, then write:
2621  * <literal>gtk_window_move (window, gdk_screen_width () - window_width,
2622  * gdk_screen_height () - window_height)</literal>.
2623  *
2624  * The extended window manager hints specification at <ulink 
2625  * url="http://www.freedesktop.org/standards/wm-spec.html"
2626  * >http://www.freedesktop.org/standards/wm-spec.html</ulink> has a 
2627  * nice table of gravities in the "implementation notes" section.
2628  *
2629  * The gtk_window_get_position() documentation may also be relevant.
2630  * 
2631  **/
2632 void
2633 gtk_window_move (GtkWindow *window,
2634                  gint       x,
2635                  gint       y)
2636 {
2637   GtkWindowGeometryInfo *info;
2638   GtkWidget *widget;
2639   
2640   g_return_if_fail (GTK_IS_WINDOW (window));
2641
2642   widget = GTK_WIDGET (window);
2643
2644   info = gtk_window_get_geometry_info (window, TRUE);  
2645   
2646   if (GTK_WIDGET_MAPPED (window))
2647     {
2648       /* we have now sent a request with this position
2649        * with currently-active constraints, so toggle flag.
2650        */
2651       info->position_constraints_changed = FALSE;
2652
2653       /* we only constrain if mapped - if not mapped,
2654        * then gtk_window_compute_configure_request()
2655        * will apply the constraints later, and we
2656        * don't want to lose information about
2657        * what position the user set before then.
2658        * i.e. if you do a move() then turn off POS_CENTER
2659        * then show the window, your move() will work.
2660        */
2661       gtk_window_constrain_position (window,
2662                                      widget->allocation.width,
2663                                      widget->allocation.height,
2664                                      &x, &y);
2665       
2666       /* Note that this request doesn't go through our standard request
2667        * framework, e.g. doesn't increment configure_request_count,
2668        * doesn't set info->last, etc.; that's because
2669        * we don't save the info needed to arrive at this same request
2670        * again.
2671        *
2672        * To gtk_window_move_resize(), this will end up looking exactly
2673        * the same as the position being changed by the window
2674        * manager.
2675        */
2676       
2677       /* FIXME are we handling gravity properly for framed windows? */
2678       if (window->frame)
2679         gdk_window_move (window->frame,
2680                          x - window->frame_left,
2681                          y - window->frame_top);
2682       else
2683         gdk_window_move (GTK_WIDGET (window)->window,
2684                          x, y);
2685     }
2686   else
2687     {
2688       /* Save this position to apply on mapping */
2689       info->initial_x = x;
2690       info->initial_y = y;
2691       info->initial_pos_set = TRUE;
2692     }
2693 }
2694
2695 /**
2696  * gtk_window_get_position:
2697  * @window: a #GtkWindow
2698  * @root_x: return location for X coordinate of gravity-determined reference p\oint
2699  * @root_y: return location for Y coordinate of gravity-determined reference p\oint
2700  *
2701  * This function returns the position you need to pass to
2702  * gtk_window_move() to keep @window in its current position.  This
2703  * means that the meaning of the returned value varies with window
2704  * gravity. See gtk_window_move() for more details.
2705  * 
2706  * If you haven't changed the window gravity, its gravity will be
2707  * #GDK_GRAVITY_NORTH_WEST. This means that gtk_window_get_position()
2708  * gets the position of the top-left corner of the window manager
2709  * frame for the window. gtk_window_move() sets the position of this
2710  * same top-left corner.
2711  *
2712  * gtk_window_get_position() is not 100% reliable because the X Window System
2713  * does not specify a way to obtain the geometry of the
2714  * decorations placed on a window by the window manager.
2715  * Thus GTK+ is using a "best guess" that works with most
2716  * window managers.
2717  *
2718  * Moreover, nearly all window managers are historically broken with
2719  * respect to their handling of window gravity. So moving a window to
2720  * its current position as returned by gtk_window_get_position() tends
2721  * to result in moving the window slightly. Window managers are
2722  * slowly getting better over time.
2723  *
2724  * If a window has gravity #GDK_GRAVITY_STATIC the window manager
2725  * frame is not relevant, and thus gtk_window_get_position() will
2726  * always produce accurate results. However you can't use static
2727  * gravity to do things like place a window in a corner of the screen,
2728  * because static gravity ignores the window manager decorations.
2729  *
2730  * If you are saving and restoring your application's window
2731  * positions, you should know that it's impossible for applications to
2732  * do this without getting it somewhat wrong because applications do
2733  * not have sufficient knowledge of window manager state. The Correct
2734  * Mechanism is to support the session management protocol (see the
2735  * "GnomeClient" object in the GNOME libraries for example) and allow
2736  * the window manager to save your window sizes and positions.
2737  * 
2738  **/
2739
2740 void
2741 gtk_window_get_position (GtkWindow *window,
2742                          gint      *root_x,
2743                          gint      *root_y)
2744 {
2745   GtkWidget *widget;
2746
2747   g_return_if_fail (GTK_IS_WINDOW (window));
2748
2749   widget = GTK_WIDGET (window);
2750   
2751   if (window->gravity == GDK_GRAVITY_STATIC)
2752     {
2753       if (GTK_WIDGET_MAPPED (widget))
2754         {
2755           /* This does a server round-trip, which is sort of wrong;
2756            * but a server round-trip is inevitable for
2757            * gdk_window_get_frame_extents() in the usual
2758            * NorthWestGravity case below, so not sure what else to
2759            * do. We should likely be consistent about whether we get
2760            * the client-side info or the server-side info.
2761            */
2762           gdk_window_get_origin (widget->window, root_x, root_y);
2763         }
2764       else
2765         {
2766           GdkRectangle configure_request;
2767           
2768           gtk_window_compute_configure_request (window,
2769                                                 &configure_request,
2770                                                 NULL, NULL);
2771           
2772           *root_x = configure_request.x;
2773           *root_y = configure_request.y;
2774         }
2775     }
2776   else
2777     {
2778       GdkRectangle frame_extents;
2779       
2780       gint x, y;
2781       gint w, h;
2782       
2783       if (GTK_WIDGET_MAPPED (widget))
2784         {
2785           if (window->frame)
2786             gdk_window_get_frame_extents (window->frame, &frame_extents);
2787           else
2788             gdk_window_get_frame_extents (widget->window, &frame_extents);
2789           x = frame_extents.x;
2790           y = frame_extents.y;
2791           gtk_window_get_size (window, &w, &h);
2792         }
2793       else
2794         {
2795           /* We just say the frame has 0 size on all sides.
2796            * Not sure what else to do.
2797            */             
2798           gtk_window_compute_configure_request (window,
2799                                                 &frame_extents,
2800                                                 NULL, NULL);
2801           x = frame_extents.x;
2802           y = frame_extents.y;
2803           w = frame_extents.width;
2804           h = frame_extents.height;
2805         }
2806       
2807       switch (window->gravity)
2808         {
2809         case GDK_GRAVITY_NORTH:
2810         case GDK_GRAVITY_CENTER:
2811         case GDK_GRAVITY_SOUTH:
2812           /* Find center of frame. */
2813           x += frame_extents.width / 2;
2814           /* Center client window on that point. */
2815           x -= w / 2;
2816           break;
2817
2818         case GDK_GRAVITY_SOUTH_EAST:
2819         case GDK_GRAVITY_EAST:
2820         case GDK_GRAVITY_NORTH_EAST:
2821           /* Find right edge of frame */
2822           x += frame_extents.width;
2823           /* Align left edge of client at that point. */
2824           x -= w;
2825           break;
2826         default:
2827           break;
2828         }
2829
2830       switch (window->gravity)
2831         {
2832         case GDK_GRAVITY_WEST:
2833         case GDK_GRAVITY_CENTER:
2834         case GDK_GRAVITY_EAST:
2835           /* Find center of frame. */
2836           y += frame_extents.height / 2;
2837           /* Center client window there. */
2838           y -= h / 2;
2839           break;
2840         case GDK_GRAVITY_SOUTH_WEST:
2841         case GDK_GRAVITY_SOUTH:
2842         case GDK_GRAVITY_SOUTH_EAST:
2843           /* Find south edge of frame */
2844           y += frame_extents.height;
2845           /* Place bottom edge of client there */
2846           y -= h;
2847           break;
2848         default:
2849           break;
2850         }
2851       
2852       if (root_x)
2853         *root_x = x;
2854       if (root_y)
2855         *root_y = y;
2856     }
2857 }
2858
2859 /**
2860  * gtk_window_reshow_with_initial_size:
2861  * @window: a #GtkWindow
2862  * 
2863  * Hides @window, then reshows it, resetting the
2864  * default size and position of the window. Used
2865  * by GUI builders only.
2866  **/
2867 void
2868 gtk_window_reshow_with_initial_size (GtkWindow *window)
2869 {
2870   GtkWidget *widget;
2871   
2872   g_return_if_fail (GTK_IS_WINDOW (window));
2873
2874   widget = GTK_WIDGET (window);
2875   
2876   gtk_widget_hide (widget);
2877   gtk_widget_unrealize (widget);
2878   gtk_widget_show (widget);
2879 }
2880
2881 static void
2882 gtk_window_destroy (GtkObject *object)
2883 {
2884   GtkWindow *window = GTK_WINDOW (object);
2885   
2886   if (window->transient_parent)
2887     gtk_window_set_transient_for (window, NULL);
2888
2889   /* frees the icons */
2890   gtk_window_set_icon_list (window, NULL);
2891   
2892   if (window->has_user_ref_count)
2893     {
2894       window->has_user_ref_count = FALSE;
2895       gtk_widget_unref (GTK_WIDGET (window));
2896     }
2897
2898   if (window->group)
2899     gtk_window_group_remove_window (window->group, window);
2900
2901    gtk_window_free_key_hash (window);
2902
2903    GTK_OBJECT_CLASS (parent_class)->destroy (object);
2904 }
2905
2906 static gboolean
2907 gtk_window_mnemonic_hash_remove (gpointer       key,
2908                                  gpointer       value,
2909                                  gpointer       user)
2910 {
2911   GtkWindowMnemonic *mnemonic = key;
2912   GtkWindow *window = user;
2913
2914   if (mnemonic->window == window)
2915     {
2916       if (mnemonic->targets)
2917         {
2918           gchar *name = gtk_accelerator_name (mnemonic->keyval, 0);
2919
2920           g_warning ("mnemonic \"%s\" wasn't removed for widget (%p)",
2921                      name, mnemonic->targets->data);
2922           g_free (name);
2923         }
2924       g_slist_free (mnemonic->targets);
2925       g_free (mnemonic);
2926       
2927       return TRUE;
2928     }
2929   return FALSE;
2930 }
2931
2932 static void
2933 gtk_window_finalize (GObject *object)
2934 {
2935   GtkWindow *window = GTK_WINDOW (object);
2936
2937   toplevel_list = g_slist_remove (toplevel_list, window);
2938
2939   g_free (window->title);
2940   g_free (window->wmclass_name);
2941   g_free (window->wmclass_class);
2942   g_free (window->wm_role);
2943
2944   g_hash_table_foreach_remove (mnemonic_hash_table,
2945                                gtk_window_mnemonic_hash_remove,
2946                                window);
2947   if (window->geometry_info)
2948     {
2949       if (window->geometry_info->widget)
2950         gtk_signal_disconnect_by_func (GTK_OBJECT (window->geometry_info->widget),
2951                                        GTK_SIGNAL_FUNC (gtk_widget_destroyed),
2952                                        &window->geometry_info->widget);
2953       g_free (window->geometry_info);
2954     }
2955
2956   if (window->keys_changed_handler)
2957     {
2958       gtk_idle_remove (window->keys_changed_handler);
2959       window->keys_changed_handler = 0;
2960     }
2961
2962   G_OBJECT_CLASS (parent_class)->finalize (object);
2963 }
2964
2965 static void
2966 gtk_window_show (GtkWidget *widget)
2967 {
2968   GtkWindow *window = GTK_WINDOW (widget);
2969   GtkContainer *container = GTK_CONTAINER (window);
2970   gboolean need_resize;
2971
2972   GTK_WIDGET_SET_FLAGS (widget, GTK_VISIBLE);
2973   
2974   need_resize = container->need_resize || !GTK_WIDGET_REALIZED (widget);
2975   container->need_resize = FALSE;
2976
2977   if (need_resize)
2978     {
2979       GtkWindowGeometryInfo *info = gtk_window_get_geometry_info (window, TRUE);
2980       GtkAllocation allocation = { 0, 0 };
2981       GdkRectangle configure_request;
2982       GdkGeometry new_geometry;
2983       guint new_flags;
2984       gboolean was_realized;
2985
2986       /* We are going to go ahead and perform this configure request
2987        * and then emulate a configure notify by going ahead and
2988        * doing a size allocate. Sort of a synchronous
2989        * mini-copy of gtk_window_move_resize() here.
2990        */
2991       gtk_window_compute_configure_request (window,
2992                                             &configure_request,
2993                                             &new_geometry,
2994                                             &new_flags);
2995       
2996       /* We update this because we are going to go ahead
2997        * and gdk_window_resize() below, rather than
2998        * queuing it.
2999        */
3000       info->last.configure_request.width = configure_request.width;
3001       info->last.configure_request.height = configure_request.height;
3002       
3003       /* and allocate the window - this is normally done
3004        * in move_resize in response to configure notify
3005        */
3006       allocation.width  = configure_request.width;
3007       allocation.height = configure_request.height;
3008       gtk_widget_size_allocate (widget, &allocation);
3009
3010       /* Then we guarantee we have a realize */
3011       was_realized = FALSE;
3012       if (!GTK_WIDGET_REALIZED (widget))
3013         {
3014           gtk_widget_realize (widget);
3015           was_realized = TRUE;
3016         }
3017
3018       /* Must be done after the windows are realized,
3019        * so that the decorations can be read
3020        */
3021       gtk_decorated_window_calculate_frame_size (window);
3022
3023       /* We only send configure request if we didn't just finish
3024        * creating the window; if we just created the window
3025        * then we created it with widget->allocation anyhow.
3026        */
3027       if (!was_realized)
3028         gdk_window_resize (widget->window,
3029                            configure_request.width,
3030                            configure_request.height);
3031     }
3032   
3033   gtk_container_check_resize (container);
3034
3035   gtk_widget_map (widget);
3036
3037   /* Try to make sure that we have some focused widget
3038    */
3039   if (!window->focus_widget)
3040     gtk_window_move_focus (window, GTK_DIR_TAB_FORWARD);
3041   
3042   if (window->modal)
3043     gtk_grab_add (widget);
3044 }
3045
3046 static void
3047 gtk_window_hide (GtkWidget *widget)
3048 {
3049   GtkWindow *window = GTK_WINDOW (widget);
3050
3051   GTK_WIDGET_UNSET_FLAGS (widget, GTK_VISIBLE);
3052   gtk_widget_unmap (widget);
3053
3054   if (window->modal)
3055     gtk_grab_remove (widget);
3056 }
3057
3058 static void
3059 gtk_window_map (GtkWidget *widget)
3060 {
3061   GtkWindow *window = GTK_WINDOW (widget);
3062   GdkWindow *toplevel;
3063   
3064   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
3065
3066   if (window->bin.child &&
3067       GTK_WIDGET_VISIBLE (window->bin.child) &&
3068       !GTK_WIDGET_MAPPED (window->bin.child))
3069     gtk_widget_map (window->bin.child);
3070
3071   if (window->frame)
3072     toplevel = window->frame;
3073   else
3074     toplevel = widget->window;
3075   
3076   if (window->maximize_initially)
3077     gdk_window_maximize (toplevel);
3078   else
3079     gdk_window_unmaximize (toplevel);
3080   
3081   if (window->stick_initially)
3082     gdk_window_stick (toplevel);
3083   else
3084     gdk_window_unstick (toplevel);
3085   
3086   if (window->iconify_initially)
3087     gdk_window_iconify (toplevel);
3088   else
3089     gdk_window_deiconify (toplevel);
3090
3091   /* No longer use the default settings */
3092   window->need_default_size = FALSE;
3093   window->need_default_position = FALSE;
3094   
3095   gdk_window_show (widget->window);
3096
3097   if (window->frame)
3098     gdk_window_show (window->frame);
3099 }
3100
3101 static void
3102 gtk_window_unmap (GtkWidget *widget)
3103 {
3104   GtkWindow *window = GTK_WINDOW (widget);
3105   GtkWindowGeometryInfo *info;    
3106
3107   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
3108   if (window->frame)
3109     gdk_window_withdraw (window->frame);
3110   else 
3111     gdk_window_withdraw (widget->window);
3112   
3113   window->configure_request_count = 0;
3114   window->configure_notify_received = FALSE;
3115
3116   /* on unmap, we reset the default positioning of the window,
3117    * so it's placed again, but we don't reset the default
3118    * size of the window, so it's remembered.
3119    */
3120   window->need_default_position = TRUE;
3121
3122   info = gtk_window_get_geometry_info (window, FALSE);
3123   if (info)
3124     {
3125       info->initial_pos_set = FALSE;
3126       info->position_constraints_changed = FALSE;
3127     }
3128 }
3129
3130 static void
3131 gtk_window_realize (GtkWidget *widget)
3132 {
3133   GtkWindow *window;
3134   GdkWindow *parent_window;
3135   GdkWindowAttr attributes;
3136   gint attributes_mask;
3137   
3138   window = GTK_WINDOW (widget);
3139
3140   /* ensure widget tree is properly size allocated */
3141   if (widget->allocation.x == -1 &&
3142       widget->allocation.y == -1 &&
3143       widget->allocation.width == 1 &&
3144       widget->allocation.height == 1)
3145     {
3146       GtkRequisition requisition;
3147       GtkAllocation allocation = { 0, 0, 200, 200 };
3148
3149       gtk_widget_size_request (widget, &requisition);
3150       if (requisition.width || requisition.height)
3151         {
3152           /* non-empty window */
3153           allocation.width = requisition.width;
3154           allocation.height = requisition.height;
3155         }
3156       gtk_widget_size_allocate (widget, &allocation);
3157       
3158       _gtk_container_queue_resize (GTK_CONTAINER (widget));
3159
3160       g_return_if_fail (!GTK_WIDGET_REALIZED (widget));
3161     }
3162   
3163   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
3164   
3165   switch (window->type)
3166     {
3167     case GTK_WINDOW_TOPLEVEL:
3168       attributes.window_type = GDK_WINDOW_TOPLEVEL;
3169       break;
3170     case GTK_WINDOW_POPUP:
3171       attributes.window_type = GDK_WINDOW_TEMP;
3172       break;
3173     default:
3174       g_warning (G_STRLOC": Unknown window type %d!", window->type);
3175       break;
3176     }
3177    
3178   attributes.title = window->title;
3179   attributes.wmclass_name = window->wmclass_name;
3180   attributes.wmclass_class = window->wmclass_class;
3181   attributes.wclass = GDK_INPUT_OUTPUT;
3182   attributes.visual = gtk_widget_get_visual (widget);
3183   attributes.colormap = gtk_widget_get_colormap (widget);
3184
3185   if (window->has_frame)
3186     {
3187       attributes.width = widget->allocation.width + window->frame_left + window->frame_right;
3188       attributes.height = widget->allocation.height + window->frame_top + window->frame_bottom;
3189       attributes.event_mask = (GDK_EXPOSURE_MASK |
3190                                GDK_KEY_PRESS_MASK |
3191                                GDK_ENTER_NOTIFY_MASK |
3192                                GDK_LEAVE_NOTIFY_MASK |
3193                                GDK_FOCUS_CHANGE_MASK |
3194                                GDK_STRUCTURE_MASK |
3195                                GDK_BUTTON_MOTION_MASK |
3196                                GDK_POINTER_MOTION_HINT_MASK |
3197                                GDK_BUTTON_PRESS_MASK |
3198                                GDK_BUTTON_RELEASE_MASK);
3199       
3200       attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP;
3201       
3202       window->frame = gdk_window_new (NULL, &attributes, attributes_mask);
3203       gdk_window_set_user_data (window->frame, widget);
3204       
3205       attributes.window_type = GDK_WINDOW_CHILD;
3206       attributes.x = window->frame_left;
3207       attributes.y = window->frame_right;
3208     
3209       attributes_mask = GDK_WA_X | GDK_WA_Y;
3210
3211       parent_window = window->frame;
3212     }
3213   else
3214     {
3215       attributes_mask = 0;
3216       parent_window = NULL;
3217     }
3218   
3219   attributes.width = widget->allocation.width;
3220   attributes.height = widget->allocation.height;
3221   attributes.event_mask = gtk_widget_get_events (widget);
3222   attributes.event_mask |= (GDK_EXPOSURE_MASK |
3223                             GDK_KEY_PRESS_MASK |
3224                             GDK_KEY_RELEASE_MASK |
3225                             GDK_ENTER_NOTIFY_MASK |
3226                             GDK_LEAVE_NOTIFY_MASK |
3227                             GDK_FOCUS_CHANGE_MASK |
3228                             GDK_STRUCTURE_MASK);
3229
3230   attributes_mask |= GDK_WA_VISUAL | GDK_WA_COLORMAP;
3231   attributes_mask |= (window->title ? GDK_WA_TITLE : 0);
3232   attributes_mask |= (window->wmclass_name ? GDK_WA_WMCLASS : 0);
3233   widget->window = gdk_window_new (parent_window, &attributes, attributes_mask);
3234   gdk_window_set_user_data (widget->window, window);
3235       
3236   widget->style = gtk_style_attach (widget->style, widget->window);
3237   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
3238   if (window->frame)
3239     gtk_style_set_background (widget->style, window->frame, GTK_STATE_NORMAL);
3240
3241   /* This is a bad hack to set the window background. */
3242   gtk_window_paint (widget, NULL);
3243   
3244   if (window->transient_parent &&
3245       GTK_WIDGET_REALIZED (window->transient_parent))
3246     gdk_window_set_transient_for (widget->window,
3247                                   GTK_WIDGET (window->transient_parent)->window);
3248
3249   if (window->wm_role)
3250     gdk_window_set_role (widget->window, window->wm_role);
3251   
3252   if (!window->decorated)
3253     gdk_window_set_decorations (widget->window, 0);
3254
3255   gdk_window_set_type_hint (widget->window, window->type_hint);
3256
3257   /* transient_for must be set to allow the modal hint */
3258   if (window->transient_parent && window->modal)
3259     gdk_window_set_modal_hint (widget->window, TRUE);
3260   else
3261     gdk_window_set_modal_hint (widget->window, FALSE);
3262
3263   /* Icons */
3264   gtk_window_realize_icon (window);
3265 }
3266
3267 static void
3268 gtk_window_unrealize (GtkWidget *widget)
3269 {
3270   GtkWindow *window;
3271   GtkWindowGeometryInfo *info;
3272
3273   window = GTK_WINDOW (widget);
3274
3275   /* On unrealize, we reset the size of the window such
3276    * that we will re-apply the default sizing stuff
3277    * next time we show the window.
3278    *
3279    * Default positioning is reset on unmap, instead of unrealize.
3280    */
3281   window->need_default_size = TRUE;
3282   info = gtk_window_get_geometry_info (window, FALSE);
3283   if (info)
3284     {
3285       info->resize_width = -1;
3286       info->resize_height = -1;
3287       info->last.configure_request.x = 0;
3288       info->last.configure_request.y = 0;
3289       info->last.configure_request.width = -1;
3290       info->last.configure_request.height = -1;
3291       /* be sure we reset geom hints on re-realize */
3292       info->last.flags = 0;
3293     }
3294   
3295   if (window->frame)
3296     {
3297       gdk_window_set_user_data (window->frame, NULL);
3298       gdk_window_destroy (window->frame);
3299       window->frame = NULL;
3300     }
3301
3302   /* Icons */
3303   gtk_window_unrealize_icon (window);
3304   
3305   (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
3306 }
3307
3308 static void
3309 gtk_window_size_request (GtkWidget      *widget,
3310                          GtkRequisition *requisition)
3311 {
3312   GtkWindow *window;
3313   GtkBin *bin;
3314
3315   window = GTK_WINDOW (widget);
3316   bin = GTK_BIN (window);
3317   
3318   requisition->width = GTK_CONTAINER (window)->border_width * 2;
3319   requisition->height = GTK_CONTAINER (window)->border_width * 2;
3320
3321   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
3322     {
3323       GtkRequisition child_requisition;
3324       
3325       gtk_widget_size_request (bin->child, &child_requisition);
3326
3327       requisition->width += child_requisition.width;
3328       requisition->height += child_requisition.height;
3329     }
3330 }
3331
3332 static void
3333 gtk_window_size_allocate (GtkWidget     *widget,
3334                           GtkAllocation *allocation)
3335 {
3336   GtkWindow *window;
3337   GtkAllocation child_allocation;
3338
3339   window = GTK_WINDOW (widget);
3340   widget->allocation = *allocation;
3341
3342   if (window->bin.child && GTK_WIDGET_VISIBLE (window->bin.child))
3343     {
3344       child_allocation.x = GTK_CONTAINER (window)->border_width;
3345       child_allocation.y = GTK_CONTAINER (window)->border_width;
3346       child_allocation.width =
3347         MAX (1, (gint)allocation->width - child_allocation.x * 2);
3348       child_allocation.height =
3349         MAX (1, (gint)allocation->height - child_allocation.y * 2);
3350
3351       gtk_widget_size_allocate (window->bin.child, &child_allocation);
3352     }
3353
3354   if (GTK_WIDGET_REALIZED (widget) && window->frame)
3355     {
3356       gdk_window_resize (window->frame,
3357                          allocation->width + window->frame_left + window->frame_right,
3358                          allocation->height + window->frame_top + window->frame_bottom);
3359     }
3360 }
3361
3362 static gint
3363 gtk_window_event (GtkWidget *widget, GdkEvent *event)
3364 {
3365   GtkWindow *window;
3366   gboolean return_val;
3367
3368   window = GTK_WINDOW (widget);
3369
3370   if (window->frame && (event->any.window == window->frame))
3371     {
3372       if ((event->type != GDK_KEY_PRESS) &&
3373           (event->type != GDK_KEY_RELEASE) &&
3374           (event->type != GDK_FOCUS_CHANGE))
3375         {
3376           gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "event");
3377           return_val = FALSE;
3378           gtk_signal_emit (GTK_OBJECT (widget), window_signals[FRAME_EVENT], event, &return_val);
3379           return TRUE;
3380         }
3381       else
3382         {
3383           g_object_unref (event->any.window);
3384           event->any.window = g_object_ref (widget->window);
3385         }
3386     }
3387
3388   return FALSE;
3389 }
3390
3391 static gboolean
3392 gtk_window_frame_event (GtkWindow *window, GdkEvent *event)
3393 {
3394   GdkEventConfigure *configure_event;
3395   GdkRectangle rect;
3396
3397   switch (event->type)
3398     {
3399     case GDK_CONFIGURE:
3400       configure_event = (GdkEventConfigure *)event;
3401       
3402       /* Invalidate the decorations */
3403       rect.x = 0;
3404       rect.y = 0;
3405       rect.width = configure_event->width;
3406       rect.height = configure_event->height;
3407       
3408       gdk_window_invalidate_rect (window->frame, &rect, FALSE);
3409
3410       /* Pass on the (modified) configure event */
3411       configure_event->width -= window->frame_left + window->frame_right;
3412       configure_event->height -= window->frame_top + window->frame_bottom;
3413       return gtk_window_configure_event (GTK_WIDGET (window), configure_event);
3414       break;
3415     default:
3416       break;
3417     }
3418   return FALSE;
3419 }
3420
3421 static gint
3422 gtk_window_configure_event (GtkWidget         *widget,
3423                             GdkEventConfigure *event)
3424 {
3425   GtkWindow *window = GTK_WINDOW (widget);
3426
3427   /* window->configure_request_count incremented for each 
3428    * configure request, and decremented to a min of 0 for
3429    * each configure notify.
3430    *
3431    * All it means is that we know we will get at least
3432    * window->configure_request_count more configure notifies.
3433    * We could get more configure notifies than that; some
3434    * of the configure notifies we get may be unrelated to
3435    * the configure requests. But we will get at least
3436    * window->configure_request_count notifies.
3437    */
3438
3439   if (window->configure_request_count > 0)
3440     window->configure_request_count -= 1;
3441   
3442   /* As an optimization, we avoid a resize when possible.
3443    *
3444    * The only times we can avoid a resize are:
3445    *   - we know only the position changed, not the size
3446    *   - we know we have made more requests and so will get more
3447    *     notifies and can wait to resize when we get them
3448    */
3449   
3450   if (window->configure_request_count > 0 ||
3451       (widget->allocation.width == event->width &&
3452        widget->allocation.height == event->height))
3453     return TRUE;
3454
3455   /*
3456    * If we do need to resize, we do that by:
3457    *   - filling in widget->allocation with the new size
3458    *   - setting configure_notify_received to TRUE
3459    *     for use in gtk_window_move_resize()
3460    *   - queueing a resize, leading to invocation of
3461    *     gtk_window_move_resize() in an idle handler
3462    *
3463    */
3464   
3465   window->configure_notify_received = TRUE;
3466   
3467   widget->allocation.width = event->width;
3468   widget->allocation.height = event->height;
3469   
3470   _gtk_container_queue_resize (GTK_CONTAINER (widget));
3471   
3472   return TRUE;
3473 }
3474
3475 /* the accel_key and accel_mods fields of the key have to be setup
3476  * upon calling this function. it'll then return whether that key
3477  * is at all used as accelerator, and if so will OR in the
3478  * accel_flags member of the key.
3479  */
3480 gboolean
3481 _gtk_window_query_nonaccels (GtkWindow      *window,
3482                              guint           accel_key,
3483                              GdkModifierType accel_mods)
3484 {
3485   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
3486
3487   /* movement keys are considered locked accels */
3488   if (!accel_mods)
3489     {
3490       static const guint bindings[] = {
3491         GDK_space, GDK_KP_Space, GDK_Return, GDK_KP_Enter, GDK_Up, GDK_KP_Up, GDK_Down, GDK_KP_Down,
3492         GDK_Left, GDK_KP_Left, GDK_Right, GDK_KP_Right, GDK_Tab, GDK_KP_Tab, GDK_ISO_Left_Tab,
3493       };
3494       guint i;
3495       
3496       for (i = 0; i < G_N_ELEMENTS (bindings); i++)
3497         if (bindings[i] == accel_key)
3498           return TRUE;
3499     }
3500
3501   /* mnemonics are considered locked accels */
3502   if (accel_mods == window->mnemonic_modifier)
3503     {
3504       GtkWindowMnemonic mkey;
3505
3506       mkey.window = window;
3507       mkey.keyval = accel_key;
3508       if (g_hash_table_lookup (mnemonic_hash_table, &mkey))
3509         return TRUE;
3510     }
3511
3512   return FALSE;
3513 }
3514
3515 static gint
3516 gtk_window_key_press_event (GtkWidget   *widget,
3517                             GdkEventKey *event)
3518 {
3519   GtkWindow *window;
3520   GtkWidget *focus;
3521   gboolean handled;
3522
3523   window = GTK_WINDOW (widget);
3524
3525   handled = FALSE;
3526
3527   /* Check for mnemonics and accelerators
3528    */
3529   if (!handled)
3530     handled = _gtk_window_activate_key (window, event);
3531
3532   if (!handled)
3533     {
3534       focus = window->focus_widget;
3535       if (focus)
3536         g_object_ref (focus);
3537       
3538       while (!handled &&
3539              focus && focus != widget &&
3540              gtk_widget_get_toplevel (focus) == widget)
3541         {
3542           GtkWidget *parent;
3543           
3544           if (GTK_WIDGET_IS_SENSITIVE (focus))
3545             handled = gtk_widget_event (focus, (GdkEvent*) event);
3546           
3547           parent = focus->parent;
3548           if (parent)
3549             g_object_ref (parent);
3550           
3551           g_object_unref (focus);
3552           
3553           focus = parent;
3554         }
3555
3556       if (focus)
3557         g_object_unref (focus);
3558     }
3559
3560   /* Chain up, invokes binding set */
3561   if (!handled && GTK_WIDGET_CLASS (parent_class)->key_press_event)
3562     handled = GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
3563
3564   return handled;
3565 }
3566
3567 static gint
3568 gtk_window_key_release_event (GtkWidget   *widget,
3569                               GdkEventKey *event)
3570 {
3571   GtkWindow *window;
3572   gint handled;
3573   
3574   window = GTK_WINDOW (widget);
3575   handled = FALSE;
3576   if (window->focus_widget &&
3577       window->focus_widget != widget &&
3578       GTK_WIDGET_SENSITIVE (window->focus_widget))
3579     {
3580       handled = gtk_widget_event (window->focus_widget, (GdkEvent*) event);
3581     }
3582
3583   if (!handled && GTK_WIDGET_CLASS (parent_class)->key_release_event)
3584     handled = GTK_WIDGET_CLASS (parent_class)->key_release_event (widget, event);
3585
3586   return handled;
3587 }
3588
3589 static void
3590 gtk_window_real_activate_default (GtkWindow *window)
3591 {
3592   gtk_window_activate_default (window);
3593 }
3594
3595 static void
3596 gtk_window_real_activate_focus (GtkWindow *window)
3597 {
3598   gtk_window_activate_focus (window);
3599 }
3600
3601 static void
3602 gtk_window_move_focus (GtkWindow       *window,
3603                        GtkDirectionType dir)
3604 {
3605   gtk_widget_child_focus (GTK_WIDGET (window), dir);
3606   
3607   if (!GTK_CONTAINER (window)->focus_child)
3608     gtk_window_set_focus (window, NULL);
3609 }
3610
3611 static gint
3612 gtk_window_enter_notify_event (GtkWidget        *widget,
3613                                GdkEventCrossing *event)
3614 {
3615   return FALSE;
3616 }
3617
3618 static gint
3619 gtk_window_leave_notify_event (GtkWidget        *widget,
3620                                GdkEventCrossing *event)
3621 {
3622   return FALSE;
3623 }
3624
3625 static void
3626 do_focus_change (GtkWidget *widget,
3627                  gboolean   in)
3628 {
3629   GdkEventFocus fevent;
3630
3631   g_object_ref (widget);
3632    
3633  if (in)
3634     GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
3635   else
3636     GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
3637
3638   fevent.type = GDK_FOCUS_CHANGE;
3639   fevent.window = widget->window;
3640   fevent.in = in;
3641   
3642   gtk_widget_event (widget, (GdkEvent*) &fevent);
3643   
3644   g_object_notify (G_OBJECT (widget), "has_focus");
3645
3646   g_object_unref (widget);
3647 }
3648
3649 static gint
3650 gtk_window_focus_in_event (GtkWidget     *widget,
3651                            GdkEventFocus *event)
3652 {
3653   GtkWindow *window = GTK_WINDOW (widget);
3654
3655   /* It appears spurious focus in events can occur when
3656    *  the window is hidden. So we'll just check to see if
3657    *  the window is visible before actually handling the
3658    *  event
3659    */
3660   if (GTK_WIDGET_VISIBLE (widget))
3661     {
3662       window->has_focus = TRUE;
3663       
3664       if (window->focus_widget &&
3665           window->focus_widget != widget &&
3666           !GTK_WIDGET_HAS_FOCUS (window->focus_widget))
3667         do_focus_change (window->focus_widget, TRUE);   
3668     }
3669
3670   return FALSE;
3671 }
3672
3673 static gint
3674 gtk_window_focus_out_event (GtkWidget     *widget,
3675                             GdkEventFocus *event)
3676 {
3677   GtkWindow *window = GTK_WINDOW (widget);
3678
3679   window->has_focus = FALSE;
3680   
3681   if (window->focus_widget &&
3682       window->focus_widget != widget &&
3683       GTK_WIDGET_HAS_FOCUS (window->focus_widget))
3684     do_focus_change (window->focus_widget, FALSE);
3685
3686   return FALSE;
3687 }
3688
3689 static GdkAtom atom_rcfiles = GDK_NONE;
3690
3691 static void
3692 gtk_window_read_rcfiles (GtkWidget *widget,
3693                          GdkEventClient *event)
3694 {
3695   GList *embedded_windows;
3696
3697   embedded_windows = gtk_object_get_data (GTK_OBJECT (widget), "gtk-embedded");
3698   if (embedded_windows)
3699     {
3700       GdkEventClient sev;
3701       int i;
3702       
3703       for (i = 0; i < 5; i++)
3704         sev.data.l[i] = 0;
3705       sev.data_format = 32;
3706       sev.message_type = atom_rcfiles;
3707       
3708       while (embedded_windows)
3709         {
3710           guint xid = GPOINTER_TO_UINT (embedded_windows->data);
3711           gdk_event_send_client_message ((GdkEvent *) &sev, xid);
3712           embedded_windows = embedded_windows->next;
3713         }
3714     }
3715
3716   gtk_rc_reparse_all ();
3717 }
3718
3719 static gint
3720 gtk_window_client_event (GtkWidget      *widget,
3721                          GdkEventClient *event)
3722 {
3723   if (!atom_rcfiles)
3724     atom_rcfiles = gdk_atom_intern ("_GTK_READ_RCFILES", FALSE);
3725
3726   if (event->message_type == atom_rcfiles) 
3727     gtk_window_read_rcfiles (widget, event);    
3728
3729   return FALSE;
3730 }
3731
3732 static void
3733 gtk_window_check_resize (GtkContainer *container)
3734 {
3735   GtkWindow *window = GTK_WINDOW (container);
3736
3737   if (GTK_WIDGET_VISIBLE (container))
3738     gtk_window_move_resize (window);
3739 }
3740
3741 static gboolean
3742 gtk_window_focus (GtkWidget        *widget,
3743                   GtkDirectionType  direction)
3744 {
3745   GtkBin *bin;
3746   GtkWindow *window;
3747   GtkContainer *container;
3748   GtkWidget *old_focus_child;
3749   GtkWidget *parent;
3750
3751   container = GTK_CONTAINER (widget);
3752   window = GTK_WINDOW (widget);
3753   bin = GTK_BIN (widget);
3754
3755   old_focus_child = container->focus_child;
3756   
3757   /* We need a special implementation here to deal properly with wrapping
3758    * around in the tab chain without the danger of going into an
3759    * infinite loop.
3760    */
3761   if (old_focus_child)
3762     {
3763       if (gtk_widget_child_focus (old_focus_child, direction))
3764         return TRUE;
3765     }
3766
3767   if (window->focus_widget)
3768     {
3769       /* Wrapped off the end, clear the focus setting for the toplpevel */
3770       parent = window->focus_widget->parent;
3771       while (parent)
3772         {
3773           gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
3774           parent = GTK_WIDGET (parent)->parent;
3775         }
3776       
3777       gtk_window_set_focus (GTK_WINDOW (container), NULL);
3778     }
3779
3780   /* Now try to focus the first widget in the window */
3781   if (bin->child)
3782     {
3783       if (gtk_widget_child_focus (bin->child, direction))
3784         return TRUE;
3785     }
3786
3787   return FALSE;
3788 }
3789
3790 static void
3791 gtk_window_real_set_focus (GtkWindow *window,
3792                            GtkWidget *focus)
3793 {
3794   gboolean def_flags = 0;
3795
3796   if (window->default_widget)
3797     def_flags = GTK_WIDGET_HAS_DEFAULT (window->default_widget);
3798   
3799   if (window->focus_widget)
3800     {
3801       if (GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget) &&
3802           (window->focus_widget != window->default_widget))
3803         {
3804           GTK_WIDGET_UNSET_FLAGS (window->focus_widget, GTK_HAS_DEFAULT);
3805
3806           if (window->default_widget)
3807             GTK_WIDGET_SET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
3808         }
3809
3810       if (window->has_focus)
3811         do_focus_change (window->focus_widget, FALSE);
3812     }
3813   
3814   window->focus_widget = focus;
3815   
3816   if (window->focus_widget)
3817     {
3818       if (GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget) &&
3819           (window->focus_widget != window->default_widget))
3820         {
3821           if (GTK_WIDGET_CAN_DEFAULT (window->focus_widget))
3822             GTK_WIDGET_SET_FLAGS (window->focus_widget, GTK_HAS_DEFAULT);
3823
3824           if (window->default_widget)
3825             GTK_WIDGET_UNSET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
3826         }
3827
3828       if (window->has_focus)
3829         do_focus_change (window->focus_widget, TRUE);
3830     }
3831   
3832   if (window->default_widget &&
3833       (def_flags != GTK_WIDGET_FLAGS (window->default_widget)))
3834     gtk_widget_queue_draw (window->default_widget);
3835 }
3836
3837 /*********************************
3838  * Functions related to resizing *
3839  *********************************/
3840
3841 /* This function doesn't constrain to geometry hints */
3842 static void 
3843 gtk_window_compute_configure_request_size (GtkWindow *window,
3844                                            guint     *width,
3845                                            guint     *height)
3846 {
3847   GtkRequisition requisition;
3848   GtkWindowGeometryInfo *info;
3849   GtkWidget *widget;
3850
3851   /* Preconditions:
3852    *  - we've done a size request
3853    */
3854   
3855   widget = GTK_WIDGET (window);
3856
3857   info = gtk_window_get_geometry_info (window, FALSE);
3858   
3859   if (window->need_default_size)
3860     {
3861       gtk_widget_get_child_requisition (widget, &requisition);
3862
3863       /* Default to requisition */
3864       *width = requisition.width;
3865       *height = requisition.height;
3866
3867       /* If window is empty so requests 0, default to random nonzero size */
3868        if (*width == 0 && *height == 0)
3869          {
3870            *width = 200;
3871            *height = 200;
3872          }
3873
3874        /* Override requisition with default size */
3875
3876        if (info)
3877          {
3878            if (info->default_width > 0)
3879              *width = info->default_width;
3880            
3881            if (info->default_height > 0)
3882              *height = info->default_height;
3883          }
3884     }
3885   else
3886     {
3887       /* Default to keeping current size */
3888       *width = widget->allocation.width;
3889       *height = widget->allocation.height;
3890     }
3891
3892   /* Override any size with gtk_window_resize() values */
3893   if (info)
3894     {
3895       if (info->resize_width > 0)
3896         *width = info->resize_width;
3897
3898       if (info->resize_height > 0)
3899         *height = info->resize_height;
3900     }
3901 }
3902
3903 static void
3904 gtk_window_compute_configure_request (GtkWindow    *window,
3905                                       GdkRectangle *request,
3906                                       GdkGeometry  *geometry,
3907                                       guint        *flags)
3908 {
3909   GdkGeometry new_geometry;
3910   guint new_flags;
3911   int w, h;
3912   GtkWidget *widget;
3913   GtkWindowPosition pos;
3914   GtkWidget *parent_widget;
3915   GtkWindowGeometryInfo *info;
3916   int x, y;
3917   
3918   widget = GTK_WIDGET (window);
3919   
3920   gtk_widget_size_request (widget, NULL);
3921   gtk_window_compute_configure_request_size (window, &w, &h);
3922   
3923   gtk_window_compute_hints (window, &new_geometry, &new_flags);
3924   gtk_window_constrain_size (window,
3925                              &new_geometry, new_flags,
3926                              w, h,
3927                              &w, &h);
3928
3929   parent_widget = (GtkWidget*) window->transient_parent;
3930   
3931   pos = window->position;
3932   if (pos == GTK_WIN_POS_CENTER_ON_PARENT &&
3933       (parent_widget == NULL ||
3934        !GTK_WIDGET_MAPPED (parent_widget)))
3935     pos = GTK_WIN_POS_NONE;
3936
3937   info = gtk_window_get_geometry_info (window, TRUE);
3938
3939   /* by default, don't change position requested */
3940   x = info->last.configure_request.x;
3941   y = info->last.configure_request.y;
3942   
3943   if (window->need_default_position)
3944     {
3945
3946       /* FIXME this all interrelates with window gravity.
3947        * For most of them I think we want to set GRAVITY_CENTER.
3948        *
3949        * Not sure how to go about that.
3950        */
3951       
3952       switch (pos)
3953         {
3954           /* here we are only handling CENTER_ALWAYS
3955            * as it relates to default positioning,
3956            * where it's equivalent to simply CENTER
3957            */
3958         case GTK_WIN_POS_CENTER_ALWAYS:
3959         case GTK_WIN_POS_CENTER:
3960           {
3961             gint screen_width = gdk_screen_width ();
3962             gint screen_height = gdk_screen_height ();
3963             
3964             x = (screen_width - w) / 2;
3965             y = (screen_height - h) / 2;
3966           }
3967           break;
3968       
3969         case GTK_WIN_POS_CENTER_ON_PARENT:
3970           {
3971             gint ox, oy;
3972             
3973             g_assert (GTK_WIDGET_MAPPED (parent_widget)); /* established earlier */
3974             
3975             gdk_window_get_origin (parent_widget->window,
3976                                    &ox, &oy);
3977             
3978             x = ox + (parent_widget->allocation.width - w) / 2;
3979             y = oy + (parent_widget->allocation.height - h) / 2;
3980           }
3981           break;
3982
3983         case GTK_WIN_POS_MOUSE:
3984           {
3985             gint screen_width = gdk_screen_width ();
3986             gint screen_height = gdk_screen_height ();
3987             int px, py;
3988             
3989             gdk_window_get_pointer (NULL, &px, &py, NULL);
3990             x = px - w / 2;
3991             y = py - h / 2;
3992             x = CLAMP (x, 0, screen_width - w);
3993             y = CLAMP (y, 0, screen_height - h);
3994           }
3995           break;
3996
3997         default:
3998           break;
3999         }
4000     } /* if (window->need_default_position) */
4001
4002   if (window->need_default_position &&
4003       info->initial_pos_set)
4004     {
4005       x = info->initial_x;
4006       y = info->initial_y;
4007       gtk_window_constrain_position (window, w, h, &x, &y);
4008     }
4009   
4010   request->x = x;
4011   request->y = y;
4012   request->width = w;
4013   request->height = h;
4014
4015   if (geometry)
4016     *geometry = new_geometry;
4017   if (flags)
4018     *flags = new_flags;
4019 }
4020
4021 static void
4022 gtk_window_constrain_position (GtkWindow    *window,
4023                                gint          new_width,
4024                                gint          new_height,
4025                                gint         *x,
4026                                gint         *y)
4027 {
4028   /* See long comments in gtk_window_move_resize()
4029    * on when it's safe to call this function.
4030    */
4031   if (window->position == GTK_WIN_POS_CENTER_ALWAYS)
4032     {
4033       gint center_x, center_y;
4034       gint screen_width = gdk_screen_width ();
4035       gint screen_height = gdk_screen_height ();
4036       
4037       center_x = (screen_width - new_width) / 2;
4038       center_y = (screen_height - new_height) / 2;
4039       
4040       *x = center_x;
4041       *y = center_y;
4042     }
4043 }
4044
4045 static void
4046 gtk_window_move_resize (GtkWindow *window)
4047 {
4048   /* Overview:
4049    *
4050    * First we determine whether any information has changed that would
4051    * cause us to revise our last configure request.  If we would send
4052    * a different configure request from last time, then
4053    * configure_request_size_changed = TRUE or
4054    * configure_request_pos_changed = TRUE. configure_request_size_changed
4055    * may be true due to new hints, a gtk_window_resize(), or whatever.
4056    * configure_request_pos_changed may be true due to gtk_window_set_position()
4057    * or gtk_window_move().
4058    *
4059    * If the configure request has changed, we send off a new one.  To
4060    * ensure GTK+ invariants are maintained (resize queue does what it
4061    * should), we go ahead and size_allocate the requested size in this
4062    * function.
4063    *
4064    * If the configure request has not changed, we don't ever resend
4065    * it, because it could mean fighting the user or window manager.
4066    *
4067    * 
4068    *   To prepare the configure request, we come up with a base size/pos:
4069    *      - the one from gtk_window_move()/gtk_window_resize()
4070    *      - else default_width, default_height if we haven't ever
4071    *        been mapped
4072    *      - else the size request if we haven't ever been mapped,
4073    *        as a substitute default size
4074    *      - else the current size of the window, as received from
4075    *        configure notifies (i.e. the current allocation)
4076    *
4077    *   If GTK_WIN_POS_CENTER_ALWAYS is active, we constrain
4078    *   the position request to be centered.
4079    */
4080   GtkWidget *widget;
4081   GtkContainer *container;
4082   GtkWindowGeometryInfo *info;
4083   GdkGeometry new_geometry;
4084   guint new_flags;
4085   GdkRectangle new_request;
4086   gboolean configure_request_size_changed;
4087   gboolean configure_request_pos_changed;
4088   gboolean hints_changed; /* do we need to send these again */
4089   GtkWindowLastGeometryInfo saved_last_info;
4090   
4091   widget = GTK_WIDGET (window);
4092   container = GTK_CONTAINER (widget);
4093   info = gtk_window_get_geometry_info (window, TRUE);
4094   
4095   configure_request_size_changed = FALSE;
4096   configure_request_pos_changed = FALSE;
4097   
4098   gtk_window_compute_configure_request (window, &new_request,
4099                                         &new_geometry, &new_flags);  
4100   
4101   /* This check implies the invariant that we never set info->last
4102    * without setting the hints and sending off a configure request.
4103    *
4104    * If we change info->last without sending the request, we may
4105    * miss a request.
4106    */
4107   if (info->last.configure_request.x != new_request.x ||
4108       info->last.configure_request.y != new_request.y)
4109     configure_request_pos_changed = TRUE;
4110
4111   if ((info->last.configure_request.width != new_request.width ||
4112        info->last.configure_request.height != new_request.height))
4113     configure_request_size_changed = TRUE;
4114   
4115   hints_changed = FALSE;
4116   
4117   if (!gtk_window_compare_hints (&info->last.geometry, info->last.flags,
4118                                  &new_geometry, new_flags))
4119     {
4120       hints_changed = TRUE;
4121     }
4122   
4123   /* Position Constraints
4124    * ====================
4125    * 
4126    * POS_CENTER_ALWAYS is conceptually a constraint rather than
4127    * a default. The other POS_ values are used only when the
4128    * window is shown, not after that.
4129    * 
4130    * However, we can't implement a position constraint as
4131    * "anytime the window size changes, center the window"
4132    * because this may well end up fighting the WM or user.  In
4133    * fact it gets in an infinite loop with at least one WM.
4134    *
4135    * Basically, applications are in no way in a position to
4136    * constrain the position of a window, with one exception:
4137    * override redirect windows. (Really the intended purpose
4138    * of CENTER_ALWAYS anyhow, I would think.)
4139    *
4140    * So the way we implement this "constraint" is to say that when WE
4141    * cause a move or resize, i.e. we make a configure request changing
4142    * window size, we recompute the CENTER_ALWAYS position to reflect
4143    * the new window size, and include it in our request.  Also, if we
4144    * just turned on CENTER_ALWAYS we snap to center with a new
4145    * request.  Otherwise, if we are just NOTIFIED of a move or resize
4146    * done by someone else e.g. the window manager, we do NOT send a
4147    * new configure request.
4148    *
4149    * For override redirect windows, this works fine; all window
4150    * sizes are from our configure requests. For managed windows,
4151    * it is at least semi-sane, though who knows what the
4152    * app author is thinking.
4153    */
4154
4155   /* This condition should be kept in sync with the condition later on
4156    * that determines whether we send a configure request.  i.e. we
4157    * should do this position constraining anytime we were going to
4158    * send a configure request anyhow, plus when constraints have
4159    * changed.
4160    */
4161   if (configure_request_pos_changed ||
4162       configure_request_size_changed ||
4163       hints_changed ||
4164       info->position_constraints_changed)
4165     {
4166       /* We request the constrained position if:
4167        *  - we were changing position, and need to clamp
4168        *    the change to the constraint
4169        *  - we're changing the size anyway
4170        *  - set_position() was called to toggle CENTER_ALWAYS on
4171        */
4172
4173       gtk_window_constrain_position (window,
4174                                      new_request.width,
4175                                      new_request.height,
4176                                      &new_request.x,
4177                                      &new_request.y);
4178       
4179       /* Update whether we need to request a move */
4180       if (info->last.configure_request.x != new_request.x ||
4181           info->last.configure_request.y != new_request.y)
4182         configure_request_pos_changed = TRUE;
4183       else
4184         configure_request_pos_changed = FALSE;
4185     }
4186
4187 #if 0
4188   {
4189     int notify_x, notify_y;
4190
4191     /* this is the position from the last configure notify */
4192     gdk_window_get_position (widget->window, &notify_x, &notify_y);
4193     
4194     g_print ("--- %s ---\n"
4195              "last : %d,%d\t%d x %d\n"
4196              "this : %d,%d\t%d x %d\n"
4197              "alloc: %d,%d\t%d x %d\n"
4198              "req  :      \t%d x %d\n"
4199              "size_changed: %d pos_changed: %d hints_changed: %d\n"
4200              "configure_notify_received: %d\n"
4201              "configure_request_count: %d\n"
4202              "position_constraints_changed: %d\n",
4203              window->title ? window->title : "(no title)",
4204              info->last.configure_request.x,
4205              info->last.configure_request.y,
4206              info->last.configure_request.width,
4207              info->last.configure_request.height,
4208              new_request.x,
4209              new_request.y,
4210              new_request.width,
4211              new_request.height,
4212              notify_x, notify_y,
4213              widget->allocation.width,
4214              widget->allocation.height,
4215              widget->requisition.width,
4216              widget->requisition.height,
4217              configure_request_pos_changed,
4218              configure_request_size_changed,
4219              hints_changed,
4220              window->configure_notify_received,
4221              window->configure_request_count,
4222              info->position_constraints_changed);
4223   }
4224 #endif
4225   
4226   saved_last_info = info->last;
4227   info->last.geometry = new_geometry;
4228   info->last.flags = new_flags;
4229   info->last.configure_request = new_request;
4230   
4231   /* need to set PPosition so the WM will look at our position,
4232    * but we don't want to count PPosition coming and going as a hints
4233    * change for future iterations. So we saved info->last prior to
4234    * this.
4235    */
4236   
4237   /* Also, if the initial position was explicitly set, then we always
4238    * toggle on PPosition. This makes gtk_window_move(window, 0, 0)
4239    * work.
4240    */
4241
4242   /* Also, we toggle on PPosition if GTK_WIN_POS_ is in use and
4243    * this is an initial map
4244    */
4245   
4246   if ((configure_request_pos_changed ||
4247        info->initial_pos_set ||
4248        (window->need_default_position &&
4249         window->position != GTK_WIN_POS_NONE)) &&
4250       (new_flags & GDK_HINT_POS) == 0)
4251     {
4252       new_flags |= GDK_HINT_POS;
4253       hints_changed = TRUE;
4254     }
4255   
4256   /* Set hints if necessary
4257    */
4258   if (hints_changed)
4259     gdk_window_set_geometry_hints (widget->window,
4260                                    &new_geometry,
4261                                    new_flags);
4262
4263   /* handle resizing/moving and widget tree allocation
4264    */
4265   if (window->configure_notify_received)
4266     { 
4267       GtkAllocation allocation;
4268
4269       /* If we have received a configure event since
4270        * the last time in this function, we need to
4271        * accept our new size and size_allocate child widgets.
4272        * (see gtk_window_configure_event() for more details).
4273        *
4274        * 1 or more configure notifies may have been received.
4275        * Also, configure_notify_received will only be TRUE
4276        * if all expected configure notifies have been received
4277        * (one per configure request), as an optimization.
4278        *
4279        */
4280       window->configure_notify_received = FALSE;
4281
4282       /* gtk_window_configure_event() filled in widget->allocation */
4283       allocation = widget->allocation;
4284       gtk_widget_size_allocate (widget, &allocation);
4285
4286       /* If the configure request changed, it means that
4287        * we either:
4288        *   1) coincidentally changed hints or widget properties
4289        *      impacting the configure request before getting
4290        *      a configure notify, or
4291        *   2) some broken widget is changing its size request
4292        *      during size allocation, resulting in
4293        *      a false appearance of changed configure request.
4294        *
4295        * For 1), we could just go ahead and ask for the
4296        * new size right now, but doing that for 2)
4297        * might well be fighting the user (and can even
4298        * trigger a loop). Since we really don't want to
4299        * do that, we requeue a resize in hopes that
4300        * by the time it gets handled, the child has seen
4301        * the light and is willing to go along with the
4302        * new size. (this happens for the zvt widget, since
4303        * the size_allocate() above will have stored the
4304        * requisition corresponding to the new size in the
4305        * zvt widget)
4306        *
4307        * This doesn't buy us anything for 1), but it shouldn't
4308        * hurt us too badly, since it is what would have
4309        * happened if we had gotten the configure event before
4310        * the new size had been set.
4311        */
4312
4313       if (configure_request_size_changed ||
4314           configure_request_pos_changed)
4315         {
4316           /* Don't change the recorded last info after all, because we
4317            * haven't actually updated to the new info yet - we decided
4318            * to postpone our configure request until later.
4319            */
4320           info->last = saved_last_info;
4321           
4322           gtk_widget_queue_resize (widget); /* migth recurse for GTK_RESIZE_IMMEDIATE */
4323         }
4324     }
4325   else if ((configure_request_size_changed || hints_changed) &&
4326            (widget->allocation.width != new_request.width ||
4327             widget->allocation.height != new_request.height))
4328
4329     {
4330       /* We are in one of the following situations:
4331        * A. configure_request_size_changed
4332        *    our requisition has changed and we need a different window size,
4333        *    so we request it from the window manager.
4334        * B. !configure_request_size_changed && hints_changed
4335        *    the window manager rejects our size, but we have just changed the
4336        *    window manager hints, so there's a chance our request will
4337        *    be honoured this time, so we try again.
4338        *
4339        * However, if the new requisition is the same as the current allocation,
4340        * we don't request it again, since we won't get a ConfigureNotify back from
4341        * the window manager unless it decides to change our requisition. If
4342        * we don't get the ConfigureNotify back, the resize queue will never be run.
4343        */
4344
4345       /* Now send the configure request */
4346       if (configure_request_pos_changed)
4347         {
4348           if (window->frame)
4349             {
4350               gdk_window_move_resize (window->frame,
4351                                       new_request.x - window->frame_left,
4352                                       new_request.y - window->frame_top,
4353                                       new_request.width + window->frame_left + window->frame_right,
4354                                       new_request.height + window->frame_top + window->frame_bottom);
4355               gdk_window_resize (GTK_WIDGET (window)->window,
4356                                  new_request.width, new_request.height);
4357             }
4358           else
4359             gdk_window_move_resize (widget->window,
4360                                     new_request.x, new_request.y,
4361                                     new_request.width, new_request.height);
4362         }
4363       else  /* only size changed */
4364         {
4365           if (window->frame)
4366             gdk_window_resize (window->frame,
4367                                new_request.width + window->frame_left + window->frame_right,
4368                                new_request.height + window->frame_top + window->frame_bottom);
4369           gdk_window_resize (widget->window,
4370                              new_request.width, new_request.height);
4371         }
4372       
4373       /* Increment the number of have-not-yet-received-notify requests */
4374       window->configure_request_count += 1;
4375
4376       /* We have now sent a request since the last position constraint
4377        * change and definitely don't need a an initial size again (not
4378        * resetting this here can lead to infinite loops for
4379        * GTK_RESIZE_IMMEDIATE containers)
4380        */
4381       info->position_constraints_changed = FALSE;
4382       info->initial_pos_set = FALSE;
4383       info->resize_width = -1;
4384       info->resize_height = -1;
4385
4386       /* for GTK_RESIZE_QUEUE toplevels, we are now awaiting a new
4387        * configure event in response to our resizing request.
4388        * the configure event will cause a new resize with
4389        * ->configure_notify_received=TRUE.
4390        * until then, we want to
4391        * - discard expose events
4392        * - coalesce resizes for our children
4393        * - defer any window resizes until the configure event arrived
4394        * to achieve this, we queue a resize for the window, but remove its
4395        * resizing handler, so resizing will not be handled from the next
4396        * idle handler but when the configure event arrives.
4397        *
4398        * FIXME: we should also dequeue the pending redraws here, since
4399        * we handle those ourselves upon ->configure_notify_received==TRUE.
4400        */
4401       if (container->resize_mode == GTK_RESIZE_QUEUE)
4402         {
4403           gtk_widget_queue_resize (widget);
4404           _gtk_container_dequeue_resize_handler (container);
4405         }
4406     }
4407   else
4408     {
4409       /* Handle any position changes.
4410        */
4411       if (configure_request_pos_changed)
4412         {
4413           if (window->frame)
4414             {
4415               gdk_window_move (window->frame,
4416                                new_request.x - window->frame_left,
4417                                new_request.y - window->frame_top);
4418             }
4419           else
4420             gdk_window_move (widget->window,
4421                              new_request.x, new_request.y);
4422         }
4423       
4424       /* And run the resize queue.
4425        */
4426       gtk_container_resize_children (container);
4427     }
4428 }
4429
4430 /* Compare two sets of Geometry hints for equality.
4431  */
4432 static gboolean
4433 gtk_window_compare_hints (GdkGeometry *geometry_a,
4434                           guint        flags_a,
4435                           GdkGeometry *geometry_b,
4436                           guint        flags_b)
4437 {
4438   if (flags_a != flags_b)
4439     return FALSE;
4440   
4441   if ((flags_a & GDK_HINT_MIN_SIZE) &&
4442       (geometry_a->min_width != geometry_b->min_width ||
4443        geometry_a->min_height != geometry_b->min_height))
4444     return FALSE;
4445
4446   if ((flags_a & GDK_HINT_MAX_SIZE) &&
4447       (geometry_a->max_width != geometry_b->max_width ||
4448        geometry_a->max_height != geometry_b->max_height))
4449     return FALSE;
4450
4451   if ((flags_a & GDK_HINT_BASE_SIZE) &&
4452       (geometry_a->base_width != geometry_b->base_width ||
4453        geometry_a->base_height != geometry_b->base_height))
4454     return FALSE;
4455
4456   if ((flags_a & GDK_HINT_ASPECT) &&
4457       (geometry_a->min_aspect != geometry_b->min_aspect ||
4458        geometry_a->max_aspect != geometry_b->max_aspect))
4459     return FALSE;
4460
4461   if ((flags_a & GDK_HINT_RESIZE_INC) &&
4462       (geometry_a->width_inc != geometry_b->width_inc ||
4463        geometry_a->height_inc != geometry_b->height_inc))
4464     return FALSE;
4465
4466   if ((flags_a & GDK_HINT_WIN_GRAVITY) &&
4467       geometry_a->win_gravity != geometry_b->win_gravity)
4468     return FALSE;
4469
4470   return TRUE;
4471 }
4472
4473 void
4474 _gtk_window_constrain_size (GtkWindow   *window,
4475                             gint         width,
4476                             gint         height,
4477                             gint        *new_width,
4478                             gint        *new_height)
4479 {
4480   GtkWindowGeometryInfo *info;
4481
4482   g_return_if_fail (GTK_IS_WINDOW (window));
4483
4484   info = window->geometry_info;
4485   if (info)
4486     {
4487       GdkWindowHints flags = info->last.flags;
4488       GdkGeometry *geometry = &info->last.geometry;
4489       
4490       gtk_window_constrain_size (window,
4491                                  geometry,
4492                                  flags,
4493                                  width,
4494                                  height,
4495                                  new_width,
4496                                  new_height);
4497     }
4498 }
4499
4500 static void 
4501 gtk_window_constrain_size (GtkWindow   *window,
4502                            GdkGeometry *geometry,
4503                            guint        flags,
4504                            gint         width,
4505                            gint         height,
4506                            gint        *new_width,
4507                            gint        *new_height)
4508 {
4509   gdk_window_constrain_size (geometry, flags, width, height,
4510                              new_width, new_height);
4511 }
4512
4513 /* Compute the set of geometry hints and flags for a window
4514  * based on the application set geometry, and requisiition
4515  * of the window. gtk_widget_size_request() must have been
4516  * called first.
4517  */
4518 static void
4519 gtk_window_compute_hints (GtkWindow   *window,
4520                           GdkGeometry *new_geometry,
4521                           guint       *new_flags)
4522 {
4523   GtkWidget *widget;
4524   gint extra_width = 0;
4525   gint extra_height = 0;
4526   GtkWindowGeometryInfo *geometry_info;
4527   GtkRequisition requisition;
4528
4529   widget = GTK_WIDGET (window);
4530   
4531   gtk_widget_get_child_requisition (widget, &requisition);
4532   geometry_info = gtk_window_get_geometry_info (GTK_WINDOW (widget), FALSE);
4533
4534   if (geometry_info)
4535     {
4536       *new_flags = geometry_info->mask;
4537       *new_geometry = geometry_info->geometry;
4538     }
4539   else
4540     {
4541       *new_flags = 0;
4542     }
4543   
4544   if (geometry_info && geometry_info->widget)
4545     {
4546       GtkRequisition child_requisition;
4547
4548       /* FIXME: This really isn't right. It gets the min size wrong and forces
4549        * callers to do horrible hacks like set a huge usize on the child requisition
4550        * to get the base size right. We really want to find the answers to:
4551        *
4552        *  - If the geometry widget was infinitely big, how much extra space
4553        *    would be needed for the stuff around it.
4554        *
4555        *  - If the geometry widget was infinitely small, how big would the
4556        *    window still have to be.
4557        *
4558        * Finding these answers would be a bit of a mess here. (Bug #68668)
4559        */
4560       gtk_widget_get_child_requisition (geometry_info->widget, &child_requisition);
4561       
4562       extra_width = widget->requisition.width - child_requisition.width;
4563       extra_height = widget->requisition.height - child_requisition.height;
4564     }
4565
4566   /* We don't want to set GDK_HINT_POS in here, we just set it
4567    * in gtk_window_move_resize() when we want the position
4568    * honored.
4569    */
4570   
4571   if (*new_flags & GDK_HINT_BASE_SIZE)
4572     {
4573       new_geometry->base_width += extra_width;
4574       new_geometry->base_height += extra_height;
4575     }
4576   else if (!(*new_flags & GDK_HINT_MIN_SIZE) &&
4577            (*new_flags & GDK_HINT_RESIZE_INC) &&
4578            ((extra_width != 0) || (extra_height != 0)))
4579     {
4580       *new_flags |= GDK_HINT_BASE_SIZE;
4581       
4582       new_geometry->base_width = extra_width;
4583       new_geometry->base_height = extra_height;
4584     }
4585   
4586   if (*new_flags & GDK_HINT_MIN_SIZE)
4587     {
4588       if (new_geometry->min_width < 0)
4589         new_geometry->min_width = requisition.width;
4590       else
4591         new_geometry->min_width += extra_width;
4592
4593       if (new_geometry->min_height < 0)
4594         new_geometry->min_height = requisition.height;
4595       else
4596         new_geometry->min_height += extra_height;
4597     }
4598   else if (!window->allow_shrink)
4599     {
4600       *new_flags |= GDK_HINT_MIN_SIZE;
4601       
4602       new_geometry->min_width = requisition.width;
4603       new_geometry->min_height = requisition.height;
4604     }
4605   
4606   if (*new_flags & GDK_HINT_MAX_SIZE)
4607     {
4608       if (new_geometry->max_width < 0)
4609         new_geometry->max_width = requisition.width;
4610       else
4611         new_geometry->max_width += extra_width;
4612
4613       if (new_geometry->max_height < 0)
4614         new_geometry->max_width = requisition.height;
4615       else
4616         new_geometry->max_height += extra_height;
4617     }
4618   else if (!window->allow_grow)
4619     {
4620       *new_flags |= GDK_HINT_MAX_SIZE;
4621       
4622       new_geometry->max_width = requisition.width;
4623       new_geometry->max_height = requisition.height;
4624     }
4625
4626   *new_flags |= GDK_HINT_WIN_GRAVITY;
4627   new_geometry->win_gravity = window->gravity;
4628 }
4629
4630 /***********************
4631  * Redrawing functions *
4632  ***********************/
4633
4634 static void
4635 gtk_window_paint (GtkWidget     *widget,
4636                   GdkRectangle *area)
4637 {
4638   gtk_paint_flat_box (widget->style, widget->window, GTK_STATE_NORMAL, 
4639                       GTK_SHADOW_NONE, area, widget, "base", 0, 0, -1, -1);
4640 }
4641
4642 static gint
4643 gtk_window_expose (GtkWidget      *widget,
4644                    GdkEventExpose *event)
4645 {
4646   if (!GTK_WIDGET_APP_PAINTABLE (widget))
4647     gtk_window_paint (widget, &event->area);
4648   
4649   if (GTK_WIDGET_CLASS (parent_class)->expose_event)
4650     return GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
4651
4652   return FALSE;
4653 }
4654
4655 /**
4656  * gtk_window_set_has_frame:
4657  * @window: a #GtkWindow
4658  * @setting: a boolean
4659  *
4660  * (Note: this is a special-purpose function for the framebuffer port,
4661  *  that causes GTK+ to draw its own window border. For most applications,
4662  *  you want gtk_window_set_decorated() instead, which tells the window
4663  *  manager whether to draw the window border.)
4664  * 
4665  * If this function is called on a window with setting of %TRUE, before
4666  * it is realized or showed, it will have a "frame" window around
4667  * @window->window, accessible in @window->frame. Using the signal 
4668  * frame_event you can recieve all events targeted at the frame.
4669  * 
4670  * This function is used by the linux-fb port to implement managed
4671  * windows, but it could concievably be used by X-programs that
4672  * want to do their own window decorations.
4673  *
4674  **/
4675 void
4676 gtk_window_set_has_frame (GtkWindow *window, 
4677                           gboolean   setting)
4678 {
4679   g_return_if_fail (GTK_IS_WINDOW (window));
4680   g_return_if_fail (!GTK_WIDGET_REALIZED (window));
4681
4682   window->has_frame = setting != FALSE;
4683 }
4684
4685 /**
4686  * gtk_window_get_has_frame:
4687  * @window: a #GtkWindow
4688  * 
4689  * Accessor for whether the window has a frame window exterior to
4690  * @window->window. Gets the value set by gtk_window_set_has_frame ().
4691  *
4692  * Return value: %TRUE if a frame has been added to the window
4693  *   via gtk_window_set_has_frame().
4694  **/
4695 gboolean
4696 gtk_window_get_has_frame (GtkWindow *window)
4697 {
4698   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
4699
4700   return window->has_frame;
4701 }
4702
4703 /**
4704  * gtk_window_set_frame_dimensions:
4705  * @window: a #GtkWindow that has a frame
4706  * @left: The width of the left border
4707  * @top: The height of the top border
4708  * @right: The width of the right border
4709  * @bottom: The height of the bottom border
4710  *
4711  * (Note: this is a special-purpose function intended for the framebuffer
4712  *  port; see gtk_window_set_has_frame(). It will have no effect on the
4713  *  window border drawn by the window manager, which is the normal
4714  *  case when using the X Window system.)
4715  *
4716  * For windows with frames (see gtk_window_set_has_frame()) this function
4717  * can be used to change the size of the frame border.
4718  **/
4719 void
4720 gtk_window_set_frame_dimensions (GtkWindow *window, 
4721                                  gint       left,
4722                                  gint       top,
4723                                  gint       right,
4724                                  gint       bottom)
4725 {
4726   GtkWidget *widget;
4727
4728   g_return_if_fail (GTK_IS_WINDOW (window));
4729
4730   widget = GTK_WIDGET (window);
4731
4732   if (window->frame_left == left &&
4733       window->frame_top == top &&
4734       window->frame_right == right && 
4735       window->frame_bottom == bottom)
4736     return;
4737
4738   window->frame_left = left;
4739   window->frame_top = top;
4740   window->frame_right = right;
4741   window->frame_bottom = bottom;
4742
4743   if (GTK_WIDGET_REALIZED (widget) && window->frame)
4744     {
4745       gint width = widget->allocation.width + left + right;
4746       gint height = widget->allocation.height + top + bottom;
4747       gdk_window_resize (window->frame, width, height);
4748       gtk_decorated_window_move_resize_window (window,
4749                                                left, top,
4750                                                widget->allocation.width,
4751                                                widget->allocation.height);
4752     }
4753 }
4754
4755 /**
4756  * gtk_window_present:
4757  * @window: a #GtkWindow
4758  *
4759  * Presents a window to the user. This may mean raising the window
4760  * in the stacking order, deiconifying it, moving it to the current
4761  * desktop, and/or giving it the keyboard focus, possibly dependent
4762  * on the user's platform, window manager, and preferences.
4763  *
4764  * If @window is hidden, this function calls gtk_widget_show()
4765  * as well.
4766  * 
4767  * This function should be used when the user tries to open a window
4768  * that's already open. Say for example the preferences dialog is
4769  * currently open, and the user chooses Preferences from the menu
4770  * a second time; use gtk_window_present() to move the already-open dialog
4771  * where the user can see it.
4772  * 
4773  **/
4774 void
4775 gtk_window_present (GtkWindow *window)
4776 {
4777   GtkWidget *widget;
4778
4779   g_return_if_fail (GTK_IS_WINDOW (window));
4780
4781   widget = GTK_WIDGET (window);
4782
4783   if (GTK_WIDGET_VISIBLE (window))
4784     {
4785       g_assert (widget->window != NULL);
4786       
4787       gdk_window_show (widget->window);
4788
4789       /* note that gdk_window_focus() will also move the window to
4790        * the current desktop, for WM spec compliant window managers.
4791        */
4792       gdk_window_focus (widget->window,
4793                         gtk_get_current_event_time ());
4794     }
4795   else
4796     {
4797       gtk_widget_show (widget);
4798     }
4799 }
4800
4801 /**
4802  * gtk_window_iconify:
4803  * @window: a #GtkWindow
4804  *
4805  * Asks to iconify (i.e. minimize) the specified @window. Note that
4806  * you shouldn't assume the window is definitely iconified afterward,
4807  * because other entities (e.g. the user or <link
4808  * linkend="gtk-X11-arch">window manager</link>) could deiconify it
4809  * again, or there may not be a window manager in which case
4810  * iconification isn't possible, etc. But normally the window will end
4811  * up iconified. Just don't write code that crashes if not.
4812  *
4813  * It's permitted to call this function before showing a window,
4814  * in which case the window will be iconified before it ever appears
4815  * onscreen.
4816  *
4817  * You can track iconification via the "window_state_event" signal
4818  * on #GtkWidget.
4819  * 
4820  **/
4821 void
4822 gtk_window_iconify (GtkWindow *window)
4823 {
4824   GtkWidget *widget;
4825   GdkWindow *toplevel;
4826   
4827   g_return_if_fail (GTK_IS_WINDOW (window));
4828
4829   widget = GTK_WIDGET (window);
4830
4831   window->iconify_initially = TRUE;
4832
4833   if (window->frame)
4834     toplevel = window->frame;
4835   else
4836     toplevel = widget->window;
4837   
4838   if (toplevel != NULL)
4839     gdk_window_iconify (toplevel);
4840 }
4841
4842 /**
4843  * gtk_window_deiconify:
4844  * @window: a #GtkWindow
4845  *
4846  * Asks to deiconify (i.e. unminimize) the specified @window. Note
4847  * that you shouldn't assume the window is definitely deiconified
4848  * afterward, because other entities (e.g. the user or <link
4849  * linkend="gtk-X11-arch">window manager</link>) could iconify it
4850  * again before your code which assumes deiconification gets to run.
4851  *
4852  * You can track iconification via the "window_state_event" signal
4853  * on #GtkWidget.
4854  **/
4855 void
4856 gtk_window_deiconify (GtkWindow *window)
4857 {
4858   GtkWidget *widget;
4859   GdkWindow *toplevel;
4860   
4861   g_return_if_fail (GTK_IS_WINDOW (window));
4862
4863   widget = GTK_WIDGET (window);
4864
4865   window->iconify_initially = FALSE;
4866
4867   if (window->frame)
4868     toplevel = window->frame;
4869   else
4870     toplevel = widget->window;
4871   
4872   if (toplevel != NULL)
4873     gdk_window_deiconify (toplevel);
4874 }
4875
4876 /**
4877  * gtk_window_stick:
4878  * @window: a #GtkWindow
4879  *
4880  * Asks to stick @window, which means that it will appear on all user
4881  * desktops. Note that you shouldn't assume the window is definitely
4882  * stuck afterward, because other entities (e.g. the user or <link
4883  * linkend="gtk-X11-arch">window manager</link>) could unstick it
4884  * again, and some window managers do not support sticking
4885  * windows. But normally the window will end up stuck. Just don't
4886  * write code that crashes if not.
4887  *
4888  * It's permitted to call this function before showing a window.
4889  *
4890  * You can track stickiness via the "window_state_event" signal
4891  * on #GtkWidget.
4892  * 
4893  **/
4894 void
4895 gtk_window_stick (GtkWindow *window)
4896 {
4897   GtkWidget *widget;
4898   GdkWindow *toplevel;
4899   
4900   g_return_if_fail (GTK_IS_WINDOW (window));
4901
4902   widget = GTK_WIDGET (window);
4903
4904   window->stick_initially = TRUE;
4905
4906   if (window->frame)
4907     toplevel = window->frame;
4908   else
4909     toplevel = widget->window;
4910   
4911   if (toplevel != NULL)
4912     gdk_window_stick (toplevel);
4913 }
4914
4915 /**
4916  * gtk_window_unstick:
4917  * @window: a #GtkWindow
4918  *
4919  * Asks to unstick @window, which means that it will appear on only
4920  * one of the user's desktops. Note that you shouldn't assume the
4921  * window is definitely unstuck afterward, because other entities
4922  * (e.g. the user or <link linkend="gtk-X11-arch">window
4923  * manager</link>) could stick it again. But normally the window will
4924  * end up stuck. Just don't write code that crashes if not.
4925  *
4926  * You can track stickiness via the "window_state_event" signal
4927  * on #GtkWidget.
4928  * 
4929  **/
4930 void
4931 gtk_window_unstick (GtkWindow *window)
4932 {
4933   GtkWidget *widget;
4934   GdkWindow *toplevel;
4935   
4936   g_return_if_fail (GTK_IS_WINDOW (window));
4937
4938   widget = GTK_WIDGET (window);
4939
4940   window->stick_initially = FALSE;
4941
4942   if (window->frame)
4943     toplevel = window->frame;
4944   else
4945     toplevel = widget->window;
4946   
4947   if (toplevel != NULL)
4948     gdk_window_unstick (toplevel);
4949 }
4950
4951 /**
4952  * gtk_window_maximize:
4953  * @window: a #GtkWindow
4954  *
4955  * Asks to maximize @window, so that it becomes full-screen. Note that
4956  * you shouldn't assume the window is definitely maximized afterward,
4957  * because other entities (e.g. the user or <link
4958  * linkend="gtk-X11-arch">window manager</link>) could unmaximize it
4959  * again, and not all window managers support maximization. But
4960  * normally the window will end up maximized. Just don't write code
4961  * that crashes if not.
4962  *
4963  * It's permitted to call this function before showing a window,
4964  * in which case the window will be maximized when it appears onscreen
4965  * initially.
4966  *
4967  * You can track maximization via the "window_state_event" signal
4968  * on #GtkWidget.
4969  * 
4970  **/
4971 void
4972 gtk_window_maximize (GtkWindow *window)
4973 {
4974   GtkWidget *widget;
4975   GdkWindow *toplevel;
4976   
4977   g_return_if_fail (GTK_IS_WINDOW (window));
4978
4979   widget = GTK_WIDGET (window);
4980
4981   window->maximize_initially = TRUE;
4982
4983   if (window->frame)
4984     toplevel = window->frame;
4985   else
4986     toplevel = widget->window;
4987   
4988   if (toplevel != NULL)
4989     gdk_window_maximize (toplevel);
4990 }
4991
4992 /**
4993  * gtk_window_unmaximize:
4994  * @window: a #GtkWindow
4995  *
4996  * Asks to unmaximize @window. Note that you shouldn't assume the
4997  * window is definitely unmaximized afterward, because other entities
4998  * (e.g. the user or <link linkend="gtk-X11-arch">window
4999  * manager</link>) could maximize it again, and not all window
5000  * managers honor requests to unmaximize. But normally the window will
5001  * end up unmaximized. Just don't write code that crashes if not.
5002  *
5003  * You can track maximization via the "window_state_event" signal
5004  * on #GtkWidget.
5005  * 
5006  **/
5007 void
5008 gtk_window_unmaximize (GtkWindow *window)
5009 {
5010   GtkWidget *widget;
5011   GdkWindow *toplevel;
5012   
5013   g_return_if_fail (GTK_IS_WINDOW (window));
5014
5015   widget = GTK_WIDGET (window);
5016
5017   window->maximize_initially = FALSE;
5018
5019   if (window->frame)
5020     toplevel = window->frame;
5021   else
5022     toplevel = widget->window;
5023   
5024   if (toplevel != NULL)
5025     gdk_window_unmaximize (toplevel);
5026 }
5027
5028 /**
5029  * gtk_window_set_resizable:
5030  * @window: a #GtkWindow
5031  * @resizable: %TRUE if the user can resize this window
5032  *
5033  * Sets whether the user can resize a window. Windows are user resizable
5034  * by default.
5035  **/
5036 void
5037 gtk_window_set_resizable (GtkWindow *window,
5038                           gboolean   resizable)
5039 {
5040   g_return_if_fail (GTK_IS_WINDOW (window));
5041
5042   gtk_window_set_policy (window, FALSE, resizable, FALSE);
5043 }
5044
5045 /**
5046  * gtk_window_get_resizable:
5047  * @window: a #GtkWindow
5048  *
5049  * Gets the value set by gtk_window_set_resizable().
5050  *
5051  * Return value: %TRUE if the user can resize the window
5052  **/
5053 gboolean
5054 gtk_window_get_resizable (GtkWindow *window)
5055 {
5056   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
5057
5058   /* allow_grow is most likely to indicate the semantic concept we
5059    * mean by "resizable" (and will be a reliable indicator if
5060    * set_policy() hasn't been called)
5061    */
5062   return window->allow_grow;
5063 }
5064
5065 /**
5066  * gtk_window_set_gravity:
5067  * @window: a #GtkWindow
5068  * @gravity: window gravity
5069  *
5070  * Window gravity defines the meaning of coordinates passed to
5071  * gtk_window_move(). See gtk_window_move() and #GdkGravity for
5072  * more details.
5073  *
5074  * The default window gravity is #GDK_GRAVITY_NORTH_WEST which will
5075  * typically "do what you mean."
5076  *
5077  **/
5078 void
5079 gtk_window_set_gravity (GtkWindow *window,
5080                         GdkGravity gravity)
5081 {
5082   g_return_if_fail (GTK_IS_WINDOW (window));
5083
5084   if (gravity != window->gravity)
5085     {
5086       window->gravity = gravity;
5087
5088       /* gtk_window_move_resize() will adapt gravity
5089        */
5090       gtk_widget_queue_resize (GTK_WIDGET (window));
5091     }
5092 }
5093
5094 /**
5095  * gtk_window_get_gravity:
5096  * @window: a #GtkWindow
5097  *
5098  * Gets the value set by gtk_window_set_gravity().
5099  *
5100  * Return value: window gravity
5101  **/
5102 GdkGravity
5103 gtk_window_get_gravity (GtkWindow *window)
5104 {
5105   g_return_val_if_fail (GTK_IS_WINDOW (window), 0);
5106
5107   return window->gravity;
5108 }
5109
5110 /**
5111  * gtk_window_begin_resize_drag:
5112  * @window: a #GtkWindow
5113  * @button: mouse button that initiated the drag
5114  * @edge: position of the resize control
5115  * @root_x: X position where the user clicked to initiate the drag, in root window coordinates
5116  * @root_y: Y position where the user clicked to initiate the drag
5117  * @timestamp: timestamp from the click event that initiated the drag
5118  *
5119  * Starts resizing a window. This function is used if an application
5120  * has window resizing controls. When GDK can support it, the resize
5121  * will be done using the standard mechanism for the <link
5122  * linkend="gtk-X11-arch">window manager</link> or windowing
5123  * system. Otherwise, GDK will try to emulate window resizing,
5124  * potentially not all that well, depending on the windowing system.
5125  * 
5126  **/
5127 void
5128 gtk_window_begin_resize_drag  (GtkWindow    *window,
5129                                GdkWindowEdge edge,
5130                                gint          button,
5131                                gint          root_x,
5132                                gint          root_y,
5133                                guint32       timestamp)
5134 {
5135   GtkWidget *widget;
5136   GdkWindow *toplevel;
5137   
5138   g_return_if_fail (GTK_IS_WINDOW (window));
5139   g_return_if_fail (GTK_WIDGET_VISIBLE (window));
5140   
5141   widget = GTK_WIDGET (window);
5142   
5143   if (window->frame)
5144     toplevel = window->frame;
5145   else
5146     toplevel = widget->window;
5147   
5148   gdk_window_begin_resize_drag (toplevel,
5149                                 edge, button,
5150                                 root_x, root_y,
5151                                 timestamp);
5152 }
5153
5154 /**
5155  * gtk_window_get_frame_dimensions:
5156  * @window: a #GtkWindow
5157  * @left: location to store the width of the frame at the left, or %NULL
5158  * @top: location to store the height of the frame at the top, or %NULL
5159  * @right: location to store the width of the frame at the returns, or %NULL
5160  * @bottom: location to store the height of the frame at the bottom, or %NULL
5161  *
5162  * (Note: this is a special-purpose function intended for the
5163  *  framebuffer port; see gtk_window_set_has_frame(). It will not
5164  *  return the size of the window border drawn by the <link
5165  *  linkend="gtk-X11-arch">window manager</link>, which is the normal
5166  *  case when using a windowing system.  See
5167  *  gdk_window_get_frame_extents() to get the standard window border
5168  *  extents.)
5169  * 
5170  * Retrieves the dimensions of the frame window for this toplevel.
5171  * See gtk_window_set_has_frame(), gtk_window_set_frame_dimensions().
5172  **/
5173 void
5174 gtk_window_get_frame_dimensions (GtkWindow *window,
5175                                  gint      *left,
5176                                  gint      *top,
5177                                  gint      *right,
5178                                  gint      *bottom)
5179 {
5180   g_return_if_fail (GTK_IS_WINDOW (window));
5181
5182   if (left)
5183     *left = window->frame_left;
5184   if (top)
5185     *top = window->frame_top;
5186   if (right)
5187     *right = window->frame_right;
5188   if (bottom)
5189     *bottom = window->frame_bottom;
5190 }
5191
5192 /**
5193  * gtk_window_begin_move_drag:
5194  * @window: a #GtkWindow
5195  * @button: mouse button that initiated the drag
5196  * @root_x: X position where the user clicked to initiate the drag, in root window coordinates
5197  * @root_y: Y position where the user clicked to initiate the drag
5198  * @timestamp: timestamp from the click event that initiated the drag
5199  *
5200  * Starts moving a window. This function is used if an application has
5201  * window movement grips. When GDK can support it, the window movement
5202  * will be done using the standard mechanism for the <link
5203  * linkend="gtk-X11-arch">window manager</link> or windowing
5204  * system. Otherwise, GDK will try to emulate window movement,
5205  * potentially not all that well, depending on the windowing system.
5206  * 
5207  **/
5208 void
5209 gtk_window_begin_move_drag  (GtkWindow *window,
5210                              gint       button,
5211                              gint       root_x,
5212                              gint       root_y,
5213                              guint32    timestamp)
5214 {
5215   GtkWidget *widget;
5216   GdkWindow *toplevel;
5217   
5218   g_return_if_fail (GTK_IS_WINDOW (window));
5219   g_return_if_fail (GTK_WIDGET_VISIBLE (window));
5220   
5221   widget = GTK_WIDGET (window);
5222   
5223   if (window->frame)
5224     toplevel = window->frame;
5225   else
5226     toplevel = widget->window;
5227   
5228   gdk_window_begin_move_drag (toplevel,
5229                               button,
5230                               root_x, root_y,
5231                               timestamp);
5232 }
5233
5234
5235 static void
5236 gtk_window_group_class_init (GtkWindowGroupClass *klass)
5237 {
5238 }
5239
5240 GtkType
5241 gtk_window_group_get_type (void)
5242 {
5243   static GtkType window_group_type = 0;
5244
5245   if (!window_group_type)
5246     {
5247       static const GTypeInfo window_group_info =
5248       {
5249         sizeof (GtkWindowGroupClass),
5250         NULL,           /* base_init */
5251         NULL,           /* base_finalize */
5252         (GClassInitFunc) gtk_window_group_class_init,
5253         NULL,           /* class_finalize */
5254         NULL,           /* class_data */
5255         sizeof (GtkWindowGroup),
5256         16,             /* n_preallocs */
5257         (GInstanceInitFunc) NULL,
5258       };
5259
5260       window_group_type = g_type_register_static (G_TYPE_OBJECT, "GtkWindowGroup", &window_group_info, 0);
5261     }
5262
5263   return window_group_type;
5264 }
5265
5266 /**
5267  * gtk_window_group_new:
5268  * 
5269  * Creates a new #GtkWindowGroup object. Grabs added with
5270  * gtk_grab_add() only affect windows within the same #GtkWindowGroup.
5271  * 
5272  * Return value: a new #GtkWindowGroup. 
5273  **/
5274 GtkWindowGroup *
5275 gtk_window_group_new (void)
5276 {
5277   return g_object_new (GTK_TYPE_WINDOW_GROUP, NULL);
5278 }
5279
5280 static void
5281 window_group_cleanup_grabs (GtkWindowGroup *group,
5282                             GtkWindow      *window)
5283 {
5284   GSList *tmp_list;
5285   GSList *to_remove = NULL;
5286
5287   tmp_list = group->grabs;
5288   while (tmp_list)
5289     {
5290       if (gtk_widget_get_toplevel (tmp_list->data) == (GtkWidget*) window)
5291         to_remove = g_slist_prepend (to_remove, g_object_ref (tmp_list->data));
5292       tmp_list = tmp_list->next;
5293     }
5294
5295   while (to_remove)
5296     {
5297       gtk_grab_remove (to_remove->data);
5298       g_object_unref (to_remove->data);
5299       to_remove = g_slist_delete_link (to_remove, to_remove);
5300     }
5301 }
5302
5303 /**
5304  * gtk_window_group_add_window:
5305  * @window_group: a #GtkWindowGroup
5306  * @window: the #GtkWindow to add
5307  * 
5308  * Adds a window to a #GtkWindowGroup. 
5309  **/
5310 void
5311 gtk_window_group_add_window (GtkWindowGroup *window_group,
5312                              GtkWindow      *window)
5313 {
5314   g_return_if_fail (GTK_IS_WINDOW_GROUP (window_group));
5315   g_return_if_fail (GTK_IS_WINDOW (window));
5316
5317   if (window->group != window_group)
5318     {
5319       g_object_ref (window);
5320       g_object_ref (window_group);
5321       
5322       if (window->group)
5323         gtk_window_group_remove_window (window->group, window);
5324       else
5325         window_group_cleanup_grabs (_gtk_window_get_group (NULL), window);
5326
5327       window->group = window_group;
5328
5329       g_object_unref (window);
5330     }
5331 }
5332
5333 /**
5334  * gtk_window_group_remove_window:
5335  * @window_group: a #GtkWindowGroup
5336  * @window: the #GtkWindow to remove
5337  * 
5338  * Removes a window from a #GtkWindowGroup.
5339  **/
5340 void
5341 gtk_window_group_remove_window (GtkWindowGroup *window_group,
5342                                 GtkWindow      *window)
5343 {
5344   g_return_if_fail (GTK_IS_WINDOW_GROUP (window_group));
5345   g_return_if_fail (GTK_IS_WIDGET (window));
5346   g_return_if_fail (window->group == window_group);
5347
5348   g_object_ref (window);
5349
5350   window_group_cleanup_grabs (window_group, window);
5351   window->group = NULL;
5352   
5353   g_object_unref (G_OBJECT (window_group));
5354   g_object_unref (window);
5355 }
5356
5357 /* Return the group for the window or the default group
5358  */
5359 GtkWindowGroup *
5360 _gtk_window_get_group (GtkWindow *window)
5361 {
5362   if (window && window->group)
5363     return window->group;
5364   else
5365     {
5366       static GtkWindowGroup *default_group = NULL;
5367
5368       if (!default_group)
5369         default_group = gtk_window_group_new ();
5370
5371       return default_group;
5372     }
5373 }
5374
5375
5376 /*
5377   Derived from XParseGeometry() in XFree86  
5378
5379   Copyright 1985, 1986, 1987,1998  The Open Group
5380
5381   All Rights Reserved.
5382
5383   The above copyright notice and this permission notice shall be included
5384   in all copies or substantial portions of the Software.
5385
5386   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
5387   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
5388   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
5389   IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
5390   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
5391   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
5392   OTHER DEALINGS IN THE SOFTWARE.
5393
5394   Except as contained in this notice, the name of The Open Group shall
5395   not be used in advertising or otherwise to promote the sale, use or
5396   other dealings in this Software without prior written authorization
5397   from The Open Group.
5398 */
5399
5400
5401 /*
5402  *    XParseGeometry parses strings of the form
5403  *   "=<width>x<height>{+-}<xoffset>{+-}<yoffset>", where
5404  *   width, height, xoffset, and yoffset are unsigned integers.
5405  *   Example:  "=80x24+300-49"
5406  *   The equal sign is optional.
5407  *   It returns a bitmask that indicates which of the four values
5408  *   were actually found in the string.  For each value found,
5409  *   the corresponding argument is updated;  for each value
5410  *   not found, the corresponding argument is left unchanged. 
5411  */
5412
5413 /* The following code is from Xlib, and is minimally modified, so we
5414  * can track any upstream changes if required.  Don't change this
5415  * code. Or if you do, put in a huge comment marking which thing
5416  * changed.
5417  */
5418
5419 static int
5420 read_int (gchar   *string,
5421           gchar  **next)
5422 {
5423   int result = 0;
5424   int sign = 1;
5425   
5426   if (*string == '+')
5427     string++;
5428   else if (*string == '-')
5429     {
5430       string++;
5431       sign = -1;
5432     }
5433
5434   for (; (*string >= '0') && (*string <= '9'); string++)
5435     {
5436       result = (result * 10) + (*string - '0');
5437     }
5438
5439   *next = string;
5440
5441   if (sign >= 0)
5442     return (result);
5443   else
5444     return (-result);
5445 }
5446
5447 /* 
5448  * Bitmask returned by XParseGeometry().  Each bit tells if the corresponding
5449  * value (x, y, width, height) was found in the parsed string.
5450  */
5451 #define NoValue         0x0000
5452 #define XValue          0x0001
5453 #define YValue          0x0002
5454 #define WidthValue      0x0004
5455 #define HeightValue     0x0008
5456 #define AllValues       0x000F
5457 #define XNegative       0x0010
5458 #define YNegative       0x0020
5459
5460 /* Try not to reformat/modify, so we can compare/sync with X sources */
5461 static int
5462 gtk_XParseGeometry (const char   *string,
5463                     int          *x,
5464                     int          *y,
5465                     unsigned int *width,   
5466                     unsigned int *height)  
5467 {
5468   int mask = NoValue;
5469   char *strind;
5470   unsigned int tempWidth, tempHeight;
5471   int tempX, tempY;
5472   char *nextCharacter;
5473
5474   /* These initializations are just to silence gcc */
5475   tempWidth = 0;
5476   tempHeight = 0;
5477   tempX = 0;
5478   tempY = 0;
5479   
5480   if ( (string == NULL) || (*string == '\0')) return(mask);
5481   if (*string == '=')
5482     string++;  /* ignore possible '=' at beg of geometry spec */
5483
5484   strind = (char *)string;
5485   if (*strind != '+' && *strind != '-' && *strind != 'x') {
5486     tempWidth = read_int(strind, &nextCharacter);
5487     if (strind == nextCharacter) 
5488       return (0);
5489     strind = nextCharacter;
5490     mask |= WidthValue;
5491   }
5492
5493   if (*strind == 'x' || *strind == 'X') {       
5494     strind++;
5495     tempHeight = read_int(strind, &nextCharacter);
5496     if (strind == nextCharacter)
5497       return (0);
5498     strind = nextCharacter;
5499     mask |= HeightValue;
5500   }
5501
5502   if ((*strind == '+') || (*strind == '-')) {
5503     if (*strind == '-') {
5504       strind++;
5505       tempX = -read_int(strind, &nextCharacter);
5506       if (strind == nextCharacter)
5507         return (0);
5508       strind = nextCharacter;
5509       mask |= XNegative;
5510
5511     }
5512     else
5513       { strind++;
5514       tempX = read_int(strind, &nextCharacter);
5515       if (strind == nextCharacter)
5516         return(0);
5517       strind = nextCharacter;
5518       }
5519     mask |= XValue;
5520     if ((*strind == '+') || (*strind == '-')) {
5521       if (*strind == '-') {
5522         strind++;
5523         tempY = -read_int(strind, &nextCharacter);
5524         if (strind == nextCharacter)
5525           return(0);
5526         strind = nextCharacter;
5527         mask |= YNegative;
5528
5529       }
5530       else
5531         {
5532           strind++;
5533           tempY = read_int(strind, &nextCharacter);
5534           if (strind == nextCharacter)
5535             return(0);
5536           strind = nextCharacter;
5537         }
5538       mask |= YValue;
5539     }
5540   }
5541         
5542   /* If strind isn't at the end of the string the it's an invalid
5543                 geometry specification. */
5544
5545   if (*strind != '\0') return (0);
5546
5547   if (mask & XValue)
5548     *x = tempX;
5549   if (mask & YValue)
5550     *y = tempY;
5551   if (mask & WidthValue)
5552     *width = tempWidth;
5553   if (mask & HeightValue)
5554     *height = tempHeight;
5555   return (mask);
5556 }
5557
5558 /**
5559  * gtk_window_parse_geometry:
5560  * @window: a #GtkWindow
5561  * @geometry: geometry string
5562  * 
5563  * Parses a standard X Window System geometry string - see the
5564  * manual page for X (type 'man X') for details on this.
5565  * gtk_window_parse_geometry() does work on all GTK+ ports
5566  * including Win32 but is primarily intended for an X environment.
5567  *
5568  * If either a size or a position can be extracted from the
5569  * geometry string, gtk_window_parse_geometry() returns %TRUE
5570  * and calls gtk_window_set_default_size() and/or gtk_window_move()
5571  * to resize/move the window.
5572  *
5573  * If gtk_window_parse_geometry() returns %TRUE, it will also
5574  * set the #GDK_HINT_USER_POS and/or #GDK_HINT_USER_SIZE hints
5575  * indicating to the window manager that the size/position of
5576  * the window was user-specified. This causes most window
5577  * managers to honor the geometry.
5578  * 
5579  * Return value: %TRUE if string was parsed successfully
5580  **/
5581 gboolean
5582 gtk_window_parse_geometry (GtkWindow   *window,
5583                            const gchar *geometry)
5584 {
5585   gint result, x, y;
5586   guint w, h;
5587   GdkGravity grav;
5588   gboolean size_set, pos_set;
5589   
5590   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
5591   g_return_val_if_fail (geometry != NULL, FALSE);
5592   
5593   result = gtk_XParseGeometry (geometry, &x, &y, &w, &h);
5594
5595   if ((result & WidthValue) == 0 ||
5596       w < 0)
5597     w = -1;
5598   if ((result & HeightValue) == 0 ||
5599       h < 0)
5600     h = -1;
5601
5602   size_set = FALSE;
5603   if ((result & WidthValue) || (result & HeightValue))
5604     {
5605       GtkWindowGeometryInfo *info;
5606       info = gtk_window_get_geometry_info (window, FALSE);
5607       if (info && info->mask & GDK_HINT_RESIZE_INC)
5608         {
5609           w *= info->geometry.width_inc;
5610           h *= info->geometry.height_inc;
5611         }
5612       gtk_window_set_default_size (window, w, h);
5613       size_set = TRUE;
5614     }
5615
5616   gtk_window_get_size (window, &w, &h);
5617   
5618   grav = GDK_GRAVITY_NORTH_WEST;
5619
5620   if ((result & XNegative) && (result & YNegative))
5621     grav = GDK_GRAVITY_SOUTH_EAST;
5622   else if (result & XNegative)
5623     grav = GDK_GRAVITY_NORTH_EAST;
5624   else if (result & YNegative)
5625     grav = GDK_GRAVITY_SOUTH_WEST;
5626
5627   if ((result & XValue) == 0)
5628     x = 0;
5629
5630   if ((result & YValue) == 0)
5631     y = 0;
5632
5633   if (grav == GDK_GRAVITY_SOUTH_WEST ||
5634       grav == GDK_GRAVITY_SOUTH_EAST)
5635     y = gdk_screen_height () - h + y;
5636
5637   if (grav == GDK_GRAVITY_SOUTH_EAST ||
5638       grav == GDK_GRAVITY_NORTH_EAST)
5639     x = gdk_screen_width () - w + x;
5640
5641   /* we don't let you put a window offscreen; maybe some people would
5642    * prefer to be able to, but it's kind of a bogus thing to do.
5643    */
5644   if (y < 0)
5645     y = 0;
5646
5647   if (x < 0)
5648     x = 0;
5649
5650   pos_set = FALSE;
5651   if ((result & XValue) || (result & YValue))
5652     {
5653       gtk_window_set_gravity (window, grav);
5654       gtk_window_move (window, x, y);
5655       pos_set = TRUE;
5656     }
5657
5658   if (size_set || pos_set)
5659     {
5660       /* Set USSize, USPosition hints */
5661       GtkWindowGeometryInfo *info;
5662
5663       info = gtk_window_get_geometry_info (window, TRUE);
5664
5665       if (pos_set)
5666         info->mask |= GDK_HINT_USER_POS;
5667       if (size_set)
5668         info->mask |= GDK_HINT_USER_SIZE;
5669     }
5670   
5671   return result != 0;
5672 }
5673
5674 static void
5675 gtk_window_mnemonic_hash_foreach (gpointer key,
5676                                   gpointer value,
5677                                   gpointer data)
5678 {
5679   struct {
5680     GtkWindow *window;
5681     GtkWindowKeysForeachFunc func;
5682     gpointer func_data;
5683   } *info = data;
5684
5685   GtkWindowMnemonic *mnemonic = value;
5686
5687   if (mnemonic->window == info->window)
5688     (*info->func) (info->window, mnemonic->keyval, info->window->mnemonic_modifier, TRUE, info->func_data);
5689 }
5690
5691 void
5692 _gtk_window_keys_foreach (GtkWindow                *window,
5693                           GtkWindowKeysForeachFunc func,
5694                           gpointer                 func_data)
5695 {
5696   GSList *groups;
5697
5698   struct {
5699     GtkWindow *window;
5700     GtkWindowKeysForeachFunc func;
5701     gpointer func_data;
5702   } info;
5703
5704   info.window = window;
5705   info.func = func;
5706   info.func_data = func_data;
5707
5708   g_hash_table_foreach (mnemonic_hash_table,
5709                         gtk_window_mnemonic_hash_foreach,
5710                         &info);
5711
5712   groups = gtk_accel_groups_from_object (G_OBJECT (window));
5713   while (groups)
5714     {
5715       GtkAccelGroup *group = groups->data;
5716       gint i;
5717
5718       for (i = 0; i < group->n_accels; i++)
5719         {
5720           GtkAccelKey *key = &group->priv_accels[i].key;
5721           
5722           if (key->accel_key)
5723             (*func) (window, key->accel_key, key->accel_mods, FALSE, func_data);
5724         }
5725       
5726       groups = groups->next;
5727     }
5728 }
5729
5730 static void
5731 gtk_window_keys_changed (GtkWindow *window)
5732 {
5733   gtk_window_free_key_hash (window);
5734   gtk_window_get_key_hash (window);
5735 }
5736
5737 typedef struct _GtkWindowKeyEntry GtkWindowKeyEntry;
5738
5739 struct _GtkWindowKeyEntry
5740 {
5741   guint keyval;
5742   guint modifiers;
5743   gboolean is_mnemonic;
5744 };
5745
5746 static void
5747 add_to_key_hash (GtkWindow      *window,
5748                  guint           keyval,
5749                  GdkModifierType modifiers,
5750                  gboolean        is_mnemonic,
5751                  gpointer        data)
5752 {
5753   GtkKeyHash *key_hash = data;
5754
5755   GtkWindowKeyEntry *entry = g_new (GtkWindowKeyEntry, 1);
5756
5757   entry->keyval = keyval;
5758   entry->modifiers = modifiers;
5759   entry->is_mnemonic = is_mnemonic;
5760
5761   /* GtkAccelGroup stores lowercased accelerators. To deal
5762    * with this, if <Shift> was specified, uppercase.
5763    */
5764   if (modifiers & GDK_SHIFT_MASK)
5765     {
5766       if (keyval == GDK_Tab)
5767         keyval = GDK_ISO_Left_Tab;
5768       else
5769         keyval = gdk_keyval_to_upper (keyval);
5770     }
5771   
5772   _gtk_key_hash_add_entry (key_hash, keyval, entry->modifiers, entry);
5773 }
5774
5775 static GtkKeyHash *
5776 gtk_window_get_key_hash (GtkWindow *window)
5777 {
5778   GtkKeyHash *key_hash = g_object_get_data (G_OBJECT (window), "gtk-window-key-hash");
5779   if (key_hash)
5780     return key_hash;
5781   
5782   key_hash = _gtk_key_hash_new (gdk_keymap_get_default(), (GDestroyNotify)g_free);
5783   _gtk_window_keys_foreach (window, add_to_key_hash, key_hash);
5784   g_object_set_data (G_OBJECT (window), "gtk-window-key-hash", key_hash);
5785
5786   return key_hash;
5787 }
5788
5789 static void
5790 gtk_window_free_key_hash (GtkWindow *window)
5791 {
5792   GtkKeyHash *key_hash = g_object_get_data (G_OBJECT (window), "gtk-window-key-hash");
5793   if (key_hash)
5794     {
5795       _gtk_key_hash_free (key_hash);
5796       g_object_set_data (G_OBJECT (window), "gtk-window-key-hash", NULL);
5797     }
5798 }
5799
5800 /**
5801  * _gtk_window_activate_key:
5802  * @window: a #GtkWindow
5803  * @event: a #GdkEventKey
5804  * 
5805  * Activates mnemonics and accelerators for this #GtKWindow
5806  * 
5807  * Return value: %TRUE if a mnemonic or accelerator was found and activated.
5808  **/
5809 gboolean
5810 _gtk_window_activate_key (GtkWindow   *window,
5811                           GdkEventKey *event)
5812 {
5813   GtkKeyHash *key_hash = g_object_get_data (G_OBJECT (window), "gtk-window-key-hash");
5814   GtkWindowKeyEntry *found_entry = NULL;
5815
5816   if (!key_hash)
5817     {
5818       gtk_window_keys_changed (window);
5819       key_hash = g_object_get_data (G_OBJECT (window), "gtk-window-key-hash");
5820     }
5821   
5822   if (key_hash)
5823     {
5824       GSList *entries = _gtk_key_hash_lookup (key_hash,
5825                                               event->hardware_keycode,
5826                                               event->state & gtk_accelerator_get_default_mod_mask (),
5827                                               event->group);
5828       GSList *tmp_list;
5829
5830       for (tmp_list = entries; tmp_list; tmp_list = tmp_list->next)
5831         {
5832           GtkWindowKeyEntry *entry = tmp_list->data;
5833           if (entry->is_mnemonic)
5834             {
5835               found_entry = entry;
5836               break;
5837             }
5838         }
5839       
5840       if (!found_entry && entries)
5841         found_entry = entries->data;
5842
5843       g_slist_free (entries);
5844     }
5845
5846   if (found_entry)
5847     {
5848       if (found_entry->is_mnemonic)
5849         return gtk_window_mnemonic_activate (window, found_entry->keyval, found_entry->modifiers);
5850       else
5851         return gtk_accel_groups_activate (G_OBJECT (window), found_entry->keyval, found_entry->modifiers);
5852     }
5853   else
5854     return FALSE;
5855 }