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