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