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