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