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