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