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