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