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