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