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