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