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