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