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