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