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