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