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