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