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