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