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