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