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