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