]> Pileus Git - ~andy/gtk/blob - gtk/gtkwindow.c
add "resizable" property
[~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 <string.h>
28 #include <limits.h>
29 #include "gdk/gdk.h"
30 #include "gdk/gdkkeysyms.h"
31
32 #if defined (GDK_WINDOWING_X11)
33 #include "x11/gdkx.h"
34 #elif defined (GDK_WINDOWING_WIN32)
35 #include "win32/gdkwin32.h"
36 #elif defined (GDK_WINDOWING_NANOX)
37 #include "nanox/gdkprivate-nanox.h"
38 #elif defined (GDK_WINDOWING_FB)
39 #include "linux-fb/gdkfb.h"
40 #endif
41
42 #include "gtkprivate.h"
43 #include "gtkrc.h"
44 #include "gtksignal.h"
45 #include "gtkwindow.h"
46 #include "gtkwindow-decorate.h"
47 #include "gtkbindings.h"
48 #include "gtkmain.h"
49 #include "gtkiconfactory.h"
50 #include "gtkintl.h"
51
52 enum {
53   SET_FOCUS,
54   FRAME_EVENT,
55   ACTIVATE_FOCUS,
56   ACTIVATE_DEFAULT,
57   MOVE_FOCUS,
58   LAST_SIGNAL
59 };
60
61 enum {
62   PROP_0,
63
64   /* Construct */
65   PROP_TYPE,
66
67   /* Style Props */
68   PROP_TITLE,
69   PROP_AUTO_SHRINK,
70   PROP_ALLOW_SHRINK,
71   PROP_ALLOW_GROW,
72   PROP_RESIZABLE,
73   PROP_MODAL,
74   PROP_WIN_POS,
75   PROP_DEFAULT_WIDTH,
76   PROP_DEFAULT_HEIGHT,
77   PROP_DESTROY_WITH_PARENT,
78
79   LAST_ARG
80 };
81
82 typedef struct {
83   GdkGeometry    geometry; /* Last set of geometry hints we set */
84   GdkWindowHints flags;
85   gint           width;
86   gint           height;
87 } GtkWindowLastGeometryInfo;
88
89 struct _GtkWindowGeometryInfo
90 {
91   /* Properties that the app has set on the window
92    */
93   GdkGeometry    geometry;      /* Geometry hints */
94   GdkWindowHints mask;
95   GtkWidget     *widget;        /* subwidget to which hints apply */
96   gint           width;         /* Default size */
97   gint           height;
98   guint          may_shrink : 1; /* one-shot auto_shrink behaviour after set_default_size */
99
100   GtkWindowLastGeometryInfo last;
101 };
102
103 typedef struct {
104   GtkWindow *window;
105   guint keyval;
106
107   GSList *targets;
108 } GtkWindowMnemonic;
109
110
111 static void gtk_window_class_init         (GtkWindowClass    *klass);
112 static void gtk_window_init               (GtkWindow         *window);
113 static void gtk_window_shutdown           (GObject           *object);
114 static void gtk_window_destroy            (GtkObject         *object);
115 static void gtk_window_finalize           (GObject           *object);
116 static void gtk_window_show               (GtkWidget         *widget);
117 static void gtk_window_hide               (GtkWidget         *widget);
118 static void gtk_window_map                (GtkWidget         *widget);
119 static void gtk_window_unmap              (GtkWidget         *widget);
120 static void gtk_window_realize            (GtkWidget         *widget);
121 static void gtk_window_unrealize          (GtkWidget         *widget);
122 static void gtk_window_size_request       (GtkWidget         *widget,
123                                            GtkRequisition    *requisition);
124 static void gtk_window_size_allocate      (GtkWidget         *widget,
125                                            GtkAllocation     *allocation);
126 static gint gtk_window_event              (GtkWidget *widget,
127                                            GdkEvent *event);
128 static gboolean gtk_window_frame_event    (GtkWidget *widget,
129                                            GdkEvent *event);
130 static gint gtk_window_configure_event    (GtkWidget         *widget,
131                                            GdkEventConfigure *event);
132 static gint gtk_window_key_press_event    (GtkWidget         *widget,
133                                            GdkEventKey       *event);
134 static gint gtk_window_key_release_event  (GtkWidget         *widget,
135                                            GdkEventKey       *event);
136 static gint gtk_window_enter_notify_event (GtkWidget         *widget,
137                                            GdkEventCrossing  *event);
138 static gint gtk_window_leave_notify_event (GtkWidget         *widget,
139                                            GdkEventCrossing  *event);
140 static gint gtk_window_focus_in_event     (GtkWidget         *widget,
141                                            GdkEventFocus     *event);
142 static gint gtk_window_focus_out_event    (GtkWidget         *widget,
143                                            GdkEventFocus     *event);
144 static gint gtk_window_client_event       (GtkWidget         *widget,
145                                            GdkEventClient    *event);
146 static void gtk_window_check_resize       (GtkContainer      *container);
147 static gint gtk_window_focus              (GtkWidget        *widget,
148                                            GtkDirectionType  direction);
149 static void gtk_window_real_set_focus     (GtkWindow         *window,
150                                            GtkWidget         *focus);
151
152 static void gtk_window_real_activate_default (GtkWindow         *window);
153 static void gtk_window_real_activate_focus   (GtkWindow         *window);
154 static void gtk_window_move_focus            (GtkWindow         *window,
155                                               GtkDirectionType   dir);
156
157 static void gtk_window_move_resize        (GtkWindow         *window);
158 static gboolean gtk_window_compare_hints  (GdkGeometry       *geometry_a,
159                                            guint              flags_a,
160                                            GdkGeometry       *geometry_b,
161                                            guint              flags_b);
162 static void gtk_window_compute_default_size (GtkWindow       *window,
163                                              guint           *width,
164                                              guint           *height);
165 static void  gtk_window_constrain_size      (GtkWindow       *window,
166                                              GdkGeometry     *geometry,
167                                              guint            flags,
168                                              gint             width,
169                                              gint             height,
170                                              gint            *new_width,
171                                              gint            *new_height);
172 static void gtk_window_compute_hints      (GtkWindow         *window, 
173                                            GdkGeometry       *new_geometry,
174                                            guint             *new_flags);
175 static gint gtk_window_compute_reposition (GtkWindow         *window,
176                                            gint               new_width,
177                                            gint               new_height,
178                                            gint              *x,
179                                            gint              *y);
180
181 static void gtk_window_read_rcfiles       (GtkWidget         *widget,
182                                            GdkEventClient    *event);
183 static void gtk_window_paint              (GtkWidget         *widget,
184                                            GdkRectangle      *area);
185 static gint gtk_window_expose             (GtkWidget         *widget,
186                                            GdkEventExpose    *event);
187 static void gtk_window_unset_transient_for         (GtkWindow  *window);
188 static void gtk_window_transient_parent_realized   (GtkWidget  *parent,
189                                                     GtkWidget  *window);
190 static void gtk_window_transient_parent_unrealized (GtkWidget  *parent,
191                                                     GtkWidget  *window);
192
193 static GtkWindowGeometryInfo* gtk_window_get_geometry_info (GtkWindow *window,
194                                                             gboolean   create);
195
196
197 static GSList      *toplevel_list = NULL;
198 static GHashTable  *mnemonic_hash_table = NULL;
199 static GtkBinClass *parent_class = NULL;
200 static guint        window_signals[LAST_SIGNAL] = { 0 };
201
202 static void gtk_window_set_property (GObject         *object,
203                                      guint            prop_id,
204                                      const GValue    *value,
205                                      GParamSpec      *pspec);
206 static void gtk_window_get_property (GObject         *object,
207                                      guint            prop_id,
208                                      GValue          *value,
209                                      GParamSpec      *pspec);
210
211
212 static guint
213 mnemonic_hash (gconstpointer key)
214 {
215   const GtkWindowMnemonic *k;
216   guint h;
217   
218   k = (GtkWindowMnemonic *)key;
219   
220   h = (gulong) k->window;
221   h ^= k->keyval << 16;
222   h ^= k->keyval >> 16;
223
224   return h;
225 }
226
227 static gboolean
228 mnemonic_equal (gconstpointer a, gconstpointer b)
229 {
230   const GtkWindowMnemonic *ka;
231   const GtkWindowMnemonic *kb;
232   
233   ka = (GtkWindowMnemonic *)a;
234   kb = (GtkWindowMnemonic *)b;
235
236   return
237     (ka->window == kb->window) &&
238     (ka->keyval == kb->keyval);
239 }
240
241 GtkType
242 gtk_window_get_type (void)
243 {
244   static GtkType window_type = 0;
245
246   if (!window_type)
247     {
248       static const GtkTypeInfo window_info =
249       {
250         "GtkWindow",
251         sizeof (GtkWindow),
252         sizeof (GtkWindowClass),
253         (GtkClassInitFunc) gtk_window_class_init,
254         (GtkObjectInitFunc) gtk_window_init,
255         /* reserved_1 */ NULL,
256         /* reserved_2 */ NULL,
257         (GtkClassInitFunc) NULL,
258       };
259
260       window_type = gtk_type_unique (gtk_bin_get_type (), &window_info);
261     }
262
263   return window_type;
264 }
265
266 static void
267 gtk_window_class_init (GtkWindowClass *klass)
268 {
269   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
270   GtkObjectClass *object_class;
271   GtkWidgetClass *widget_class;
272   GtkContainerClass *container_class;
273   GtkBindingSet *binding_set;
274   
275   object_class = (GtkObjectClass*) klass;
276   widget_class = (GtkWidgetClass*) klass;
277   container_class = (GtkContainerClass*) klass;
278   
279   parent_class = gtk_type_class (gtk_bin_get_type ());
280
281   gobject_class->shutdown = gtk_window_shutdown;
282   gobject_class->finalize = gtk_window_finalize;
283
284   gobject_class->set_property = gtk_window_set_property;
285   gobject_class->get_property = gtk_window_get_property;
286   
287   object_class->destroy = gtk_window_destroy;
288
289   widget_class->show = gtk_window_show;
290   widget_class->hide = gtk_window_hide;
291   widget_class->map = gtk_window_map;
292   widget_class->unmap = gtk_window_unmap;
293   widget_class->realize = gtk_window_realize;
294   widget_class->unrealize = gtk_window_unrealize;
295   widget_class->size_request = gtk_window_size_request;
296   widget_class->size_allocate = gtk_window_size_allocate;
297   widget_class->configure_event = gtk_window_configure_event;
298   widget_class->key_press_event = gtk_window_key_press_event;
299   widget_class->key_release_event = gtk_window_key_release_event;
300   widget_class->enter_notify_event = gtk_window_enter_notify_event;
301   widget_class->leave_notify_event = gtk_window_leave_notify_event;
302   widget_class->focus_in_event = gtk_window_focus_in_event;
303   widget_class->focus_out_event = gtk_window_focus_out_event;
304   widget_class->client_event = gtk_window_client_event;
305   widget_class->focus = gtk_window_focus;
306   
307   widget_class->expose_event = gtk_window_expose;
308    
309   container_class->check_resize = gtk_window_check_resize;
310
311   klass->set_focus = gtk_window_real_set_focus;
312   klass->frame_event = gtk_window_frame_event;
313
314   klass->activate_default = gtk_window_real_activate_default;
315   klass->activate_focus = gtk_window_real_activate_focus;
316   klass->move_focus = gtk_window_move_focus;
317   
318   /* Construct */
319   g_object_class_install_property (gobject_class,
320                                    PROP_TYPE,
321                                    g_param_spec_enum ("type",
322                                                       _("Window Type"),
323                                                       _("The type of the window"),
324                                                       GTK_TYPE_WINDOW_TYPE,
325                                                       GTK_WINDOW_TOPLEVEL,
326                                                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
327
328   /* Style Props */
329   g_object_class_install_property (gobject_class,
330                                    PROP_TITLE,
331                                    g_param_spec_string ("title",
332                                                         _("Window Title"),
333                                                         _("The title of the window"),
334                                                         NULL,
335                                                         G_PARAM_READWRITE));
336
337   g_object_class_install_property (gobject_class,
338                                    PROP_AUTO_SHRINK,
339                                    g_param_spec_boolean ("auto_shrink",
340                                                          _("Auto Shrink"),
341                                                          _("If TRUE, the window automatically shrinks to its size request anytime a resize occurs. Don't use this feature, it makes no sense."),
342                                                          FALSE,
343                                                          G_PARAM_READWRITE));
344
345   g_object_class_install_property (gobject_class,
346                                    PROP_ALLOW_SHRINK,
347                                    g_param_spec_boolean ("allow_shrink",
348                                                          _("Allow Shrink"),
349                                                          _("If TRUE, the window has no mimimum size. Don't use this feature, it makes no sense."),
350                                                          FALSE,
351                                                          G_PARAM_READWRITE));
352
353   g_object_class_install_property (gobject_class,
354                                    PROP_ALLOW_GROW,
355                                    g_param_spec_boolean ("allow_grow",
356                                                          _("Allow Grow"),
357                                                          _("If TRUE, users can expand the window beyond its minimum size."),
358                                                          TRUE,
359                                                          G_PARAM_READWRITE));
360
361   g_object_class_install_property (gobject_class,
362                                    PROP_RESIZABLE,
363                                    g_param_spec_boolean ("resizable",
364                                                          _("Resizable"),
365                                                          _("If TRUE, users can resize the window."),
366                                                          TRUE,
367                                                          G_PARAM_READWRITE));
368   
369   g_object_class_install_property (gobject_class,
370                                    PROP_MODAL,
371                                    g_param_spec_boolean ("modal",
372                                                          _("Modal"),
373                                                          _("If TRUE, the window is modal (other windows are not usable while this one is up)."),
374                                                          FALSE,
375                                                          G_PARAM_READWRITE));
376
377   g_object_class_install_property (gobject_class,
378                                    PROP_WIN_POS,
379                                    g_param_spec_enum ("window_position",
380                                                       _("Window Position"),
381                                                       _("The initial position of the window."),
382                                                       GTK_TYPE_WINDOW_POSITION,
383                                                       GTK_WIN_POS_NONE,
384                                                       G_PARAM_READWRITE));
385  
386   g_object_class_install_property (gobject_class,
387                                    PROP_DEFAULT_WIDTH,
388                                    g_param_spec_int ("default_width",
389                                                      _("Default Width"),
390                                                      _("The default width of the window, or 0 to use the size request."),
391                                                      0,
392                                                      G_MAXINT,
393                                                      0,
394                                                      G_PARAM_READWRITE));
395  
396   g_object_class_install_property (gobject_class,
397                                    PROP_DEFAULT_HEIGHT,
398                                    g_param_spec_int ("default_height",
399                                                      _("Default Height"),
400                                                      _("The default height of the windo, or 0 to use the size request."),
401                                                      0,
402                                                      G_MAXINT,
403                                                      0,
404                                                      G_PARAM_READWRITE));
405  
406   g_object_class_install_property (gobject_class,
407                                    PROP_DESTROY_WITH_PARENT,
408                                    g_param_spec_boolean ("destroy_with_parent",
409                                                          _("Destroy with Parent"),
410                                                          _("If this window should be destroyed when the parent is destroyed,"),
411                                                          FALSE,
412                                                          G_PARAM_READWRITE));
413
414   /* Style props are set or not */
415
416   window_signals[SET_FOCUS] =
417     g_signal_newc ("set_focus",
418                    G_TYPE_FROM_CLASS (object_class),
419                    G_SIGNAL_RUN_LAST,
420                    G_STRUCT_OFFSET (GtkWindowClass, set_focus),
421                    NULL, NULL,
422                    gtk_marshal_VOID__OBJECT,
423                    G_TYPE_NONE, 1,
424                    GTK_TYPE_WIDGET);
425   
426   window_signals[FRAME_EVENT] =
427     g_signal_newc ("frame_event",
428                    G_TYPE_FROM_CLASS(object_class),
429                    G_SIGNAL_RUN_LAST,
430                    G_STRUCT_OFFSET(GtkWindowClass, frame_event),
431                    _gtk_boolean_handled_accumulator, NULL,
432                    gtk_marshal_BOOLEAN__BOXED,
433                    G_TYPE_BOOLEAN, 1,
434                    GDK_TYPE_EVENT);
435
436   window_signals[ACTIVATE_FOCUS] =
437     g_signal_newc ("activate_focus",
438                    G_OBJECT_CLASS_TYPE (object_class),
439                    G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
440                    GTK_SIGNAL_OFFSET (GtkWindowClass, activate_focus),
441                    NULL, NULL,
442                    gtk_marshal_VOID__VOID,
443                    G_TYPE_NONE,
444                    0);
445
446   window_signals[ACTIVATE_DEFAULT] =
447     g_signal_newc ("activate_default",
448                    G_OBJECT_CLASS_TYPE (object_class),
449                    G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
450                    GTK_SIGNAL_OFFSET (GtkWindowClass, activate_default),
451                    NULL, NULL,
452                    gtk_marshal_VOID__VOID,
453                    G_TYPE_NONE,
454                    0);
455
456   window_signals[MOVE_FOCUS] =
457     g_signal_newc ("move_focus",
458                    G_OBJECT_CLASS_TYPE (object_class),
459                    G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
460                    GTK_SIGNAL_OFFSET (GtkWindowClass, move_focus),
461                    NULL, NULL,
462                    gtk_marshal_VOID__ENUM,
463                    G_TYPE_NONE,
464                    1,
465                    GTK_TYPE_DIRECTION_TYPE);
466   
467   if (!mnemonic_hash_table)
468     mnemonic_hash_table = g_hash_table_new (mnemonic_hash,
469                                             mnemonic_equal);
470
471   /*
472    * Key bindings
473    */
474
475   binding_set = gtk_binding_set_by_class (klass);
476
477   gtk_binding_entry_add_signal (binding_set, GDK_space, 0,
478                                 "activate_focus", 0);
479
480   gtk_binding_entry_add_signal (binding_set, GDK_Return, 0,
481                                 "activate_default", 0);
482
483   gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0,
484                                 "activate_default", 0);
485
486   gtk_binding_entry_add_signal (binding_set, GDK_Up, 0,
487                                 "move_focus", 1,
488                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_UP);
489   gtk_binding_entry_add_signal (binding_set, GDK_KP_Up, 0,
490                                 "move_focus", 1,
491                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_UP);
492
493   gtk_binding_entry_add_signal (binding_set, GDK_Down, 0,
494                                 "move_focus", 1,
495                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_DOWN);
496   gtk_binding_entry_add_signal (binding_set, GDK_KP_Down, 0,
497                                 "move_focus", 1,
498                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_DOWN);
499
500   gtk_binding_entry_add_signal (binding_set, GDK_Left, 0,
501                                 "move_focus", 1,
502                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_LEFT);
503   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0,
504                                 "move_focus", 1,
505                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_LEFT);  
506
507   gtk_binding_entry_add_signal (binding_set, GDK_Right, 0,
508                                 "move_focus", 1,
509                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_RIGHT);
510   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0,
511                                 "move_focus", 1,
512                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_RIGHT);  
513
514   gtk_binding_entry_add_signal (binding_set, GDK_Tab, 0,
515                                 "move_focus", 1,
516                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_FORWARD);
517   gtk_binding_entry_add_signal (binding_set, GDK_ISO_Left_Tab, 0,
518                                 "move_focus", 1,
519                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_FORWARD);
520
521   gtk_binding_entry_add_signal (binding_set, GDK_Tab, GDK_SHIFT_MASK,
522                                 "move_focus", 1,
523                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_BACKWARD);
524   gtk_binding_entry_add_signal (binding_set, GDK_ISO_Left_Tab, GDK_SHIFT_MASK,
525                                 "move_focus", 1,
526                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_BACKWARD);
527 }
528
529 static void
530 gtk_window_init (GtkWindow *window)
531 {
532   GTK_WIDGET_UNSET_FLAGS (window, GTK_NO_WINDOW);
533   GTK_WIDGET_SET_FLAGS (window, GTK_TOPLEVEL);
534
535   GTK_PRIVATE_SET_FLAG (window, GTK_ANCHORED);
536
537   gtk_container_set_resize_mode (GTK_CONTAINER (window), GTK_RESIZE_QUEUE);
538
539   window->title = NULL;
540   window->wmclass_name = g_strdup (g_get_prgname ());
541   window->wmclass_class = g_strdup (gdk_progclass);
542   window->wm_role = NULL;
543   window->geometry_info = NULL;
544   window->type = GTK_WINDOW_TOPLEVEL;
545   window->focus_widget = NULL;
546   window->default_widget = NULL;
547   window->resize_count = 0;
548   window->allow_shrink = FALSE;
549   window->allow_grow = TRUE;
550   window->auto_shrink = FALSE;
551   window->handling_resize = FALSE;
552   window->position = GTK_WIN_POS_NONE;
553   window->use_uposition = TRUE;
554   window->modal = FALSE;
555   window->frame = NULL;
556   window->has_frame = FALSE;
557   window->frame_left = 0;
558   window->frame_right = 0;
559   window->frame_top = 0;
560   window->frame_bottom = 0;
561   window->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
562   window->gravity = GDK_GRAVITY_NORTH_WEST;
563   window->decorated = TRUE;
564   window->mnemonic_modifier = GDK_MOD1_MASK;
565   
566   gtk_widget_ref (GTK_WIDGET (window));
567   gtk_object_sink (GTK_OBJECT (window));
568   window->has_user_ref_count = TRUE;
569   toplevel_list = g_slist_prepend (toplevel_list, window);
570
571   gtk_decorated_window_init (window);
572
573   gtk_signal_connect (GTK_OBJECT (window),
574                       "event",
575                       GTK_SIGNAL_FUNC (gtk_window_event),
576                       NULL);
577 }
578
579 static void
580 gtk_window_set_property (GObject      *object,
581                          guint         prop_id,
582                          const GValue *value,
583                          GParamSpec   *pspec)
584 {
585   GtkWindow  *window;
586
587   window = GTK_WINDOW (object);
588
589   switch (prop_id)
590     {
591     case PROP_TYPE:
592       window->type = g_value_get_enum (value);
593       break;
594     case PROP_TITLE:
595       gtk_window_set_title (window, g_value_get_string (value));
596       break;
597     case PROP_AUTO_SHRINK:
598       window->auto_shrink = g_value_get_boolean (value);
599       gtk_widget_queue_resize (GTK_WIDGET (window));
600       break;
601     case PROP_ALLOW_SHRINK:
602       window->allow_shrink = g_value_get_boolean (value);
603       gtk_widget_queue_resize (GTK_WIDGET (window));
604       break;
605     case PROP_ALLOW_GROW:
606       window->allow_grow = g_value_get_boolean (value);
607       gtk_widget_queue_resize (GTK_WIDGET (window));
608       g_object_notify (G_OBJECT (window), "resizable");
609       break;
610     case PROP_RESIZABLE:
611       window->allow_grow = g_value_get_boolean (value);
612       gtk_widget_queue_resize (GTK_WIDGET (window));
613       g_object_notify (G_OBJECT (window), "allow_grow");
614       break;
615     case PROP_MODAL:
616       gtk_window_set_modal (window, g_value_get_boolean (value));
617       break;
618     case PROP_WIN_POS:
619       gtk_window_set_position (window, g_value_get_enum (value));
620       break;
621     case PROP_DEFAULT_WIDTH:
622       gtk_window_set_default_size (window, g_value_get_int (value), -1);
623       break;
624     case PROP_DEFAULT_HEIGHT:
625       gtk_window_set_default_size (window, -1, g_value_get_int (value));
626       break;
627     case PROP_DESTROY_WITH_PARENT:
628       gtk_window_set_destroy_with_parent (window, g_value_get_boolean (value));
629       break;
630     default:
631       break;
632     }
633 }
634
635 static void
636 gtk_window_get_property (GObject      *object,
637                          guint         prop_id,
638                          GValue       *value,
639                          GParamSpec   *pspec)
640 {
641   GtkWindow  *window;
642
643   window = GTK_WINDOW (object);
644
645   switch (prop_id)
646     {
647       GtkWindowGeometryInfo *info;
648     case PROP_TYPE:
649       g_value_set_enum (value, window->type);
650       break;
651     case PROP_TITLE:
652       g_value_set_string (value, window->title);
653       break;
654     case PROP_AUTO_SHRINK:
655       g_value_set_boolean (value, window->auto_shrink);
656       break;
657     case PROP_ALLOW_SHRINK:
658       g_value_set_boolean (value, window->allow_shrink);
659       break;
660     case PROP_ALLOW_GROW:
661       g_value_set_boolean (value, window->allow_grow);
662       break;
663     case PROP_RESIZABLE:
664       g_value_set_boolean (value, window->allow_grow);
665       break;
666     case PROP_MODAL:
667       g_value_set_boolean (value, window->modal);
668       break;
669     case PROP_WIN_POS:
670       g_value_set_enum (value, window->position);
671       break;
672     case PROP_DEFAULT_WIDTH:
673       info = gtk_window_get_geometry_info (window, FALSE);
674       if (!info)
675         g_value_set_int (value, 0);
676       else
677         g_value_set_int (value, info->width);
678       break;
679     case PROP_DEFAULT_HEIGHT:
680       info = gtk_window_get_geometry_info (window, FALSE);
681       if (!info)
682         g_value_set_int (value, 0);
683       else
684         g_value_set_int (value, info->height);
685       break;
686     case PROP_DESTROY_WITH_PARENT:
687       g_value_set_boolean (value, window->destroy_with_parent);
688       break;
689     default:
690       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
691       break;
692     }
693 }
694
695 /**
696  * gtk_window_new:
697  * @type: type of window
698  * 
699  * Creates a new #GtkWindow, which is a toplevel window that can
700  * contain other widgets. Nearly always, the type of the window should
701  * be #GTK_WINDOW_TOPLEVEL. If you're implementing something like a
702  * popup menu from scratch (which is a bad idea, just use #GtkMenu),
703  * you might use #GTK_WINDOW_POPUP. #GTK_WINDOW_POPUP is not for
704  * dialogs, though in some other toolkits dialogs are called "popups."
705  * In GTK+, #GTK_WINDOW_POPUP means a pop-up menu or pop-up tooltip.
706  * Popup windows are not controlled by the window manager.
707  *
708  * If you simply want an undecorated window (no window borders), use
709  * gtk_window_set_decorated(), don't use #GTK_WINDOW_POPUP.
710  * 
711  * Return value: a new #GtkWindow.
712  **/
713 GtkWidget*
714 gtk_window_new (GtkWindowType type)
715 {
716   GtkWindow *window;
717
718   g_return_val_if_fail (type >= GTK_WINDOW_TOPLEVEL && type <= GTK_WINDOW_POPUP, NULL);
719
720   window = gtk_type_new (GTK_TYPE_WINDOW);
721
722   window->type = type;
723
724   return GTK_WIDGET (window);
725 }
726
727 /**
728  * gtk_window_set_title:
729  * @window: a #GtkWindow
730  * @title: title of the window
731  * 
732  * Sets the title of the #GtkWindow. The title of a window will be displayed in
733  * its title bar; on the X Window System, the title bar is rendered by the
734  * window manager, so exactly how the title appears to users may vary according
735  * to a user's exact configuration. The title should help a user distinguish
736  * this window from other windows they may have open. A good title might
737  * include the application name and current document filename, for example.
738  * 
739  **/
740 void
741 gtk_window_set_title (GtkWindow   *window,
742                       const gchar *title)
743 {
744   g_return_if_fail (window != NULL);
745   g_return_if_fail (GTK_IS_WINDOW (window));
746
747   if (window->title)
748     g_free (window->title);
749   window->title = g_strdup (title);
750
751   if (GTK_WIDGET_REALIZED (window))
752     {
753       gdk_window_set_title (GTK_WIDGET (window)->window, window->title);
754
755       gtk_decorated_window_set_title (window, title);
756     }
757
758   g_object_notify (G_OBJECT (window), "title");
759 }
760
761 /**
762  * gtk_window_get_title:
763  * @window: a #GtkWindow
764  *
765  * Retrieves the title of the window. See gtk_window_set_title().
766  *
767  * Return value: the title of the window, or %NULL if none has
768  *    been set explicitely. The returned string is owned by the widget
769  *    and must not be modified or freed.
770  **/
771 G_CONST_RETURN gchar *
772 gtk_window_get_title (GtkWindow *window)
773 {
774   g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
775
776   return window->title;
777 }
778
779 /**
780  * gtk_window_set_wmclass:
781  * @window: a #GtkWindow
782  * @wmclass_name: window name hint
783  * @wmclass_class: window class hint
784  *
785  * Don't use this function. It sets the X Window System "class" and
786  * "name" hints for a window.  According to the ICCCM, you should
787  * always set these to the same value for all windows in an
788  * application, and GTK sets them to that value by default, so calling
789  * this function is sort of pointless. However, you may want to call
790  * gtk_window_set_role() on each window in your application, for the
791  * benefit of the session manager. Setting the role allows the window
792  * manager to restore window positions when loading a saved session.
793  * 
794  **/
795 void
796 gtk_window_set_wmclass (GtkWindow *window,
797                         const gchar *wmclass_name,
798                         const gchar *wmclass_class)
799 {
800   g_return_if_fail (window != NULL);
801   g_return_if_fail (GTK_IS_WINDOW (window));
802
803   g_free (window->wmclass_name);
804   window->wmclass_name = g_strdup (wmclass_name);
805
806   g_free (window->wmclass_class);
807   window->wmclass_class = g_strdup (wmclass_class);
808
809   if (GTK_WIDGET_REALIZED (window))
810     g_warning ("gtk_window_set_wmclass: shouldn't set wmclass after window is realized!\n");
811 }
812
813 /**
814  * gtk_window_set_role:
815  * @window: a #GtkWindow
816  * @role: unique identifier for the window to be used when restoring a session
817  *
818  * In combination with the window title, the window role allows a
819  * window manager to identify "the same" window when an application is
820  * restarted. So for example you might set the "toolbox" role on your
821  * app's toolbox window, so that when the user restarts their session,
822  * the window manager can put the toolbox back in the same place.
823  *
824  * If a window already has a unique title, you don't need to set the
825  * role, since the WM can use the title to identify the window when
826  * restoring the session.
827  * 
828  **/
829 void
830 gtk_window_set_role (GtkWindow   *window,
831                      const gchar *role)
832 {
833   g_return_if_fail (GTK_IS_WINDOW (window));
834
835   if (role == window->wm_role)
836     return;
837   
838   g_free (window->wm_role);
839   window->wm_role = g_strdup (role);
840   
841   if (GTK_WIDGET_REALIZED (window))
842     g_warning ("gtk_window_set_role(): shouldn't set role after window is realized!\n");
843 }
844
845 /**
846  * gtk_window_get_role:
847  * @window: a #GtkWindow
848  *
849  * Returns the role of the window. See gtk_window_set_role() for
850  * further explanation.
851  *
852  * Return value: the role of the window if set, or %NULL. The
853  *   returned is owned by the widget and must not be modified
854  *   or freed.
855  **/
856 G_CONST_RETURN gchar *
857 gtk_window_get_role (GtkWindow *window)
858 {
859   g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
860
861   return window->wm_role;
862 }
863
864 /**
865  * gtk_window_set_focus:
866  * @window: a #GtkWindow
867  * @focus: widget to be the new focus widget
868  *
869  * If @focus is not the current focus widget, and is focusable, emits
870  * the "set_focus" signal to set @focus as the focus widget for the
871  * window.  This function is more or less GTK-internal; to focus an
872  * entry widget or the like, you should use gtk_widget_grab_focus()
873  * instead of this function.
874  * 
875  **/
876 void
877 gtk_window_set_focus (GtkWindow *window,
878                       GtkWidget *focus)
879 {
880   g_return_if_fail (window != NULL);
881   g_return_if_fail (GTK_IS_WINDOW (window));
882   if (focus)
883     {
884       g_return_if_fail (GTK_IS_WIDGET (focus));
885       g_return_if_fail (GTK_WIDGET_CAN_FOCUS (focus));
886     }
887
888   if ((window->focus_widget != focus) ||
889       (focus && !GTK_WIDGET_HAS_FOCUS (focus)))
890     gtk_signal_emit (GTK_OBJECT (window), window_signals[SET_FOCUS], focus);
891 }
892
893 /**
894  * gtk_window_set_default:
895  * @window: a #GtkWindow
896  * @default_widget: widget to be the default
897  *
898  * The default widget is the widget that's activated when the user
899  * presses Enter in a dialog (for example). This function tells a
900  * #GtkWindow about the current default widget; it's really a GTK
901  * internal function and you shouldn't need it. Instead, to change the
902  * default widget, first set the #GTK_CAN_DEFAULT flag on the widget
903  * you'd like to make the default using GTK_WIDGET_SET_FLAGS(), then
904  * call gtk_widget_grab_default() to move the default.
905  * 
906  **/
907 void
908 gtk_window_set_default (GtkWindow *window,
909                         GtkWidget *default_widget)
910 {
911   g_return_if_fail (window != NULL);
912   g_return_if_fail (GTK_IS_WINDOW (window));
913
914   if (default_widget)
915     g_return_if_fail (GTK_WIDGET_CAN_DEFAULT (default_widget));
916
917   if (window->default_widget != default_widget)
918     {
919       if (window->default_widget)
920         {
921           if (window->focus_widget != window->default_widget ||
922               !GTK_WIDGET_RECEIVES_DEFAULT (window->default_widget))
923             GTK_WIDGET_UNSET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
924           gtk_widget_queue_draw (window->default_widget);
925         }
926
927       window->default_widget = default_widget;
928
929       if (window->default_widget)
930         {
931           if (window->focus_widget == NULL ||
932               !GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget))
933             GTK_WIDGET_SET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
934           gtk_widget_queue_draw (window->default_widget);
935         }
936     }
937 }
938
939 void
940 gtk_window_set_policy (GtkWindow *window,
941                        gboolean   allow_shrink,
942                        gboolean   allow_grow,
943                        gboolean   auto_shrink)
944 {
945   g_return_if_fail (window != NULL);
946   g_return_if_fail (GTK_IS_WINDOW (window));
947
948   window->allow_shrink = (allow_shrink != FALSE);
949   window->allow_grow = (allow_grow != FALSE);
950   window->auto_shrink = (auto_shrink != FALSE);
951
952   g_object_notify (G_OBJECT (window), "allow_shrink");
953   g_object_notify (G_OBJECT (window), "allow_grow");
954   g_object_notify (G_OBJECT (window), "auto_shrink");
955   
956   gtk_widget_queue_resize (GTK_WIDGET (window));
957 }
958
959 void
960 gtk_window_add_accel_group (GtkWindow        *window,
961                             GtkAccelGroup    *accel_group)
962 {
963   g_return_if_fail (window != NULL);
964   g_return_if_fail (GTK_IS_WINDOW (window));
965   g_return_if_fail (accel_group != NULL);
966
967   gtk_accel_group_attach (accel_group, GTK_OBJECT (window));
968 }
969
970 void
971 gtk_window_remove_accel_group (GtkWindow       *window,
972                                GtkAccelGroup   *accel_group)
973 {
974   g_return_if_fail (window != NULL);
975   g_return_if_fail (GTK_IS_WINDOW (window));
976   g_return_if_fail (accel_group != NULL);
977
978   gtk_accel_group_detach (accel_group, GTK_OBJECT (window));
979 }
980
981 void
982 gtk_window_add_mnemonic (GtkWindow *window,
983                          guint      keyval,
984                          GtkWidget *target)
985 {
986   GtkWindowMnemonic key;
987   GtkWindowMnemonic *mnemonic;
988
989   g_return_if_fail (GTK_IS_WINDOW (window));
990   g_return_if_fail (GTK_IS_WIDGET (target));
991   
992   key.window = window;
993   key.keyval = keyval;
994   mnemonic = g_hash_table_lookup (mnemonic_hash_table, &key);
995
996   if (mnemonic)
997     {
998       g_return_if_fail (g_slist_find (mnemonic->targets, target) == NULL);
999       mnemonic->targets = g_slist_prepend (mnemonic->targets, target);
1000     }
1001   else
1002     {
1003       mnemonic = g_new (GtkWindowMnemonic, 1);
1004       *mnemonic = key;
1005       mnemonic->targets = g_slist_prepend (NULL, target);
1006       g_hash_table_insert (mnemonic_hash_table, mnemonic, mnemonic);
1007     }
1008 }
1009
1010 void
1011 gtk_window_remove_mnemonic (GtkWindow *window,
1012                             guint      keyval,
1013                             GtkWidget *target)
1014 {
1015   GtkWindowMnemonic key;
1016   GtkWindowMnemonic *mnemonic;
1017
1018   g_return_if_fail (GTK_IS_WINDOW (window));
1019   g_return_if_fail (GTK_IS_WIDGET (target));
1020   
1021   key.window = window;
1022   key.keyval = keyval;
1023   mnemonic = g_hash_table_lookup (mnemonic_hash_table, &key);
1024
1025   g_return_if_fail (mnemonic && g_slist_find (mnemonic->targets, target) != NULL);
1026
1027   mnemonic->targets = g_slist_remove (mnemonic->targets, target);
1028   if (mnemonic->targets == NULL)
1029     {
1030       g_hash_table_remove (mnemonic_hash_table, mnemonic);
1031       g_free (mnemonic);
1032     }
1033 }
1034
1035 gboolean
1036 gtk_window_mnemonic_activate (GtkWindow      *window,
1037                               guint           keyval,
1038                               GdkModifierType modifier)
1039 {
1040   GtkWindowMnemonic key;
1041   GtkWindowMnemonic *mnemonic;
1042   GSList *list;
1043   GtkWidget *widget, *chosen_widget;
1044   gboolean overloaded;
1045
1046   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
1047
1048   if (window->mnemonic_modifier != (modifier & gtk_accelerator_get_default_mod_mask ()))
1049     return FALSE;
1050   
1051   key.window = window;
1052   key.keyval = keyval;
1053   mnemonic = g_hash_table_lookup (mnemonic_hash_table, &key);
1054
1055   if (!mnemonic)
1056     return FALSE;
1057   
1058   overloaded = FALSE;
1059   chosen_widget = NULL;
1060   list = mnemonic->targets;
1061   while (list)
1062     {
1063       widget = GTK_WIDGET (list->data);
1064       
1065       if (GTK_WIDGET_IS_SENSITIVE (widget) &&
1066           GTK_WIDGET_MAPPED (widget))
1067         {
1068           if (chosen_widget)
1069             {
1070               overloaded = TRUE;
1071               break;
1072             }
1073           else
1074             chosen_widget = widget;
1075         }
1076       list = g_slist_next (list);
1077     }
1078
1079   if (chosen_widget)
1080     {
1081       /* For round robin we put the activated entry on
1082        * the end of the list after activation
1083        */
1084       mnemonic->targets = g_slist_remove (mnemonic->targets, chosen_widget);
1085       mnemonic->targets = g_slist_append (mnemonic->targets, chosen_widget);
1086
1087       return gtk_widget_mnemonic_activate (chosen_widget, overloaded);
1088     }
1089   return FALSE;
1090 }
1091
1092 void
1093 gtk_window_set_mnemonic_modifier (GtkWindow      *window,
1094                                   GdkModifierType modifier)
1095 {
1096   g_return_if_fail (GTK_IS_WINDOW (window));
1097   g_return_if_fail ((modifier & ~GDK_MODIFIER_MASK) == 0);
1098
1099   window->mnemonic_modifier = modifier;
1100 }
1101
1102 /**
1103  * gtk_window_get_mnemonic_modifier:
1104  * @window: a #GtkWindow
1105  *
1106  * Returns the mnemonic modifier for this window. See
1107  * gtk_window_set_mnemonic_modifier().
1108  *
1109  * Return value: the modifier mask used to activate
1110  *               mnemonics on this window.
1111  **/
1112 GdkModifierType
1113 gtk_window_get_mnemonic_modifier (GtkWindow *window)
1114 {
1115   g_return_val_if_fail (GTK_IS_WINDOW (window), 0);
1116
1117   return window->mnemonic_modifier;
1118 }
1119
1120 void
1121 gtk_window_set_position (GtkWindow         *window,
1122                          GtkWindowPosition  position)
1123 {
1124   g_return_if_fail (GTK_IS_WINDOW (window));
1125
1126   window->position = position;
1127
1128   g_object_notify (G_OBJECT (window), "window_position");
1129 }
1130
1131 gboolean 
1132 gtk_window_activate_focus (GtkWindow *window)
1133 {
1134   g_return_val_if_fail (window != NULL, FALSE);
1135   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
1136
1137   if (window->focus_widget)
1138     {
1139       if (GTK_WIDGET_IS_SENSITIVE (window->focus_widget))
1140         gtk_widget_activate (window->focus_widget);
1141       return TRUE;
1142     }
1143
1144   return FALSE;
1145 }
1146
1147 gboolean
1148 gtk_window_activate_default (GtkWindow *window)
1149 {
1150   g_return_val_if_fail (window != NULL, FALSE);
1151   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
1152
1153   if (window->default_widget && GTK_WIDGET_IS_SENSITIVE (window->default_widget) &&
1154       (!window->focus_widget || !GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget)))
1155     {
1156       gtk_widget_activate (window->default_widget);
1157       return TRUE;
1158     }
1159   else if (window->focus_widget)
1160     {
1161       if (GTK_WIDGET_IS_SENSITIVE (window->focus_widget))
1162         gtk_widget_activate (window->focus_widget);
1163       return TRUE;
1164     }
1165
1166   return FALSE;
1167 }
1168
1169 /**
1170  * gtk_window_set_modal:
1171  * @window: a #GtkWindow
1172  * @modal: whether the window is modal
1173  * 
1174  * Sets a window modal or non-modal. Modal windows prevent interaction
1175  * with other windows in the same application. To keep modal dialogs
1176  * on top of main application windows, use
1177  * gtk_window_set_transient_for() to make the dialog transient for the
1178  * parent; most window managers will then disallow lowering the dialog
1179  * below the parent.
1180  * 
1181  * 
1182  **/
1183 void
1184 gtk_window_set_modal (GtkWindow *window,
1185                       gboolean   modal)
1186 {
1187   g_return_if_fail (window != NULL);
1188   g_return_if_fail (GTK_IS_WINDOW (window));
1189
1190   window->modal = modal != FALSE;
1191   
1192   /* adjust desired modality state */
1193   if (GTK_WIDGET_VISIBLE (window) && window->modal)
1194     gtk_grab_add (GTK_WIDGET (window));
1195   else
1196     gtk_grab_remove (GTK_WIDGET (window));
1197
1198   g_object_notify (G_OBJECT (window), "modal");
1199 }
1200
1201 /**
1202  * gtk_window_get_modal:
1203  * @window: a #GtkWindow
1204  * 
1205  * Returns whether the window is modal. See gtk_window_set_modal().
1206  *
1207  * Return value: %TRUE if the window is set to be modal and
1208  *               establishes a grab when shown
1209  **/
1210 gboolean
1211 gtk_window_get_modal (GtkWindow *window)
1212 {
1213   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
1214
1215   return window->modal;
1216 }
1217
1218 /**
1219  * gtk_window_list_toplevels:
1220  * 
1221  * Returns a list of all existing toplevel windows. The widgets
1222  * in the list are not individually referenced. If you want
1223  * to iterate through the list and perform actions involving
1224  * callbacks that might destroy the widgets, you MUST call
1225  * g_list_foreach (result, (GFunc)g_object_ref, NULL) first, and
1226  * then unref all the widgets afterwards.
1227  * 
1228  * Return value: list of toplevel widgets
1229  **/
1230 GList*
1231 gtk_window_list_toplevels (void)
1232 {
1233   GList *list = NULL;
1234   GSList *slist;
1235
1236   for (slist = toplevel_list; slist; slist = slist->next)
1237     list = g_list_prepend (list, slist->data);
1238
1239   return list;
1240 }
1241
1242 void
1243 gtk_window_add_embedded_xid (GtkWindow *window, guint xid)
1244 {
1245   GList *embedded_windows;
1246
1247   g_return_if_fail (window != NULL);
1248   g_return_if_fail (GTK_IS_WINDOW (window));
1249
1250   embedded_windows = gtk_object_get_data (GTK_OBJECT (window), "gtk-embedded");
1251   if (embedded_windows)
1252     gtk_object_remove_no_notify_by_id (GTK_OBJECT (window), 
1253                                        g_quark_from_static_string ("gtk-embedded"));
1254   embedded_windows = g_list_prepend (embedded_windows,
1255                                      GUINT_TO_POINTER (xid));
1256
1257   gtk_object_set_data_full (GTK_OBJECT (window), "gtk-embedded", 
1258                             embedded_windows,
1259                             embedded_windows ?
1260                               (GtkDestroyNotify) g_list_free : NULL);
1261 }
1262
1263 void
1264 gtk_window_remove_embedded_xid (GtkWindow *window, guint xid)
1265 {
1266   GList *embedded_windows;
1267   GList *node;
1268
1269   g_return_if_fail (window != NULL);
1270   g_return_if_fail (GTK_IS_WINDOW (window));
1271   
1272   embedded_windows = gtk_object_get_data (GTK_OBJECT (window), "gtk-embedded");
1273   if (embedded_windows)
1274     gtk_object_remove_no_notify_by_id (GTK_OBJECT (window), 
1275                                        g_quark_from_static_string ("gtk-embedded"));
1276
1277   node = g_list_find (embedded_windows, GUINT_TO_POINTER (xid));
1278   if (node)
1279     {
1280       embedded_windows = g_list_remove_link (embedded_windows, node);
1281       g_list_free_1 (node);
1282     }
1283   
1284   gtk_object_set_data_full (GTK_OBJECT (window), 
1285                             "gtk-embedded", embedded_windows,
1286                             embedded_windows ?
1287                               (GtkDestroyNotify) g_list_free : NULL);
1288 }
1289
1290 void       
1291 _gtk_window_reposition (GtkWindow *window,
1292                         gint       x,
1293                         gint       y)
1294 {
1295   GtkWindowGeometryInfo *info;
1296   
1297   g_return_if_fail (window != NULL);
1298   g_return_if_fail (GTK_IS_WINDOW (window));
1299
1300   /* keep this in sync with gtk_window_compute_reposition()
1301    */
1302   if (GTK_WIDGET_REALIZED (window))
1303     {
1304       info = gtk_window_get_geometry_info (window, TRUE);
1305
1306       if (!(info->last.flags & GDK_HINT_POS))
1307         {
1308           info->last.flags |= GDK_HINT_POS;
1309           gdk_window_set_geometry_hints (GTK_WIDGET (window)->window,
1310                                          &info->last.geometry,
1311                                          info->last.flags);
1312         }
1313
1314       if (window->frame)
1315         gdk_window_move (window->frame,  x - window->frame_left, y - window->frame_top);
1316       else
1317         gdk_window_move (GTK_WIDGET (window)->window, x, y);
1318     }
1319 }
1320
1321 static void
1322 gtk_window_shutdown (GObject *object)
1323 {
1324   GtkWindow *window;
1325
1326   g_return_if_fail (GTK_IS_WINDOW (object));
1327
1328   window = GTK_WINDOW (object);
1329
1330   gtk_window_set_focus (window, NULL);
1331   gtk_window_set_default (window, NULL);
1332
1333   G_OBJECT_CLASS (parent_class)->shutdown (object);
1334 }
1335
1336 static void
1337 parent_destroyed_callback (GtkWindow *parent, GtkWindow *child)
1338 {
1339   gtk_widget_destroy (GTK_WIDGET (child));
1340 }
1341
1342 static void
1343 connect_parent_destroyed (GtkWindow *window)
1344 {
1345   if (window->transient_parent)
1346     {
1347       gtk_signal_connect (GTK_OBJECT (window->transient_parent),
1348                           "destroy",
1349                           GTK_SIGNAL_FUNC (parent_destroyed_callback),
1350                           window);
1351     }  
1352 }
1353
1354 static void
1355 disconnect_parent_destroyed (GtkWindow *window)
1356 {
1357   if (window->transient_parent)
1358     {
1359       gtk_signal_disconnect_by_func (GTK_OBJECT (window->transient_parent),
1360                                      GTK_SIGNAL_FUNC (parent_destroyed_callback),
1361                                      window);
1362     }
1363 }
1364
1365 static void
1366 gtk_window_transient_parent_realized (GtkWidget *parent,
1367                                       GtkWidget *window)
1368 {
1369   if (GTK_WIDGET_REALIZED (window))
1370     gdk_window_set_transient_for (window->window, parent->window);
1371 }
1372
1373 static void
1374 gtk_window_transient_parent_unrealized (GtkWidget *parent,
1375                                         GtkWidget *window)
1376 {
1377   if (GTK_WIDGET_REALIZED (window))
1378     gdk_property_delete (window->window, 
1379                          gdk_atom_intern ("WM_TRANSIENT_FOR", FALSE));
1380 }
1381
1382 static void       
1383 gtk_window_unset_transient_for  (GtkWindow *window)
1384 {
1385   if (window->transient_parent)
1386     {
1387       gtk_signal_disconnect_by_func (GTK_OBJECT (window->transient_parent),
1388                                      GTK_SIGNAL_FUNC (gtk_window_transient_parent_realized),
1389                                      window);
1390       gtk_signal_disconnect_by_func (GTK_OBJECT (window->transient_parent),
1391                                      GTK_SIGNAL_FUNC (gtk_window_transient_parent_unrealized),
1392                                      window);
1393       gtk_signal_disconnect_by_func (GTK_OBJECT (window->transient_parent),
1394                                      GTK_SIGNAL_FUNC (gtk_widget_destroyed),
1395                                      &window->transient_parent);
1396
1397       if (window->destroy_with_parent)
1398         disconnect_parent_destroyed (window);
1399       
1400       window->transient_parent = NULL;
1401     }
1402 }
1403
1404 /**
1405  * gtk_window_set_transient_for:
1406  * @window: a #GtkWindow
1407  * @parent: parent window
1408  *
1409  * Dialog windows should be set transient for the main application
1410  * window they were spawned from. This allows window managers to
1411  * e.g. keep the dialog on top of the main window, or center the
1412  * dialog over the main window. gtk_dialog_new_with_buttons() and
1413  * other convenience functions in GTK+ will sometimes call
1414  * gtk_window_set_transient_for() on your behalf.
1415  * 
1416  **/
1417 void       
1418 gtk_window_set_transient_for  (GtkWindow *window, 
1419                                GtkWindow *parent)
1420 {
1421   g_return_if_fail (GTK_IS_WINDOW (window));
1422   g_return_if_fail (parent == NULL || GTK_IS_WINDOW (parent));
1423   g_return_if_fail (window != parent);
1424
1425     
1426   if (window->transient_parent)
1427     {
1428       if (GTK_WIDGET_REALIZED (window) && 
1429           GTK_WIDGET_REALIZED (window->transient_parent) && 
1430           (!parent || !GTK_WIDGET_REALIZED (parent)))
1431         gtk_window_transient_parent_unrealized (GTK_WIDGET (window->transient_parent),
1432                                                 GTK_WIDGET (window));
1433
1434       gtk_window_unset_transient_for (window);
1435     }
1436
1437   window->transient_parent = parent;
1438
1439   if (parent)
1440     {
1441       gtk_signal_connect (GTK_OBJECT (parent), "destroy",
1442                           GTK_SIGNAL_FUNC (gtk_widget_destroyed),
1443                           &window->transient_parent);
1444       gtk_signal_connect (GTK_OBJECT (parent), "realize",
1445                           GTK_SIGNAL_FUNC (gtk_window_transient_parent_realized),
1446                           window);
1447       gtk_signal_connect (GTK_OBJECT (parent), "unrealize",
1448                           GTK_SIGNAL_FUNC (gtk_window_transient_parent_unrealized),
1449                           window);
1450
1451       if (window->destroy_with_parent)
1452         connect_parent_destroyed (window);
1453       
1454       if (GTK_WIDGET_REALIZED (window) &&
1455           GTK_WIDGET_REALIZED (parent))
1456         gtk_window_transient_parent_realized (GTK_WIDGET (parent),
1457                                               GTK_WIDGET (window));
1458     }
1459 }
1460
1461 /**
1462  * gtk_window_get_transient_for:
1463  * @window: a #GtkWindow
1464  *
1465  * Fetches the transient parent for this window. See
1466  * gtk_window_set_transient_for().
1467  *
1468  * Return value: the transient parent for this window, or %NULL
1469  *    if no transient parent has been set.
1470  **/
1471 GtkWindow *
1472 gtk_window_get_transient_for (GtkWindow *window)
1473 {
1474   g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
1475
1476   return window->transient_parent;
1477 }
1478
1479 /**
1480  * gtk_window_set_type_hint:
1481  * @window: a #GtkWindow
1482  * @hint: the window type
1483  *
1484  * By setting the type hint for the window, you allow the window
1485  * manager to decorate and handle the window in a way which is
1486  * suitable to the function of the window in your application.
1487  *
1488  * This function should be called before the window becomes visible.
1489  *
1490  * gtk_dialog_new_with_buttons() and other convenience functions in GTK+
1491  * will sometimes call gtk_window_set_type_hint() on your behalf.
1492  * 
1493  **/
1494 void
1495 gtk_window_set_type_hint (GtkWindow           *window, 
1496                           GdkWindowTypeHint    hint)
1497 {
1498   g_return_if_fail (GTK_IS_WINDOW (window));
1499   g_return_if_fail (!GTK_WIDGET_VISIBLE (window));
1500   window->type_hint = hint;
1501 }
1502
1503 /**
1504  * gtk_window_get_type_hint:
1505  * @window: a #GtkWindow
1506  *
1507  * Gets the type hint for this window. See gtk_window_set_type_hint().
1508  *
1509  * Return value: the type hint for @window.
1510  **/
1511 GdkWindowTypeHint
1512 gtk_window_get_type_hint (GtkWindow *window)
1513 {
1514   g_return_val_if_fail (GTK_IS_WINDOW (window), GDK_WINDOW_TYPE_HINT_NORMAL);
1515
1516   return window->type_hint;
1517 }
1518
1519 /**
1520  * gtk_window_set_destroy_with_parent:
1521  * @window: a #GtkWindow
1522  * @setting: whether to destroy @window with its transient parent
1523  * 
1524  * If @setting is TRUE, then destroying the transient parent of @window
1525  * will also destroy @window itself. This is useful for dialogs that
1526  * shouldn't persist beyond the lifetime of the main window they're
1527  * associated with, for example.
1528  **/
1529 void
1530 gtk_window_set_destroy_with_parent  (GtkWindow *window,
1531                                      gboolean   setting)
1532 {
1533   g_return_if_fail (GTK_IS_WINDOW (window));
1534
1535   if (window->destroy_with_parent == (setting != FALSE))
1536     return;
1537
1538   if (window->destroy_with_parent)
1539     {
1540       disconnect_parent_destroyed (window);
1541     }
1542   else
1543     {
1544       connect_parent_destroyed (window);
1545     }
1546   
1547   window->destroy_with_parent = setting;
1548
1549   g_object_notify (G_OBJECT (window), "destroy_with_parent");
1550 }
1551
1552 /**
1553  * gtk_window_get_destroy_with_parent:
1554  * @window: a #GtkWindow
1555  * 
1556  * Returns whether the window will be destroyed with its transient parent. See
1557  * gtk_window_set_destroy_with_parent ().
1558  *
1559  * Return value: %TRUE if the window will be destroyed with its transient parent.
1560  **/
1561 gboolean
1562 gtk_window_get_destroy_with_parent (GtkWindow *window)
1563 {
1564   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
1565
1566   return window->destroy_with_parent;
1567 }
1568
1569 static GtkWindowGeometryInfo*
1570 gtk_window_get_geometry_info (GtkWindow *window,
1571                               gboolean   create)
1572 {
1573   GtkWindowGeometryInfo *info;
1574
1575   info = window->geometry_info;
1576   if (!info && create)
1577     {
1578       info = g_new0 (GtkWindowGeometryInfo, 1);
1579
1580       info->width = 0;
1581       info->height = 0;
1582       info->last.width = -1;
1583       info->last.height = -1;
1584       info->widget = NULL;
1585       info->mask = 0;
1586       info->may_shrink = FALSE;
1587       window->geometry_info = info;
1588     }
1589
1590   return info;
1591 }
1592
1593 /**
1594  * gtk_window_set_geometry_hints:
1595  * @window: a #GtkWindow
1596  * @geometry_widget: widget the geometry hints will be applied to
1597  * @geometry: struct containing geometry information
1598  * @geom_mask: mask indicating which struct fields should be paid attention to
1599  *
1600  * This function sets up hints about how a window can be resized by
1601  * the user.  You can set a minimum and maximum size; allowed resize
1602  * increments (e.g. for xterm, you can only resize by the size of a
1603  * character); aspect ratios; and more. See the #GdkGeometry struct.
1604  * 
1605  **/
1606 void       
1607 gtk_window_set_geometry_hints (GtkWindow       *window,
1608                                GtkWidget       *geometry_widget,
1609                                GdkGeometry     *geometry,
1610                                GdkWindowHints   geom_mask)
1611 {
1612   GtkWindowGeometryInfo *info;
1613
1614   g_return_if_fail (window != NULL);
1615
1616   info = gtk_window_get_geometry_info (window, TRUE);
1617   
1618   if (info->widget)
1619     gtk_signal_disconnect_by_func (GTK_OBJECT (info->widget),
1620                                    GTK_SIGNAL_FUNC (gtk_widget_destroyed),
1621                                    &info->widget);
1622   
1623   info->widget = geometry_widget;
1624   if (info->widget)
1625     gtk_signal_connect (GTK_OBJECT (geometry_widget), "destroy",
1626                         GTK_SIGNAL_FUNC (gtk_widget_destroyed),
1627                         &info->widget);
1628
1629   if (geometry)
1630     info->geometry = *geometry;
1631
1632   info->mask = geom_mask;
1633
1634   gtk_widget_queue_resize (GTK_WIDGET (window));
1635 }
1636
1637 /**
1638  * gtk_window_set_decorated:
1639  * @window: a #GtkWindow
1640  * @setting: %TRUE to decorate the window
1641  *
1642  * By default, windows are decorated with a title bar, resize
1643  * controls, etc.  Some window managers allow GTK+ to disable these
1644  * decorations, creating a borderless window. If you set the decorated
1645  * property to %FALSE using this function, GTK+ will do its best to
1646  * convince the window manager not to decorate the window.
1647  * 
1648  **/
1649 void
1650 gtk_window_set_decorated (GtkWindow *window,
1651                           gboolean   setting)
1652 {
1653   g_return_if_fail (GTK_IS_WINDOW (window));
1654
1655   setting = setting != FALSE;
1656
1657   if (setting == window->decorated)
1658     return;
1659
1660   if (GTK_WIDGET (window)->window)
1661     {
1662       if (window->decorated)
1663         gdk_window_set_decorations (GTK_WIDGET (window)->window,
1664                                     GDK_DECOR_ALL);
1665       else
1666         gdk_window_set_decorations (GTK_WIDGET (window)->window,
1667                                     0);
1668     }
1669 }
1670
1671 /**
1672  * gtk_window_get_decorated:
1673  * @window: a #GtkWindow
1674  *
1675  * Returns whether the window has been set to have decorations
1676  * such as a title bar via gtk_window_set_decorated().
1677  *
1678  * Return value: %TRUE if the window has been set to have decorations
1679  **/
1680 gboolean
1681 gtk_window_get_decorated (GtkWindow *window)
1682 {
1683   g_return_val_if_fail (GTK_IS_WINDOW (window), TRUE);
1684
1685   return window->decorated;
1686 }
1687
1688 /**
1689  * gtk_window_set_default_size:
1690  * @window: a #GtkWindow
1691  * @width: width in pixels, 0 to unset, or -1 to leave the width unchanged
1692  * @height: height in pixels, 0 to unset, or -1 to leave the height unchanged
1693  *
1694  * Sets the default size of a window. If the window's "natural" size
1695  * (its size request) is larger than the default, the default will be
1696  * ignored. So the default size is a minimum initial size.  Unlike
1697  * gtk_widget_set_usize(), which sets a size request for a widget and
1698  * thus would keep users from shrinking the window, this function only
1699  * sets the initial size, just as if the user had resized the window
1700  * themselves. Users can still shrink the window again as they
1701  * normally would. Setting a default size of 0 means to use the
1702  * "natural" default size (the size request of the window).
1703  *
1704  * For more control over a window's initial size and how resizing works,
1705  * investigate gtk_window_set_geometry_hints().
1706  *
1707  * A useful feature: if you set the "geometry widget" via
1708  * gtk_window_set_geometry_hints(), the default size specified by
1709  * gtk_window_set_default_size() will be the default size of that
1710  * widget, not of the entire window.
1711  * 
1712  **/
1713 void       
1714 gtk_window_set_default_size (GtkWindow   *window,
1715                              gint         width,
1716                              gint         height)
1717 {
1718   GtkWindowGeometryInfo *info;
1719
1720   g_return_if_fail (GTK_IS_WINDOW (window));
1721
1722   info = gtk_window_get_geometry_info (window, TRUE);
1723
1724   g_object_freeze_notify (G_OBJECT (window));
1725   if (width >= 0)
1726     {
1727       info->width = width;
1728       g_object_notify (G_OBJECT (window), "default_width");
1729       info->may_shrink = TRUE;
1730     }
1731   if (height >= 0)
1732     {
1733       info->height = height;
1734       g_object_notify (G_OBJECT (window), "default_height");
1735       info->may_shrink = TRUE;
1736     }
1737   g_object_thaw_notify (G_OBJECT (window));
1738   
1739   gtk_widget_queue_resize (GTK_WIDGET (window));
1740 }
1741
1742 /**
1743  * gtk_window_get_default_size:
1744  * @window: a #GtkWindow
1745  * @width: location to store the default width, or %NULL
1746  * @height: location to store the default height, or %NULL
1747  *
1748  * Gets the default size of the window. A value of 0 for the
1749  * width or height indicates that a default size has not
1750  * been explicitely set for that dimension, so the value
1751  * will be computed from the requisition of the window.
1752  **/
1753 void
1754 gtk_window_get_default_size (GtkWindow *window,
1755                              gint      *width,
1756                              gint      *height)
1757 {
1758   GtkWindowGeometryInfo *info;
1759
1760   g_return_if_fail (GTK_IS_WINDOW (window));
1761
1762   info = gtk_window_get_geometry_info (window, FALSE);
1763
1764   if (width)
1765     *width = info ? info->width : 0;
1766
1767   if (height)
1768     *height = info ? info->height : 0;
1769 }
1770   
1771 static void
1772 gtk_window_destroy (GtkObject *object)
1773 {
1774   GtkWindow *window;
1775   
1776   g_return_if_fail (GTK_IS_WINDOW (object));
1777
1778   window = GTK_WINDOW (object);
1779
1780   if (window->transient_parent)
1781     gtk_window_set_transient_for (window, NULL);
1782
1783   if (window->has_user_ref_count)
1784     {
1785       window->has_user_ref_count = FALSE;
1786       gtk_widget_unref (GTK_WIDGET (window));
1787     }
1788
1789   if (window->group)
1790     gtk_window_group_remove_window (window->group, window);
1791
1792   GTK_OBJECT_CLASS (parent_class)->destroy (object);
1793 }
1794
1795 static gboolean
1796 gtk_window_mnemonic_hash_remove (gpointer       key,
1797                                  gpointer       value,
1798                                  gpointer       user)
1799 {
1800   GtkWindowMnemonic *mnemonic = key;
1801   GtkWindow *window = user;
1802
1803   if (mnemonic->window == window)
1804     {
1805       if (mnemonic->targets)
1806         {
1807           gchar *name = gtk_accelerator_name (mnemonic->keyval, 0);
1808
1809           g_warning ("mnemonic \"%s\" wasn't removed for widget (%p)",
1810                      name, mnemonic->targets->data);
1811           g_free (name);
1812         }
1813       g_slist_free (mnemonic->targets);
1814       g_free (mnemonic);
1815       
1816       return TRUE;
1817     }
1818   return FALSE;
1819 }
1820
1821 static void
1822 gtk_window_finalize (GObject *object)
1823 {
1824   GtkWindow *window;
1825
1826   g_return_if_fail (GTK_IS_WINDOW (object));
1827
1828   window = GTK_WINDOW (object);
1829
1830   toplevel_list = g_slist_remove (toplevel_list, window);
1831
1832   g_free (window->title);
1833   g_free (window->wmclass_name);
1834   g_free (window->wmclass_class);
1835   g_free (window->wm_role);
1836
1837   g_hash_table_foreach_remove (mnemonic_hash_table,
1838                                gtk_window_mnemonic_hash_remove,
1839                                window);
1840   if (window->geometry_info)
1841     {
1842       if (window->geometry_info->widget)
1843         gtk_signal_disconnect_by_func (GTK_OBJECT (window->geometry_info->widget),
1844                                        GTK_SIGNAL_FUNC (gtk_widget_destroyed),
1845                                        &window->geometry_info->widget);
1846       g_free (window->geometry_info);
1847     }
1848   
1849   G_OBJECT_CLASS (parent_class)->finalize (object);
1850 }
1851
1852 static void
1853 gtk_window_show (GtkWidget *widget)
1854 {
1855   GtkWindow *window = GTK_WINDOW (widget);
1856   GtkContainer *container = GTK_CONTAINER (window);
1857   gboolean need_resize;
1858   
1859   GTK_WIDGET_SET_FLAGS (widget, GTK_VISIBLE);
1860   
1861   need_resize = container->need_resize || !GTK_WIDGET_REALIZED (widget);
1862   container->need_resize = FALSE;
1863   
1864   if (need_resize)
1865     {
1866       GtkWindowGeometryInfo *info = gtk_window_get_geometry_info (window, TRUE);
1867       GtkAllocation allocation = { 0, 0 };
1868       GdkGeometry new_geometry;
1869       guint width, height, new_flags;
1870       gboolean was_realized;
1871       
1872       /* determine default size to initially show the window with */
1873       gtk_widget_size_request (widget, NULL);
1874       gtk_window_compute_default_size (window, &width, &height);
1875       
1876       /* save away the last default size for later comparisions */
1877       info->last.width = width;
1878       info->last.height = height;
1879
1880       /* constrain size to geometry */
1881       gtk_window_compute_hints (window, &new_geometry, &new_flags);
1882       gtk_window_constrain_size (window,
1883                                  &new_geometry, new_flags,
1884                                  width, height,
1885                                  &width, &height);
1886       
1887       /* and allocate the window */
1888       allocation.width  = width;
1889       allocation.height = height;
1890       gtk_widget_size_allocate (widget, &allocation);
1891       
1892       was_realized = FALSE;
1893       if (!GTK_WIDGET_REALIZED (widget))
1894         {
1895           gtk_widget_realize (widget);
1896           was_realized = TRUE;;
1897         }
1898
1899       /* Must be done after the windows are realized,
1900        * so that the decorations can be read
1901        */
1902       gtk_decorated_window_calculate_frame_size (window);
1903       
1904       if (!was_realized)
1905         gdk_window_resize (widget->window, width, height);
1906     }
1907   
1908   gtk_container_check_resize (container);
1909
1910   gtk_widget_map (widget);
1911
1912   if (window->modal)
1913     gtk_grab_add (widget);
1914 }
1915
1916 static void
1917 gtk_window_hide (GtkWidget *widget)
1918 {
1919   GtkWindow *window;
1920
1921   g_return_if_fail (widget != NULL);
1922   g_return_if_fail (GTK_IS_WINDOW (widget));
1923
1924   window = GTK_WINDOW (widget);
1925
1926   GTK_WIDGET_UNSET_FLAGS (widget, GTK_VISIBLE);
1927   gtk_widget_unmap (widget);
1928
1929   if (window->modal)
1930     gtk_grab_remove (widget);
1931 }
1932
1933 static void
1934 gtk_window_map (GtkWidget *widget)
1935 {
1936   GtkWindow *window;
1937   GdkWindow *toplevel;
1938   
1939   g_return_if_fail (widget != NULL);
1940   g_return_if_fail (GTK_IS_WINDOW (widget));
1941
1942   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1943
1944   window = GTK_WINDOW (widget);
1945
1946   if (window->bin.child &&
1947       GTK_WIDGET_VISIBLE (window->bin.child) &&
1948       !GTK_WIDGET_MAPPED (window->bin.child))
1949     gtk_widget_map (window->bin.child);
1950
1951   if (window->frame)
1952     toplevel = window->frame;
1953   else
1954     toplevel = widget->window;
1955   
1956   if (window->maximize_initially)
1957     gdk_window_maximize (toplevel);
1958   else
1959     gdk_window_unmaximize (toplevel);
1960   
1961   if (window->stick_initially)
1962     gdk_window_stick (toplevel);
1963   else
1964     gdk_window_unstick (toplevel);
1965   
1966   if (window->iconify_initially)
1967     gdk_window_iconify (toplevel);
1968   else
1969     gdk_window_deiconify (toplevel);
1970   
1971   gdk_window_show (widget->window);
1972
1973   if (window->frame)
1974     gdk_window_show (window->frame);
1975 }
1976
1977 static void
1978 gtk_window_unmap (GtkWidget *widget)
1979 {
1980   GtkWindow *window;
1981
1982   g_return_if_fail (widget != NULL);
1983   g_return_if_fail (GTK_IS_WINDOW (widget));
1984
1985   window = GTK_WINDOW (widget);
1986   
1987   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1988   if (window->frame)
1989     gdk_window_withdraw (window->frame);
1990   else 
1991     gdk_window_withdraw (widget->window);
1992
1993   window->use_uposition = TRUE;
1994   window->resize_count = 0;
1995   window->handling_resize = FALSE;
1996
1997 }
1998
1999 static void
2000 gtk_window_realize (GtkWidget *widget)
2001 {
2002   GtkWindow *window;
2003   GdkWindow *parent_window;
2004   GdkWindowAttr attributes;
2005   gint attributes_mask;
2006   
2007   g_return_if_fail (GTK_IS_WINDOW (widget));
2008
2009   window = GTK_WINDOW (widget);
2010
2011   /* ensure widget tree is properly size allocated */
2012   if (widget->allocation.x == -1 &&
2013       widget->allocation.y == -1 &&
2014       widget->allocation.width == 1 &&
2015       widget->allocation.height == 1)
2016     {
2017       GtkRequisition requisition;
2018       GtkAllocation allocation = { 0, 0, 200, 200 };
2019
2020       gtk_widget_size_request (widget, &requisition);
2021       if (requisition.width || requisition.height)
2022         {
2023           /* non-empty window */
2024           allocation.width = requisition.width;
2025           allocation.height = requisition.height;
2026         }
2027       gtk_widget_size_allocate (widget, &allocation);
2028       
2029       gtk_container_queue_resize (GTK_CONTAINER (widget));
2030
2031       g_return_if_fail (!GTK_WIDGET_REALIZED (widget));
2032     }
2033   
2034   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
2035   
2036   switch (window->type)
2037     {
2038     case GTK_WINDOW_TOPLEVEL:
2039       attributes.window_type = GDK_WINDOW_TOPLEVEL;
2040       break;
2041     case GTK_WINDOW_POPUP:
2042       attributes.window_type = GDK_WINDOW_TEMP;
2043       break;
2044     default:
2045       g_warning (G_STRLOC": Unknown window type %d!", window->type);
2046       break;
2047     }
2048    
2049   attributes.title = window->title;
2050   attributes.wmclass_name = window->wmclass_name;
2051   attributes.wmclass_class = window->wmclass_class;
2052   attributes.wclass = GDK_INPUT_OUTPUT;
2053   attributes.visual = gtk_widget_get_visual (widget);
2054   attributes.colormap = gtk_widget_get_colormap (widget);
2055
2056   if (window->has_frame)
2057     {
2058       attributes.width = widget->allocation.width + window->frame_left + window->frame_right;
2059       attributes.height = widget->allocation.height + window->frame_top + window->frame_bottom;
2060       attributes.event_mask = (GDK_EXPOSURE_MASK |
2061                                GDK_KEY_PRESS_MASK |
2062                                GDK_ENTER_NOTIFY_MASK |
2063                                GDK_LEAVE_NOTIFY_MASK |
2064                                GDK_FOCUS_CHANGE_MASK |
2065                                GDK_STRUCTURE_MASK |
2066                                GDK_BUTTON_MOTION_MASK |
2067                                GDK_POINTER_MOTION_HINT_MASK |
2068                                GDK_BUTTON_PRESS_MASK |
2069                                GDK_BUTTON_RELEASE_MASK);
2070       
2071       attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP;
2072       
2073       window->frame = gdk_window_new (NULL, &attributes, attributes_mask);
2074       gdk_window_set_user_data (window->frame, widget);
2075       
2076       attributes.window_type = GDK_WINDOW_CHILD;
2077       attributes.x = window->frame_left;
2078       attributes.y = window->frame_right;
2079     
2080       attributes_mask = GDK_WA_X | GDK_WA_Y;
2081
2082       parent_window = window->frame;
2083     }
2084   else
2085     {
2086       attributes_mask = 0;
2087       parent_window = NULL;
2088     }
2089   
2090   attributes.width = widget->allocation.width;
2091   attributes.height = widget->allocation.height;
2092   attributes.event_mask = gtk_widget_get_events (widget);
2093   attributes.event_mask |= (GDK_EXPOSURE_MASK |
2094                             GDK_KEY_PRESS_MASK |
2095                             GDK_ENTER_NOTIFY_MASK |
2096                             GDK_LEAVE_NOTIFY_MASK |
2097                             GDK_FOCUS_CHANGE_MASK |
2098                             GDK_STRUCTURE_MASK);
2099
2100   attributes_mask |= GDK_WA_VISUAL | GDK_WA_COLORMAP;
2101   attributes_mask |= (window->title ? GDK_WA_TITLE : 0);
2102   attributes_mask |= (window->wmclass_name ? GDK_WA_WMCLASS : 0);
2103   widget->window = gdk_window_new (parent_window, &attributes, attributes_mask);
2104   gdk_window_set_user_data (widget->window, window);
2105       
2106   widget->style = gtk_style_attach (widget->style, widget->window);
2107   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
2108   if (window->frame)
2109     gtk_style_set_background (widget->style, window->frame, GTK_STATE_NORMAL);
2110
2111   /* This is a bad hack to set the window background. */
2112   gtk_window_paint (widget, NULL);
2113   
2114   if (window->transient_parent &&
2115       GTK_WIDGET_REALIZED (window->transient_parent))
2116     gdk_window_set_transient_for (widget->window,
2117                                   GTK_WIDGET (window->transient_parent)->window);
2118
2119   if (window->wm_role)
2120     gdk_window_set_role (widget->window, window->wm_role);
2121   
2122   if (!window->decorated)
2123     gdk_window_set_decorations (widget->window, 0);
2124
2125   gdk_window_set_type_hint (widget->window, window->type_hint);
2126
2127   /* transient_for must be set to allow the modal hint */
2128   if (window->transient_parent && window->modal)
2129     gdk_window_set_modal_hint (widget->window, TRUE);
2130   else
2131     gdk_window_set_modal_hint (widget->window, FALSE);
2132 }
2133
2134 static void
2135 gtk_window_unrealize (GtkWidget *widget)
2136 {
2137   GtkWindow *window;
2138
2139   g_return_if_fail (widget != NULL);
2140   g_return_if_fail (GTK_IS_WINDOW (widget));
2141
2142   window = GTK_WINDOW (widget);
2143
2144   if (window->frame)
2145     {
2146       gdk_window_set_user_data (window->frame, NULL);
2147       gdk_window_destroy (window->frame);
2148       window->frame = NULL;
2149     }
2150   
2151   (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
2152 }
2153
2154 static void
2155 gtk_window_size_request (GtkWidget      *widget,
2156                          GtkRequisition *requisition)
2157 {
2158   GtkWindow *window;
2159   GtkBin *bin;
2160
2161   g_return_if_fail (widget != NULL);
2162   g_return_if_fail (GTK_IS_WINDOW (widget));
2163   g_return_if_fail (requisition != NULL);
2164
2165   window = GTK_WINDOW (widget);
2166   bin = GTK_BIN (window);
2167   
2168   requisition->width = GTK_CONTAINER (window)->border_width * 2;
2169   requisition->height = GTK_CONTAINER (window)->border_width * 2;
2170
2171   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
2172     {
2173       GtkRequisition child_requisition;
2174       
2175       gtk_widget_size_request (bin->child, &child_requisition);
2176
2177       requisition->width += child_requisition.width;
2178       requisition->height += child_requisition.height;
2179     }
2180 }
2181
2182 static void
2183 gtk_window_size_allocate (GtkWidget     *widget,
2184                           GtkAllocation *allocation)
2185 {
2186   GtkWindow *window;
2187   GtkAllocation child_allocation;
2188
2189   g_return_if_fail (widget != NULL);
2190   g_return_if_fail (GTK_IS_WINDOW (widget));
2191   g_return_if_fail (allocation != NULL);
2192
2193   window = GTK_WINDOW (widget);
2194   widget->allocation = *allocation;
2195
2196   if (window->bin.child && GTK_WIDGET_VISIBLE (window->bin.child))
2197     {
2198       child_allocation.x = GTK_CONTAINER (window)->border_width;
2199       child_allocation.y = GTK_CONTAINER (window)->border_width;
2200       child_allocation.width =
2201         MAX (1, (gint)allocation->width - child_allocation.x * 2);
2202       child_allocation.height =
2203         MAX (1, (gint)allocation->height - child_allocation.y * 2);
2204
2205       gtk_widget_size_allocate (window->bin.child, &child_allocation);
2206     }
2207
2208   if (GTK_WIDGET_REALIZED (widget) && window->frame)
2209     {
2210       gdk_window_resize (window->frame,
2211                          allocation->width + window->frame_left + window->frame_right,
2212                          allocation->height + window->frame_top + window->frame_bottom);
2213     }
2214 }
2215
2216 static gint
2217 gtk_window_event (GtkWidget *widget, GdkEvent *event)
2218 {
2219   GtkWindow *window;
2220   gboolean return_val;
2221
2222   
2223   g_return_val_if_fail (widget != NULL, FALSE);
2224   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
2225   g_return_val_if_fail (event != NULL, FALSE);
2226   
2227   window = GTK_WINDOW (widget);
2228
2229   if (window->frame && (event->any.window == window->frame))
2230     {
2231       if ((event->type != GDK_KEY_PRESS) &&
2232           (event->type != GDK_KEY_RELEASE) &&
2233           (event->type != GDK_FOCUS_CHANGE))
2234         {
2235           gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "event");
2236           return_val = FALSE;
2237           gtk_signal_emit (GTK_OBJECT (widget), window_signals[FRAME_EVENT], event, &return_val);
2238           return TRUE;
2239         }
2240       else
2241         {
2242           g_object_unref (event->any.window);
2243           event->any.window = g_object_ref (widget->window);
2244         }
2245     }
2246
2247   return FALSE;
2248 }
2249
2250 static gboolean
2251 gtk_window_frame_event (GtkWidget *widget, GdkEvent *event)
2252 {
2253   GdkEventConfigure *configure_event;
2254   GtkWindow *window = GTK_WINDOW (widget);
2255   GdkRectangle rect;
2256
2257   switch (event->type)
2258     {
2259     case GDK_CONFIGURE:
2260       configure_event = (GdkEventConfigure *)event;
2261       
2262       /* Invalidate the decorations */
2263       rect.x = 0;
2264       rect.y = 0;
2265       rect.width = configure_event->width;
2266       rect.height = configure_event->height;
2267       
2268       gdk_window_invalidate_rect (window->frame, &rect, FALSE);
2269
2270       /* Pass on the (modified) configure event */
2271       configure_event->width -= window->frame_left + window->frame_right;
2272       configure_event->height -= window->frame_top + window->frame_bottom;
2273       return gtk_window_configure_event (widget, configure_event);
2274       break;
2275     default:
2276       break;
2277     }
2278   return FALSE;
2279 }
2280
2281 static gint
2282 gtk_window_configure_event (GtkWidget         *widget,
2283                             GdkEventConfigure *event)
2284 {
2285   GtkWindow *window;
2286   
2287   g_return_val_if_fail (widget != NULL, FALSE);
2288   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
2289   g_return_val_if_fail (event != NULL, FALSE);
2290   
2291   window = GTK_WINDOW (widget);
2292
2293   /* we got a configure event specifying the new window size and position,
2294    * in principle we have to distinguish 4 cases here:
2295    * 1) the size didn't change and resize_count == 0
2296    *    -> the window was merely moved (sometimes not even that)
2297    * 2) the size didn't change and resize_count > 0
2298    *    -> we requested a new size, but didn't get it
2299    * 3) the size changed and resize_count > 0
2300    *    -> we asked for a new size and we got one
2301    * 4) the size changed and resize_count == 0
2302    *    -> we got resized from outside the toolkit, and have to
2303    *    accept that size since we don't want to fight neither the
2304    *    window manager nor the user
2305    * in the three latter cases we have to reallocate the widget tree,
2306    * which happens in gtk_window_move_resize(), so we set a flag for
2307    * that function and assign the new size. if resize_count > 1,
2308    * we simply do nothing and wait for more configure events.
2309    */
2310
2311   if (window->resize_count > 0 ||
2312       widget->allocation.width != event->width ||
2313       widget->allocation.height != event->height)
2314     {
2315       if (window->resize_count > 0)
2316         window->resize_count -= 1;
2317
2318       if (window->resize_count == 0)
2319         {
2320           window->handling_resize = TRUE;
2321           
2322           widget->allocation.width = event->width;
2323           widget->allocation.height = event->height;
2324           
2325           gtk_widget_queue_resize (widget);
2326         }
2327     }
2328
2329   return TRUE;
2330 }
2331
2332 static gint
2333 gtk_window_key_press_event (GtkWidget   *widget,
2334                             GdkEventKey *event)
2335 {
2336   GtkWindow *window;
2337   gboolean handled;
2338
2339   g_return_val_if_fail (widget != NULL, FALSE);
2340   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
2341   g_return_val_if_fail (event != NULL, FALSE);
2342
2343   window = GTK_WINDOW (widget);
2344
2345   handled = FALSE;
2346   
2347   if (window->focus_widget && window->focus_widget != widget &&
2348       GTK_WIDGET_IS_SENSITIVE (window->focus_widget))
2349     handled = gtk_widget_event (window->focus_widget, (GdkEvent*) event);
2350
2351   if (!handled)
2352     handled = gtk_window_mnemonic_activate (window,
2353                                             event->keyval,
2354                                             event->state);
2355
2356   if (!handled)
2357     handled = gtk_accel_groups_activate (GTK_OBJECT (window), event->keyval, event->state);
2358
2359   /* Chain up, invokes binding set */
2360   if (!handled && GTK_WIDGET_CLASS (parent_class)->key_press_event)
2361     handled = GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
2362
2363   return handled;
2364 }
2365
2366
2367 static void
2368 gtk_window_real_activate_default (GtkWindow *window)
2369 {
2370   gtk_window_activate_default (window);
2371 }
2372
2373 static void
2374 gtk_window_real_activate_focus (GtkWindow *window)
2375 {
2376   gtk_window_activate_focus (window);
2377 }
2378
2379 static void
2380 gtk_window_move_focus (GtkWindow       *window,
2381                        GtkDirectionType dir)
2382 {
2383   gtk_widget_child_focus (GTK_WIDGET (window), dir);
2384   
2385   if (!GTK_CONTAINER (window)->focus_child)
2386     gtk_window_set_focus (window, NULL);
2387 }
2388
2389 static gint
2390 gtk_window_key_release_event (GtkWidget   *widget,
2391                               GdkEventKey *event)
2392 {
2393   GtkWindow *window;
2394   gint handled;
2395   
2396   g_return_val_if_fail (widget != NULL, FALSE);
2397   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
2398   g_return_val_if_fail (event != NULL, FALSE);
2399   
2400   window = GTK_WINDOW (widget);
2401   handled = FALSE;
2402   if (window->focus_widget &&
2403       window->focus_widget != widget &&
2404       GTK_WIDGET_SENSITIVE (window->focus_widget))
2405     {
2406       handled = gtk_widget_event (window->focus_widget, (GdkEvent*) event);
2407     }
2408
2409   if (!handled && GTK_WIDGET_CLASS (parent_class)->key_release_event)
2410     handled = GTK_WIDGET_CLASS (parent_class)->key_release_event (widget, event);
2411
2412   return handled;
2413 }
2414
2415 static gint
2416 gtk_window_enter_notify_event (GtkWidget        *widget,
2417                                GdkEventCrossing *event)
2418 {
2419   g_return_val_if_fail (widget != NULL, FALSE);
2420   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
2421   g_return_val_if_fail (event != NULL, FALSE);
2422
2423   return FALSE;
2424 }
2425
2426 static gint
2427 gtk_window_leave_notify_event (GtkWidget        *widget,
2428                                GdkEventCrossing *event)
2429 {
2430   g_return_val_if_fail (widget != NULL, FALSE);
2431   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
2432   g_return_val_if_fail (event != NULL, FALSE);
2433
2434   return FALSE;
2435 }
2436
2437 static gint
2438 gtk_window_focus_in_event (GtkWidget     *widget,
2439                            GdkEventFocus *event)
2440 {
2441   GtkWindow *window = GTK_WINDOW (widget);
2442   GdkEventFocus fevent;
2443
2444   /* It appears spurious focus in events can occur when
2445    *  the window is hidden. So we'll just check to see if
2446    *  the window is visible before actually handling the
2447    *  event
2448    */
2449   if (GTK_WIDGET_VISIBLE (widget))
2450     {
2451       window->has_focus = TRUE;
2452       
2453       if (window->focus_widget &&
2454           window->focus_widget != widget &&
2455           !GTK_WIDGET_HAS_FOCUS (window->focus_widget))
2456         {
2457           fevent.type = GDK_FOCUS_CHANGE;
2458           fevent.window = window->focus_widget->window;
2459           fevent.in = TRUE;
2460
2461           gtk_widget_event (window->focus_widget, (GdkEvent*) &fevent);
2462         }
2463     }
2464
2465   return FALSE;
2466 }
2467
2468 static gint
2469 gtk_window_focus_out_event (GtkWidget     *widget,
2470                             GdkEventFocus *event)
2471 {
2472   GtkWindow *window = GTK_WINDOW (widget);
2473   GdkEventFocus fevent;
2474
2475   window->has_focus = FALSE;
2476   
2477   if (window->focus_widget &&
2478       window->focus_widget != widget &&
2479       GTK_WIDGET_HAS_FOCUS (window->focus_widget))
2480     {
2481       fevent.type = GDK_FOCUS_CHANGE;
2482       fevent.window = window->focus_widget->window;
2483       fevent.in = FALSE;
2484
2485       gtk_widget_event (window->focus_widget, (GdkEvent*) &fevent);
2486     }
2487
2488   return FALSE;
2489 }
2490
2491 static GdkAtom atom_rcfiles = GDK_NONE;
2492
2493 static void
2494 gtk_window_read_rcfiles (GtkWidget *widget,
2495                          GdkEventClient *event)
2496 {
2497   GList *embedded_windows;
2498
2499   embedded_windows = gtk_object_get_data (GTK_OBJECT (widget), "gtk-embedded");
2500   if (embedded_windows)
2501     {
2502       GdkEventClient sev;
2503       int i;
2504       
2505       for(i = 0; i < 5; i++)
2506         sev.data.l[i] = 0;
2507       sev.data_format = 32;
2508       sev.message_type = atom_rcfiles;
2509       
2510       while (embedded_windows)
2511         {
2512           guint xid = GPOINTER_TO_UINT (embedded_windows->data);
2513           gdk_event_send_client_message ((GdkEvent *) &sev, xid);
2514           embedded_windows = embedded_windows->next;
2515         }
2516     }
2517
2518   if (gtk_rc_reparse_all ())
2519     {
2520       /* If the above returned true, some of our RC files are out
2521        * of date, so we need to reset all our widgets. Our other
2522        * toplevel windows will also get the message, but by
2523        * then, the RC file will up to date, so we have to tell
2524        * them now. Also, we have to invalidate cached icons in
2525        * icon sets so they get re-rendered.
2526        */
2527       GList *list, *toplevels;
2528
2529       _gtk_icon_set_invalidate_caches ();
2530       
2531       toplevels = gtk_window_list_toplevels ();
2532       g_list_foreach (toplevels, (GFunc)g_object_ref, NULL);
2533       
2534       for (list = toplevels; list; list = list->next)
2535         {
2536           gtk_widget_reset_rc_styles (list->data);
2537           gtk_widget_unref (list->data);
2538         }
2539       g_list_free (toplevels);
2540     }
2541 }
2542
2543 static gint
2544 gtk_window_client_event (GtkWidget      *widget,
2545                          GdkEventClient *event)
2546 {
2547   g_return_val_if_fail (widget != NULL, FALSE);
2548   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
2549   g_return_val_if_fail (event != NULL, FALSE);
2550
2551   if (!atom_rcfiles)
2552     atom_rcfiles = gdk_atom_intern("_GTK_READ_RCFILES", FALSE);
2553
2554   if(event->message_type == atom_rcfiles) 
2555     gtk_window_read_rcfiles (widget, event);    
2556
2557   return FALSE;
2558 }
2559
2560 static void
2561 gtk_window_check_resize (GtkContainer *container)
2562 {
2563   GtkWindow *window;
2564
2565   g_return_if_fail (container != NULL);
2566   g_return_if_fail (GTK_IS_WINDOW (container));
2567
2568   window = GTK_WINDOW (container);
2569
2570   if (GTK_WIDGET_VISIBLE (container))
2571     gtk_window_move_resize (window);
2572 }
2573
2574 static gboolean
2575 gtk_window_focus (GtkWidget        *widget,
2576                   GtkDirectionType  direction)
2577 {
2578   GtkBin *bin;
2579   GtkWindow *window;
2580   GtkContainer *container;
2581   GtkWidget *old_focus_child;
2582   GtkWidget *parent;
2583
2584   container = GTK_CONTAINER (widget);
2585   window = GTK_WINDOW (widget);
2586   bin = GTK_BIN (widget);
2587
2588   old_focus_child = container->focus_child;
2589   
2590   /* We need a special implementation here to deal properly with wrapping
2591    * around in the tab chain without the danger of going into an
2592    * infinite loop.
2593    */
2594   if (old_focus_child)
2595     {
2596       if (gtk_widget_child_focus (old_focus_child, direction))
2597         return TRUE;
2598     }
2599
2600   if (window->focus_widget)
2601     {
2602       /* Wrapped off the end, clear the focus setting for the toplpevel */
2603       parent = window->focus_widget->parent;
2604       while (parent)
2605         {
2606           gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
2607           parent = GTK_WIDGET (parent)->parent;
2608         }
2609       
2610       gtk_window_set_focus (GTK_WINDOW (container), NULL);
2611     }
2612
2613   /* Now try to focus the first widget in the window */
2614   if (bin->child)
2615     {
2616       if (gtk_widget_child_focus (bin->child, direction))
2617         return TRUE;
2618     }
2619
2620   return FALSE;
2621 }
2622
2623 static void
2624 gtk_window_real_set_focus (GtkWindow *window,
2625                            GtkWidget *focus)
2626 {
2627   GdkEventFocus event;
2628   gboolean def_flags = 0;
2629
2630   g_return_if_fail (window != NULL);
2631   g_return_if_fail (GTK_IS_WINDOW (window));
2632   
2633   if (window->default_widget)
2634     def_flags = GTK_WIDGET_HAS_DEFAULT (window->default_widget);
2635   
2636   if (window->focus_widget)
2637     {
2638       if (GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget) &&
2639           (window->focus_widget != window->default_widget))
2640         {
2641           GTK_WIDGET_UNSET_FLAGS (window->focus_widget, GTK_HAS_DEFAULT);
2642
2643           if (window->default_widget)
2644             GTK_WIDGET_SET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
2645         }
2646
2647       if (window->has_focus)
2648         {
2649           event.type = GDK_FOCUS_CHANGE;
2650           event.window = window->focus_widget->window;
2651           event.in = FALSE;
2652           
2653           gtk_widget_event (window->focus_widget, (GdkEvent*) &event);
2654         }
2655     }
2656   
2657   window->focus_widget = focus;
2658   
2659   if (window->focus_widget)
2660     {
2661       if (GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget) &&
2662           (window->focus_widget != window->default_widget))
2663         {
2664           if (GTK_WIDGET_CAN_DEFAULT (window->focus_widget))
2665             GTK_WIDGET_SET_FLAGS (window->focus_widget, GTK_HAS_DEFAULT);
2666
2667           if (window->default_widget)
2668             GTK_WIDGET_UNSET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
2669         }
2670
2671       if (window->has_focus)
2672         {
2673           event.type = GDK_FOCUS_CHANGE;
2674           event.window = window->focus_widget->window;
2675           event.in = TRUE;
2676           
2677           gtk_widget_event (window->focus_widget, (GdkEvent*) &event);
2678         }
2679     }
2680   
2681   if (window->default_widget &&
2682       (def_flags != GTK_WIDGET_FLAGS (window->default_widget)))
2683     gtk_widget_queue_draw (window->default_widget);
2684 }
2685
2686
2687
2688 /*********************************
2689  * Functions related to resizing *
2690  *********************************/
2691
2692 static void
2693 gtk_window_move_resize (GtkWindow *window)
2694 {
2695   GtkWidget *widget;
2696   GtkContainer *container;
2697   GtkWindowGeometryInfo *info;
2698   GtkWindowLastGeometryInfo saved_last_info;
2699   GdkGeometry new_geometry;
2700   guint new_flags;
2701   gint x, y;
2702   gint width, height;
2703   gint new_width, new_height;
2704   gboolean need_reposition;
2705   gboolean default_size_changed = FALSE;
2706   gboolean hints_changed = FALSE;
2707   gboolean may_shrink = window->auto_shrink;
2708
2709   g_return_if_fail (GTK_WIDGET_REALIZED (window));
2710
2711   widget = GTK_WIDGET (window);
2712   container = GTK_CONTAINER (widget);
2713   info = gtk_window_get_geometry_info (window, TRUE);
2714   saved_last_info = info->last;
2715
2716   gtk_widget_size_request (widget, NULL);
2717   gtk_window_compute_default_size (window, &new_width, &new_height);
2718   
2719   if (info->last.width < 0 ||
2720       info->last.width != new_width ||
2721       info->last.height != new_height)
2722     {
2723       default_size_changed = TRUE;
2724       may_shrink |= info->may_shrink;
2725       info->last.width = new_width;
2726       info->last.height = new_height;
2727
2728       /* We need to force a reposition in this case
2729        */
2730       if (window->position == GTK_WIN_POS_CENTER_ALWAYS)
2731         window->use_uposition = TRUE;
2732     }
2733   info->may_shrink = FALSE;
2734   
2735   /* Compute new set of hints for the window
2736    */
2737   gtk_window_compute_hints (window, &new_geometry, &new_flags);
2738   if (!gtk_window_compare_hints (&info->last.geometry, info->last.flags,
2739                                  &new_geometry, new_flags))
2740     {
2741       hints_changed = TRUE;
2742       info->last.geometry = new_geometry;
2743       info->last.flags = new_flags;
2744     }
2745
2746   /* From the default size and the allocation, figure out the size
2747    * the window should be.
2748    */
2749   if (!default_size_changed ||
2750       (!may_shrink &&
2751        new_width <= widget->allocation.width &&
2752        new_height <= widget->allocation.height))
2753     {
2754       new_width = widget->allocation.width;
2755       new_height = widget->allocation.height;
2756     }
2757
2758   /* constrain the window size to the specified geometry */
2759   gtk_window_constrain_size (window,
2760                              &new_geometry, new_flags,
2761                              new_width, new_height,
2762                              &new_width, &new_height);
2763
2764   /* compute new window position if a move is required
2765    */
2766   need_reposition = gtk_window_compute_reposition (window, new_width, new_height, &x, &y);
2767   if (need_reposition && !(new_flags & GDK_HINT_POS))
2768     {
2769       new_flags |= GDK_HINT_POS;
2770       hints_changed = TRUE;
2771     }
2772
2773
2774   /* handle actual resizing:
2775    * - handle reallocations due to configure events
2776    * - figure whether we need to request a new window size
2777    * - handle simple resizes within our widget tree
2778    * - reposition window if neccessary
2779    */
2780   width = widget->allocation.width;
2781   height = widget->allocation.height;
2782
2783   if (window->handling_resize)
2784     { 
2785       GtkAllocation allocation;
2786       
2787       /* if we are just responding to a configure event, which
2788        * might be due to a resize by the window manager, the
2789        * user, or a response to a resizing request we made
2790        * earlier, we go ahead, allocate the new size and we're done
2791        * (see gtk_window_configure_event() for more details).
2792        */
2793       
2794       window->handling_resize = FALSE;
2795       
2796       allocation = widget->allocation;
2797       
2798       gtk_widget_size_allocate (widget, &allocation);
2799       gtk_widget_queue_draw (widget);
2800
2801       if ((default_size_changed || hints_changed) && (width != new_width || height != new_height))
2802         {
2803           /* We could be here for two reasons
2804            *  1) We coincidentally got a resize while handling
2805            *     another resize.
2806            *  2) Our computation of default_size_changed was completely
2807            *     screwed up, probably because one of our children
2808            *     is changed requisition during size allocation).
2809            *
2810            * For 1), we could just go ahead and ask for the
2811            * new size right now, but doing that for 2)
2812            * might well be fighting the user (and can even
2813            * trigger a loop). Since we really don't want to
2814            * do that, we requeue a resize in hopes that
2815            * by the time it gets handled, the child has seen
2816            * the light and is willing to go along with the
2817            * new size. (this happens for the zvt widget, since
2818            * the size_allocate() above will have stored the
2819            * requisition corresponding to the new size in the
2820            * zvt widget)
2821            *
2822            * This doesn't buy us anything for 1), but it shouldn't
2823            * hurt us too badly, since it is what would have
2824            * happened if we had gotten the configure event before
2825            * the new size had been set.
2826            */
2827           
2828           if (need_reposition)
2829             {
2830               if (window->frame)
2831                 gdk_window_move (window->frame, x - window->frame_left, y - window->frame_top);
2832               else
2833                 gdk_window_move (GTK_WIDGET (window)->window, x, y);
2834             }
2835
2836           /* we have to preserve the values and flags that are used
2837            * for computation of default_size_changed and hints_changed
2838            */
2839           info->last = saved_last_info;
2840           
2841           gtk_widget_queue_resize (widget);
2842
2843           return;
2844         }
2845     }
2846
2847   /* Now set hints if necessary
2848    */
2849   if (hints_changed)
2850     gdk_window_set_geometry_hints (widget->window,
2851                                    &new_geometry,
2852                                    new_flags);
2853
2854   if ((default_size_changed || hints_changed) &&
2855       (width != new_width || height != new_height))
2856     {
2857       /* given that (width != new_width || height != new_height), we are in one
2858        * of the following situations:
2859        * 
2860        * default_size_changed
2861        *   our requisition has changed and we need a different window size,
2862        *   so we request it from the window manager.
2863        *
2864        * !default_size_changed
2865        *   the window manager wouldn't assign us the size we requested, in this
2866        *   case we don't try to request a new size with every resize.
2867        *
2868        * !default_size_changed && hints_changed
2869        *   the window manager rejects our size, but we have just changed the
2870        *   window manager hints, so there's a certain chance our request will
2871        *   be honoured this time, so we try again.
2872        */
2873       
2874       /* request a new window size */
2875       if (need_reposition)
2876         {
2877           if (window->frame)
2878             {
2879               gdk_window_move_resize (window->frame,
2880                                       x - window->frame_left, y - window->frame_top,
2881                                       new_width + window->frame_left + window->frame_right,
2882                                       new_height + window->frame_top + window->frame_bottom);
2883               gdk_window_resize (GTK_WIDGET (window)->window, new_width, new_height);
2884             }
2885           else
2886             gdk_window_move_resize (GTK_WIDGET (window)->window, x, y, new_width, new_height);
2887         }
2888       else
2889         {
2890           if (window->frame)
2891             gdk_window_resize (window->frame,
2892                                new_width + window->frame_left + window->frame_right,
2893                                new_height + window->frame_top + window->frame_bottom);
2894           gdk_window_resize (GTK_WIDGET (window)->window, new_width, new_height);
2895         }
2896       window->resize_count += 1;
2897       
2898       /* we are now awaiting the new configure event in response to our
2899        * resizing request. the configure event will cause a new resize
2900        * with ->handling_resize=TRUE.
2901        * until then, we want to
2902        * - discard expose events
2903        * - coalesce resizes for our children
2904        * - defer any window resizes until the configure event arrived
2905        * to achive this, we queue a resize for the window, but remove its
2906        * resizing handler, so resizing will not be handled from the next
2907        * idle handler but when the configure event arrives.
2908        *
2909        * FIXME: we should also dequeue the pending redraws here, since
2910        * we handle those ourselves in ->handling_resize==TRUE.
2911        */
2912       gtk_widget_queue_resize (GTK_WIDGET (container));
2913       if (container->resize_mode == GTK_RESIZE_QUEUE)
2914         gtk_container_dequeue_resize_handler (container);
2915     }
2916   else
2917     {
2918       if (need_reposition)
2919         {
2920           if (window->frame)
2921             gdk_window_move (window->frame, x - window->frame_left, y - window->frame_top);
2922           else
2923             gdk_window_move (widget->window, x, y);
2924         }
2925
2926       if (container->resize_widgets)
2927         gtk_container_resize_children (GTK_CONTAINER (window));
2928     }
2929 }
2930
2931 /* Compare two sets of Geometry hints for equality.
2932  */
2933 static gboolean
2934 gtk_window_compare_hints (GdkGeometry *geometry_a,
2935                           guint        flags_a,
2936                           GdkGeometry *geometry_b,
2937                           guint        flags_b)
2938 {
2939   if (flags_a != flags_b)
2940     return FALSE;
2941   
2942   if ((flags_a & GDK_HINT_MIN_SIZE) &&
2943       (geometry_a->min_width != geometry_b->min_width ||
2944        geometry_a->min_height != geometry_b->min_height))
2945     return FALSE;
2946
2947   if ((flags_a & GDK_HINT_MAX_SIZE) &&
2948       (geometry_a->max_width != geometry_b->max_width ||
2949        geometry_a->max_height != geometry_b->max_height))
2950     return FALSE;
2951
2952   if ((flags_a & GDK_HINT_BASE_SIZE) &&
2953       (geometry_a->base_width != geometry_b->base_width ||
2954        geometry_a->base_height != geometry_b->base_height))
2955     return FALSE;
2956
2957   if ((flags_a & GDK_HINT_ASPECT) &&
2958       (geometry_a->min_aspect != geometry_b->min_aspect ||
2959        geometry_a->max_aspect != geometry_b->max_aspect))
2960     return FALSE;
2961
2962   if ((flags_a & GDK_HINT_RESIZE_INC) &&
2963       (geometry_a->width_inc != geometry_b->width_inc ||
2964        geometry_a->height_inc != geometry_b->height_inc))
2965     return FALSE;
2966
2967   if ((flags_a & GDK_HINT_WIN_GRAVITY) &&
2968       geometry_a->win_gravity != geometry_b->win_gravity)
2969     return FALSE;
2970
2971   return TRUE;
2972 }
2973
2974 /* Compute the default_size for a window. The result will
2975  * be stored in *width and *height. The default size is
2976  * the size the window should have when initially mapped.
2977  * This routine does not attempt to constrain the size
2978  * to obey the geometry hints - that must be done elsewhere.
2979  */
2980 static void 
2981 gtk_window_compute_default_size (GtkWindow       *window,
2982                                  guint           *width,
2983                                  guint           *height)
2984 {
2985   GtkRequisition requisition;
2986   GtkWindowGeometryInfo *info;
2987   
2988   gtk_widget_get_child_requisition (GTK_WIDGET (window), &requisition);
2989   *width = requisition.width;
2990   *height = requisition.height;
2991
2992   info = gtk_window_get_geometry_info (window, FALSE);
2993   
2994   if (*width == 0 && *height == 0)
2995     {
2996       /* empty window */
2997       *width = 200;
2998       *height = 200;
2999     }
3000   
3001   if (info)
3002     {
3003       *width = info->width > 0 ? info->width : *width;
3004       *height = info->height > 0 ? info->height : *height;
3005     }
3006 }
3007
3008 void
3009 _gtk_window_constrain_size (GtkWindow   *window,
3010                             gint         width,
3011                             gint         height,
3012                             gint        *new_width,
3013                             gint        *new_height)
3014 {
3015   GtkWindowGeometryInfo *info;
3016
3017   g_return_if_fail (GTK_IS_WINDOW (window));
3018
3019   info = window->geometry_info;
3020   if (info)
3021     {
3022       GdkWindowHints flags = info->last.flags;
3023       GdkGeometry *geometry = &info->last.geometry;
3024       
3025       gtk_window_constrain_size (window,
3026                                  geometry,
3027                                  flags,
3028                                  width,
3029                                  height,
3030                                  new_width,
3031                                  new_height);
3032     }
3033 }
3034
3035 static void 
3036 gtk_window_constrain_size (GtkWindow   *window,
3037                            GdkGeometry *geometry,
3038                            guint        flags,
3039                            gint         width,
3040                            gint         height,
3041                            gint        *new_width,
3042                            gint        *new_height)
3043 {
3044   gdk_window_constrain_size (geometry, flags, width, height,
3045                              new_width, new_height);
3046 }
3047
3048 /* Compute the set of geometry hints and flags for a window
3049  * based on the application set geometry, and requisiition
3050  * of the window. gtk_widget_size_request() must have been
3051  * called first.
3052  */
3053 static void
3054 gtk_window_compute_hints (GtkWindow   *window,
3055                           GdkGeometry *new_geometry,
3056                           guint       *new_flags)
3057 {
3058   GtkWidget *widget;
3059   GtkWidgetAuxInfo *aux_info;
3060   gint ux, uy;
3061   gint extra_width = 0;
3062   gint extra_height = 0;
3063   GtkWindowGeometryInfo *geometry_info;
3064   GtkRequisition requisition;
3065
3066   g_return_if_fail (GTK_IS_WINDOW (window));
3067
3068   widget = GTK_WIDGET (window);
3069   
3070   gtk_widget_get_child_requisition (widget, &requisition);
3071   geometry_info = gtk_window_get_geometry_info (GTK_WINDOW (widget), FALSE);
3072
3073   g_return_if_fail (geometry_info != NULL);
3074   
3075   *new_flags = geometry_info->mask;
3076   *new_geometry = geometry_info->geometry;
3077   
3078   if (geometry_info->widget)
3079     {
3080       extra_width = widget->requisition.width - geometry_info->widget->requisition.width;
3081       extra_height = widget->requisition.height - geometry_info->widget->requisition.height;
3082     }
3083   
3084   ux = 0;
3085   uy = 0;
3086   
3087   aux_info = _gtk_widget_get_aux_info (widget, FALSE);
3088   if (aux_info && aux_info->x_set && aux_info->y_set)
3089     {
3090       ux = aux_info->x;
3091       uy = aux_info->y;
3092       *new_flags |= GDK_HINT_POS;
3093     }
3094   
3095   if (*new_flags & GDK_HINT_BASE_SIZE)
3096     {
3097       new_geometry->base_width += extra_width;
3098       new_geometry->base_height += extra_height;
3099     }
3100   else if (!(*new_flags & GDK_HINT_MIN_SIZE) &&
3101            (*new_flags & GDK_HINT_RESIZE_INC) &&
3102            ((extra_width != 0) || (extra_height != 0)))
3103     {
3104       *new_flags |= GDK_HINT_BASE_SIZE;
3105       
3106       new_geometry->base_width = extra_width;
3107       new_geometry->base_height = extra_height;
3108     }
3109   
3110   if (*new_flags & GDK_HINT_MIN_SIZE)
3111     {
3112       if (new_geometry->min_width < 0)
3113         new_geometry->min_width = requisition.width;
3114       else
3115         new_geometry->min_width += extra_width;
3116
3117       if (new_geometry->min_height < 0)
3118         new_geometry->min_width = requisition.height;
3119       else
3120         new_geometry->min_height += extra_height;
3121     }
3122   else if (!window->allow_shrink)
3123     {
3124       *new_flags |= GDK_HINT_MIN_SIZE;
3125       
3126       new_geometry->min_width = requisition.width;
3127       new_geometry->min_height = requisition.height;
3128     }
3129   
3130   if (*new_flags & GDK_HINT_MAX_SIZE)
3131     {
3132       if (new_geometry->max_width < 0)
3133         new_geometry->max_width = requisition.width;
3134       else
3135         new_geometry->max_width += extra_width;
3136
3137       if (new_geometry->max_height < 0)
3138         new_geometry->max_width = requisition.height;
3139       else
3140         new_geometry->max_height += extra_height;
3141     }
3142   else if (!window->allow_grow)
3143     {
3144       *new_flags |= GDK_HINT_MAX_SIZE;
3145       
3146       new_geometry->max_width = requisition.width;
3147       new_geometry->max_height = requisition.height;
3148     }
3149
3150   *new_flags |= GDK_HINT_WIN_GRAVITY;
3151   new_geometry->win_gravity = window->gravity;
3152 }
3153
3154 /* Compute a new position for the window based on a new
3155  * size. *x and *y will be set to the new coordinates. Returns
3156  * TRUE if the window needs to be moved (and thus x and y got
3157  * assigned)
3158  */
3159 static gint
3160 gtk_window_compute_reposition (GtkWindow *window,
3161                                gint       new_width,
3162                                gint       new_height,
3163                                gint      *x,
3164                                gint      *y)
3165 {
3166   GtkWidget *widget = GTK_WIDGET (window);
3167   GtkWindowPosition pos;
3168   GtkWidget *parent_widget;
3169   gboolean needs_move = FALSE;
3170
3171   parent_widget = (GtkWidget*) window->transient_parent;
3172   
3173   pos = window->position;
3174   if (pos == GTK_WIN_POS_CENTER_ON_PARENT &&
3175       (parent_widget == NULL ||
3176        !GTK_WIDGET_MAPPED (parent_widget)))
3177     pos = GTK_WIN_POS_NONE;
3178   
3179   switch (pos)
3180   {
3181     case GTK_WIN_POS_CENTER:
3182     case GTK_WIN_POS_CENTER_ALWAYS:
3183       if (window->use_uposition)
3184         {
3185           gint screen_width = gdk_screen_width ();
3186           gint screen_height = gdk_screen_height ();
3187           
3188           *x = (screen_width - new_width) / 2;
3189           *y = (screen_height - new_height) / 2;
3190           needs_move = TRUE;
3191         }
3192       break;
3193
3194     case GTK_WIN_POS_CENTER_ON_PARENT:
3195       if (window->use_uposition)
3196         {
3197           gint ox, oy;
3198           gdk_window_get_origin (parent_widget->window,
3199                                    &ox, &oy);
3200                                  
3201           *x = ox + (parent_widget->allocation.width - new_width) / 2;
3202           *y = oy + (parent_widget->allocation.height - new_height) / 2;
3203           needs_move = TRUE;
3204         }
3205       break;
3206
3207     case GTK_WIN_POS_MOUSE:
3208       if (window->use_uposition)
3209         {
3210           gint screen_width = gdk_screen_width ();
3211           gint screen_height = gdk_screen_height ();
3212           
3213           gdk_window_get_pointer (NULL, x, y, NULL);
3214           *x -= new_width / 2;
3215           *y -= new_height / 2;
3216           *x = CLAMP (*x, 0, screen_width - new_width);
3217           *y = CLAMP (*y, 0, screen_height - new_height);
3218           needs_move = TRUE;
3219         }
3220       break;
3221     default:
3222       if (window->use_uposition)
3223         {
3224           GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (widget, FALSE);
3225
3226           if (aux_info && aux_info->x_set && aux_info->y_set)
3227             {
3228               *x = aux_info->x;
3229               *y = aux_info->y;
3230               needs_move = TRUE;
3231             }
3232         }
3233       break;
3234     }
3235
3236   if (needs_move)
3237     {
3238       GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (widget, TRUE);
3239
3240       /* we handle necessary window positioning by hand here,
3241        * so we can coalesce the window movement with possible
3242        * resizes to get only one configure event.
3243        */
3244       aux_info->x_set = TRUE;
3245       aux_info->y_set = TRUE;
3246       aux_info->x = *x;
3247       aux_info->y = *y;
3248       window->use_uposition = FALSE;
3249     }
3250
3251   return needs_move;
3252 }
3253
3254 /***********************
3255  * Redrawing functions *
3256  ***********************/
3257
3258 static void
3259 gtk_window_paint (GtkWidget     *widget,
3260                   GdkRectangle *area)
3261 {
3262   gtk_paint_flat_box (widget->style, widget->window, GTK_STATE_NORMAL, 
3263                       GTK_SHADOW_NONE, area, widget, "base", 0, 0, -1, -1);
3264 }
3265
3266 static gint
3267 gtk_window_expose (GtkWidget      *widget,
3268                    GdkEventExpose *event)
3269 {
3270   g_return_val_if_fail (widget != NULL, FALSE);
3271   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
3272   g_return_val_if_fail (event != NULL, FALSE);
3273
3274   if (!GTK_WIDGET_APP_PAINTABLE (widget))
3275     gtk_window_paint (widget, &event->area);
3276   
3277   if (GTK_WIDGET_CLASS (parent_class)->expose_event)
3278     return GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
3279
3280   return TRUE;
3281 }
3282
3283 /**
3284  * gtk_window_set_has_frame:
3285  * @window: a #GtkWindow
3286  * @setting: a boolean
3287  * 
3288  * If this function is called on a window with setting of TRUE, before
3289  * it is realized or showed, it will have a "frame" window around
3290  * widget->window, accessible in window->frame. Using the signal 
3291  * frame_event you can recieve all events targeted at the frame.
3292  * 
3293  * This function is used by the linux-fb port to implement managed
3294  * windows, but it could concievably be used by X-programs that
3295  * want to do their own window decorations.
3296  **/
3297 void
3298 gtk_window_set_has_frame (GtkWindow *window, 
3299                           gboolean   setting)
3300 {
3301   g_return_if_fail (window != NULL);
3302   g_return_if_fail (GTK_IS_WINDOW (window));
3303   g_return_if_fail (!GTK_WIDGET_REALIZED (window));
3304
3305   window->has_frame = setting != FALSE;
3306 }
3307
3308 /**
3309  * gtk_window_get_has_frame:
3310  * @window: a #GtkWindow
3311  * 
3312  * Returns whether the window has a frame window exterior to
3313  * widget->window. See gtk_window_set_has_frame ().
3314  *
3315  * Return value: %TRUE if a frame has been added to the window
3316  *   via gtk_widow_has_frame
3317  **/
3318 gboolean
3319 gtk_window_get_has_frame (GtkWindow *window)
3320 {
3321   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
3322
3323   return window->has_frame;
3324 }
3325
3326 /**
3327  * gtk_window_set_frame_dimensions:
3328  * @window: a #GtkWindow that has a frame
3329  * @left: The width of the left border
3330  * @top: The height of the top border
3331  * @right: The width of the right border
3332  * @bottom: The height of the bottom border
3333  *
3334  * For windows with frames (see #gtk_window_set_has_frame) this function
3335  * can be used to change the size of the frame border.
3336  **/
3337 void
3338 gtk_window_set_frame_dimensions (GtkWindow *window, 
3339                                  gint       left,
3340                                  gint       top,
3341                                  gint       right,
3342                                  gint       bottom)
3343 {
3344   GtkWidget *widget = GTK_WIDGET (window);
3345
3346   g_return_if_fail (window != NULL);
3347   g_return_if_fail (GTK_IS_WINDOW (window));
3348
3349   if (window->frame_left == left &&
3350       window->frame_top == top &&
3351       window->frame_right == right && 
3352       window->frame_bottom == bottom)
3353     return;
3354
3355   window->frame_left = left;
3356   window->frame_top = top;
3357   window->frame_right = right;
3358   window->frame_bottom = bottom;
3359
3360   if (GTK_WIDGET_REALIZED (widget) && window->frame)
3361     {
3362       gint width = widget->allocation.width + left + right;
3363       gint height = widget->allocation.height + top + bottom;
3364       gdk_window_resize (window->frame, width, height);
3365       gtk_decorated_window_move_resize_window (window,
3366                                                left, top,
3367                                                widget->allocation.width,
3368                                                widget->allocation.height);
3369     }
3370 }
3371
3372 /**
3373  * gtk_window_present:
3374  * @window: a #GtkWindow
3375  *
3376  * Presents a window to the user. This may mean raising the window
3377  * in the stacking order, deiconifying it, moving it to the current
3378  * desktop, and/or giving it the keyboard focus, possibly dependent
3379  * on the user's platform, window manager, and preferences.
3380  *
3381  * If @window is hidden, this function calls gtk_widget_show()
3382  * as well.
3383  * 
3384  * This function should be used when the user tries to open a window
3385  * that's already open. Say for example the preferences dialog is
3386  * currently open, and the user chooses Preferences from the menu
3387  * a second time; use gtk_window_present() to move the already-open dialog
3388  * where the user can see it.
3389  * 
3390  **/
3391 void
3392 gtk_window_present (GtkWindow *window)
3393 {
3394   GtkWidget *widget;
3395
3396   g_return_if_fail (GTK_IS_WINDOW (window));
3397
3398   widget = GTK_WIDGET (window);
3399
3400   if (GTK_WIDGET_VISIBLE (window))
3401     {
3402       g_assert (widget->window != NULL);
3403       
3404       gdk_window_show (widget->window);
3405
3406       /* note that gdk_window_focus() will also move the window to
3407        * the current desktop, for WM spec compliant window managers.
3408        */
3409       gdk_window_focus (widget->window,
3410                         gtk_get_current_event_time ());
3411     }
3412   else
3413     {
3414       gtk_widget_show (widget);
3415     }
3416 }
3417
3418 /**
3419  * gtk_window_iconify:
3420  * @window: a #GtkWindow
3421  *
3422  * Asks to iconify @window. Note that you shouldn't assume the window
3423  * is definitely iconified afterward, because other entities (e.g. the
3424  * user or window manager) could deiconify it again, or there may not
3425  * be a window manager in which case iconification isn't possible,
3426  * etc. But normally the window will end up iconified. Just don't write
3427  * code that crashes if not.
3428  *
3429  * It's permitted to call this function before showing a window,
3430  * in which case the window will be iconified before it ever appears
3431  * onscreen.
3432  *
3433  * You can track iconification via the "window_state_event" signal
3434  * on #GtkWidget.
3435  * 
3436  **/
3437 void
3438 gtk_window_iconify (GtkWindow *window)
3439 {
3440   GtkWidget *widget;
3441   GdkWindow *toplevel;
3442   
3443   g_return_if_fail (GTK_IS_WINDOW (window));
3444
3445   widget = GTK_WIDGET (window);
3446
3447   window->iconify_initially = TRUE;
3448
3449   if (window->frame)
3450     toplevel = window->frame;
3451   else
3452     toplevel = widget->window;
3453   
3454   if (toplevel != NULL)
3455     gdk_window_iconify (toplevel);
3456 }
3457
3458 /**
3459  * gtk_window_deiconify:
3460  * @window: a #GtkWindow
3461  *
3462  * Asks to deiconify @window. Note that you shouldn't assume the
3463  * window is definitely deiconified afterward, because other entities
3464  * (e.g. the user or window manager) could iconify it again before
3465  * your code which assumes deiconification gets to run.
3466  *
3467  * You can track iconification via the "window_state_event" signal
3468  * on #GtkWidget.
3469  **/
3470 void
3471 gtk_window_deiconify (GtkWindow *window)
3472 {
3473   GtkWidget *widget;
3474   GdkWindow *toplevel;
3475   
3476   g_return_if_fail (GTK_IS_WINDOW (window));
3477
3478   widget = GTK_WIDGET (window);
3479
3480   window->iconify_initially = FALSE;
3481
3482   if (window->frame)
3483     toplevel = window->frame;
3484   else
3485     toplevel = widget->window;
3486   
3487   if (toplevel != NULL)
3488     gdk_window_deiconify (toplevel);
3489 }
3490
3491 /**
3492  * gtk_window_stick:
3493  * @window: a #GtkWindow
3494  *
3495  * Asks to stick @window, which means that it will appear on all user
3496  * desktops. Note that you shouldn't assume the window is definitely
3497  * stuck afterward, because other entities (e.g. the user or window
3498  * manager) could unstick it again, and some window managers do not
3499  * support sticking windows. But normally the window will end up
3500  * stuck. Just don't write code that crashes if not.
3501  *
3502  * It's permitted to call this function before showing a window.
3503  *
3504  * You can track stickiness via the "window_state_event" signal
3505  * on #GtkWidget.
3506  * 
3507  **/
3508 void
3509 gtk_window_stick (GtkWindow *window)
3510 {
3511   GtkWidget *widget;
3512   GdkWindow *toplevel;
3513   
3514   g_return_if_fail (GTK_IS_WINDOW (window));
3515
3516   widget = GTK_WIDGET (window);
3517
3518   window->stick_initially = TRUE;
3519
3520   if (window->frame)
3521     toplevel = window->frame;
3522   else
3523     toplevel = widget->window;
3524   
3525   if (toplevel != NULL)
3526     gdk_window_stick (toplevel);
3527 }
3528
3529 /**
3530  * gtk_window_unstick:
3531  * @window: a #GtkWindow
3532  *
3533  * Asks to unstick @window, which means that it will appear on only
3534  * one of the user's desktops. Note that you shouldn't assume the
3535  * window is definitely unstuck afterward, because other entities
3536  * (e.g. the user or window manager) could stick it again. But
3537  * normally the window will end up stuck. Just don't write code that
3538  * crashes if not.
3539  *
3540  * You can track stickiness via the "window_state_event" signal
3541  * on #GtkWidget.
3542  * 
3543  **/
3544 void
3545 gtk_window_unstick (GtkWindow *window)
3546 {
3547   GtkWidget *widget;
3548   GdkWindow *toplevel;
3549   
3550   g_return_if_fail (GTK_IS_WINDOW (window));
3551
3552   widget = GTK_WIDGET (window);
3553
3554   window->stick_initially = FALSE;
3555
3556   if (window->frame)
3557     toplevel = window->frame;
3558   else
3559     toplevel = widget->window;
3560   
3561   if (toplevel != NULL)
3562     gdk_window_unstick (toplevel);
3563 }
3564
3565 /**
3566  * gtk_window_maximize:
3567  * @window: a #GtkWindow
3568  *
3569  * Asks to maximize @window, so that it becomes full-screen. Note that
3570  * you shouldn't assume the window is definitely maximized afterward,
3571  * because other entities (e.g. the user or window manager) could
3572  * unmaximize it again, and not all window managers support
3573  * maximization. But normally the window will end up maximized. Just
3574  * don't write code that crashes if not.
3575  *
3576  * It's permitted to call this function before showing a window,
3577  * in which case the window will be maximized when it appears onscreen
3578  * initially.
3579  *
3580  * You can track maximization via the "window_state_event" signal
3581  * on #GtkWidget.
3582  * 
3583  **/
3584 void
3585 gtk_window_maximize (GtkWindow *window)
3586 {
3587   GtkWidget *widget;
3588   GdkWindow *toplevel;
3589   
3590   g_return_if_fail (GTK_IS_WINDOW (window));
3591
3592   widget = GTK_WIDGET (window);
3593
3594   window->maximize_initially = TRUE;
3595
3596   if (window->frame)
3597     toplevel = window->frame;
3598   else
3599     toplevel = widget->window;
3600   
3601   if (toplevel != NULL)
3602     gdk_window_maximize (toplevel);
3603 }
3604
3605 /**
3606  * gtk_window_unmaximize:
3607  * @window: a #GtkWindow
3608  *
3609  * Asks to unmaximize @window. Note that you shouldn't assume the
3610  * window is definitely unmaximized afterward, because other entities
3611  * (e.g. the user or window manager) could maximize it again, and not
3612  * all window managers honor requests to unmaximize. But normally the
3613  * window will end up unmaximized. Just don't write code that crashes
3614  * if not.
3615  *
3616  * You can track maximization via the "window_state_event" signal
3617  * on #GtkWidget.
3618  * 
3619  **/
3620 void
3621 gtk_window_unmaximize (GtkWindow *window)
3622 {
3623   GtkWidget *widget;
3624   GdkWindow *toplevel;
3625   
3626   g_return_if_fail (GTK_IS_WINDOW (window));
3627
3628   widget = GTK_WIDGET (window);
3629
3630   window->maximize_initially = FALSE;
3631
3632   if (window->frame)
3633     toplevel = window->frame;
3634   else
3635     toplevel = widget->window;
3636   
3637   if (toplevel != NULL)
3638     gdk_window_unmaximize (toplevel);
3639 }
3640
3641 /**
3642  * gtk_window_set_resizable:
3643  * @window: a #GtkWindow
3644  * @resizable: %TRUE if the user can resize this window
3645  *
3646  * Sets whether the user can resize a window. Windows are user resizable
3647  * by default.
3648  **/
3649 void
3650 gtk_window_set_resizable (GtkWindow *window,
3651                           gboolean   resizable)
3652 {
3653   g_return_if_fail (GTK_IS_WINDOW (window));
3654
3655   gtk_window_set_policy (window, FALSE, resizable, FALSE);
3656 }
3657
3658 /**
3659  * gtk_window_get_resizable:
3660  * @window: a #GtkWindow
3661  *
3662  * Gets the value set by gtk_window_set_resizable().
3663  *
3664  * Return value: %TRUE if the user can resize the window
3665  **/
3666 gboolean
3667 gtk_window_get_resizable (GtkWindow *window)
3668 {
3669   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
3670
3671   /* allow_grow is most likely to indicate the semantic concept we
3672    * mean by "resizable" (and will be a reliable indicator if
3673    * set_policy() hasn't been called)
3674    */
3675   return window->allow_grow;
3676 }
3677
3678 /**
3679  * gtk_window_set_gravity:
3680  * @window: a #GtkWindow
3681  * @gravity: window gravity
3682  *
3683  * Window gravity defines the "reference point" to be used when
3684  * positioning or resizing a window. Calls to
3685  * gtk_widget_set_uposition() will position a different point on the
3686  * window depending on the window gravity. When the window changes size
3687  * the reference point determined by the window's gravity will stay in
3688  * a fixed location.
3689  *
3690  * See #GdkGravity for full details. To briefly summarize,
3691  * #GDK_GRAVITY_NORTH_WEST means that the reference point is the
3692  * northwest (top left) corner of the window
3693  * frame. #GDK_GRAVITY_SOUTH_EAST would be the bottom right corner of
3694  * the frame, and so on. If you want to position the window contents,
3695  * rather than the window manager's frame, #GDK_GRAVITY_STATIC moves
3696  * the reference point to the northwest corner of the #GtkWindow
3697  * itself.
3698  *
3699  * The default window gravity is #GDK_GRAVITY_NORTH_WEST.
3700  *
3701  **/
3702 void
3703 gtk_window_set_gravity (GtkWindow *window,
3704                         GdkGravity gravity)
3705 {
3706   g_return_if_fail (GTK_IS_WINDOW (window));
3707
3708   if (gravity != window->gravity)
3709     {
3710       window->gravity = gravity;
3711
3712       /* gtk_window_move_resize() will adapt gravity
3713        */
3714       gtk_widget_queue_resize (GTK_WIDGET (window));
3715     }
3716 }
3717
3718 /**
3719  * gtk_window_get_gravity:
3720  * @window: a #GtkWindow
3721  *
3722  * Gets the value set by gtk_window_set_gravity().
3723  *
3724  * Return value: window gravity
3725  **/
3726 GdkGravity
3727 gtk_window_get_gravity (GtkWindow *window)
3728 {
3729   g_return_val_if_fail (GTK_IS_WINDOW (window), 0);
3730
3731   return window->gravity;
3732 }
3733
3734 /**
3735  * gtk_window_begin_resize_drag:
3736  * @window: a #GtkWindow
3737  * @button: mouse button that initiated the drag
3738  * @edge: position of the resize control
3739  * @root_x: X position where the user clicked to initiate the drag, in root window coordinates
3740  * @root_y: Y position where the user clicked to initiate the drag
3741  * @timestamp: timestamp from the click event that initiated the drag
3742  *
3743  * Starts resizing a window. This function is used if an application
3744  * has window resizing controls. When GDK can support it, the resize
3745  * will be done using the standard mechanism for the window manager or
3746  * windowing system. Otherwise, GDK will try to emulate window
3747  * resizing, potentially not all that well, depending on the windowing system.
3748  * 
3749  **/
3750 void
3751 gtk_window_begin_resize_drag  (GtkWindow    *window,
3752                                GdkWindowEdge edge,
3753                                gint          button,
3754                                gint          root_x,
3755                                gint          root_y,
3756                                guint32       timestamp)
3757 {
3758   GtkWidget *widget;
3759   GdkWindow *toplevel;
3760   
3761   g_return_if_fail (GTK_IS_WINDOW (window));
3762   g_return_if_fail (GTK_WIDGET_VISIBLE (window));
3763   
3764   widget = GTK_WIDGET (window);
3765   
3766   if (window->frame)
3767     toplevel = window->frame;
3768   else
3769     toplevel = widget->window;
3770   
3771   gdk_window_begin_resize_drag (toplevel,
3772                                 edge, button,
3773                                 root_x, root_y,
3774                                 timestamp);
3775 }
3776
3777 /**
3778  * gtk_window_get_frame_dimensions:
3779  * @window: a #GtkWindow
3780  * @left: location to store the width of the frame at the left, or %NULL
3781  * @top: location to store the height of the frame at the top, or %NULL
3782  * @right: location to store the width of the frame at the returns, or %NULL
3783  * @bottom: location to store the height of the frame at the bottom, or %NULL
3784  *
3785  * Retrieves the dimensions of the frame window for this toplevel.
3786  * See gtk_window_set_has_frame(), gtk_window_set_frame_dimensions().
3787  **/
3788 void
3789 gtk_window_get_frame_dimensions (GtkWindow *window,
3790                                  gint      *left,
3791                                  gint      *top,
3792                                  gint      *right,
3793                                  gint      *bottom)
3794 {
3795   g_return_if_fail (GTK_IS_WINDOW (window));
3796
3797   if (left)
3798     *left = window->frame_left;
3799   if (top)
3800     *top = window->frame_top;
3801   if (right)
3802     *top = window->frame_right;
3803   if (bottom)
3804     *top = window->frame_bottom;
3805 }
3806
3807 /**
3808  * gtk_window_begin_move_drag:
3809  * @window: a #GtkWindow
3810  * @button: mouse button that initiated the drag
3811  * @root_x: X position where the user clicked to initiate the drag, in root window coordinates
3812  * @root_y: Y position where the user clicked to initiate the drag
3813  * @timestamp: timestamp from the click event that initiated the drag
3814  *
3815  * Starts moving a window. This function is used if an application
3816  * has window movement grips. When GDK can support it, the window movement
3817  * will be done using the standard mechanism for the window manager or
3818  * windowing system. Otherwise, GDK will try to emulate window
3819  * movement, potentially not all that well, depending on the windowing system.
3820  * 
3821  **/
3822 void
3823 gtk_window_begin_move_drag  (GtkWindow *window,
3824                              gint       button,
3825                              gint       root_x,
3826                              gint       root_y,
3827                              guint32    timestamp)
3828 {
3829   GtkWidget *widget;
3830   GdkWindow *toplevel;
3831   
3832   g_return_if_fail (GTK_IS_WINDOW (window));
3833   g_return_if_fail (GTK_WIDGET_VISIBLE (window));
3834   
3835   widget = GTK_WIDGET (window);
3836   
3837   if (window->frame)
3838     toplevel = window->frame;
3839   else
3840     toplevel = widget->window;
3841   
3842   gdk_window_begin_move_drag (toplevel,
3843                               button,
3844                               root_x, root_y,
3845                               timestamp);
3846 }
3847
3848
3849 static void
3850 gtk_window_group_class_init (GtkWindowGroupClass *klass)
3851 {
3852 }
3853
3854 GtkType
3855 gtk_window_group_get_type (void)
3856 {
3857   static GtkType window_group_type = 0;
3858
3859   if (!window_group_type)
3860     {
3861       static const GTypeInfo window_group_info =
3862       {
3863         sizeof (GtkWindowGroupClass),
3864         NULL,           /* base_init */
3865         NULL,           /* base_finalize */
3866         (GClassInitFunc) gtk_window_group_class_init,
3867         NULL,           /* class_finalize */
3868         NULL,           /* class_data */
3869         sizeof (GtkWindowGroup),
3870         16,             /* n_preallocs */
3871         (GInstanceInitFunc) NULL,
3872       };
3873
3874       window_group_type = g_type_register_static (G_TYPE_OBJECT, "GtkWindowGroup", &window_group_info, 0);
3875     }
3876
3877   return window_group_type;
3878 }
3879
3880 /**
3881  * gtk_window_group_new:
3882  * 
3883  * Create a new #GtkWindowGroup object. Grabs added with
3884  * gtk_window_grab_add() only affect windows within the
3885  * same #GtkWindowGroup
3886  * 
3887  * Return value: 
3888  **/
3889 GtkWindowGroup *
3890 gtk_window_group_new (void)
3891 {
3892   return g_object_new (GTK_TYPE_WINDOW_GROUP, NULL);
3893 }
3894
3895 static void
3896 window_group_cleanup_grabs (GtkWindowGroup *group,
3897                             GtkWindow      *window)
3898 {
3899   GSList *tmp_list;
3900   GSList *to_remove = NULL;
3901
3902   tmp_list = group->grabs;
3903   while (tmp_list)
3904     {
3905       if (gtk_widget_get_toplevel (tmp_list->data) == (GtkWidget*) window)
3906         to_remove = g_slist_prepend (to_remove, g_object_ref (tmp_list->data));
3907       tmp_list = tmp_list->next;
3908     }
3909
3910   while (to_remove)
3911     {
3912       gtk_grab_remove (to_remove->data);
3913       g_object_unref (to_remove->data);
3914       to_remove = g_slist_delete_link (to_remove, to_remove);
3915     }
3916 }
3917
3918 /**
3919  * gtk_window_group_add_widget:
3920  * @window_group: a #GtkWindowGroup
3921  * @window: the #GtkWindow to add
3922  * 
3923  * Add a window to a #GtkWindowGroup. 
3924  **/
3925 void
3926 gtk_window_group_add_window (GtkWindowGroup *window_group,
3927                              GtkWindow      *window)
3928 {
3929   g_return_if_fail (GTK_IS_WINDOW_GROUP (window_group));
3930   g_return_if_fail (GTK_IS_WINDOW (window));
3931
3932   if (window->group != window_group)
3933     {
3934       g_object_ref (window);
3935       g_object_ref (window_group);
3936       
3937       if (window->group)
3938         gtk_window_group_remove_window (window->group, window);
3939       else
3940         window_group_cleanup_grabs (_gtk_window_get_group (NULL), window);
3941
3942       window->group = window_group;
3943
3944       g_object_unref (window);
3945     }
3946 }
3947
3948 /**
3949  * gtk_window_group_remove_window:
3950  * @window_group: a #GtkWindowGroup
3951  * @window: the #GtkWindow to remove
3952  * 
3953  * Removes a window from a #GtkWindowGroup.
3954  **/
3955 void
3956 gtk_window_group_remove_window (GtkWindowGroup *window_group,
3957                                 GtkWindow      *window)
3958 {
3959   g_return_if_fail (GTK_IS_WINDOW_GROUP (window_group));
3960   g_return_if_fail (GTK_IS_WIDGET (window));
3961   g_return_if_fail (window->group == window_group);
3962
3963   g_object_ref (window);
3964
3965   window_group_cleanup_grabs (window_group, window);
3966   window->group = NULL;
3967   
3968   g_object_unref (G_OBJECT (window_group));
3969   g_object_unref (window);
3970 }
3971
3972 /* Return the group for the window or the default group
3973  */
3974 GtkWindowGroup *
3975 _gtk_window_get_group (GtkWindow *window)
3976 {
3977   if (window && window->group)
3978     return window->group;
3979   else
3980     {
3981       static GtkWindowGroup *default_group = NULL;
3982
3983       if (!default_group)
3984         default_group = gtk_window_group_new ();
3985
3986       return default_group;
3987     }
3988 }