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