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