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