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