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