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