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