]> Pileus Git - ~andy/gtk/blob - gtk/gtkwindow.c
add signals and binding set, so keybindings are configurable
[~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              (GtkContainer     *container,
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   
305   widget_class->expose_event = gtk_window_expose;
306    
307   container_class->check_resize = gtk_window_check_resize;
308   container_class->focus = gtk_window_focus;
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_set_wmclass:
745  * @window: a #GtkWindow
746  * @wmclass_name: window name hint
747  * @wmclass_class: window class hint
748  *
749  * Don't use this function. It sets the X Window System "class" and
750  * "name" hints for a window.  According to the ICCCM, you should
751  * always set these to the same value for all windows in an
752  * application, and GTK sets them to that value by default, so calling
753  * this function is sort of pointless. However, you may want to call
754  * gtk_window_set_role() on each window in your application, for the
755  * benefit of the session manager. Setting the role allows the window
756  * manager to restore window positions when loading a saved session.
757  * 
758  **/
759 void
760 gtk_window_set_wmclass (GtkWindow *window,
761                         const gchar *wmclass_name,
762                         const gchar *wmclass_class)
763 {
764   g_return_if_fail (window != NULL);
765   g_return_if_fail (GTK_IS_WINDOW (window));
766
767   g_free (window->wmclass_name);
768   window->wmclass_name = g_strdup (wmclass_name);
769
770   g_free (window->wmclass_class);
771   window->wmclass_class = g_strdup (wmclass_class);
772
773   if (GTK_WIDGET_REALIZED (window))
774     g_warning ("gtk_window_set_wmclass: shouldn't set wmclass after window is realized!\n");
775 }
776
777 /**
778  * gtk_window_set_role:
779  * @window: a #GtkWindow
780  * @role: unique identifier for the window to be used when restoring a session
781  *
782  * In combination with the window title, the window role allows a
783  * window manager to identify "the same" window when an application is
784  * restarted. So for example you might set the "toolbox" role on your
785  * app's toolbox window, so that when the user restarts their session,
786  * the window manager can put the toolbox back in the same place.
787  *
788  * If a window already has a unique title, you don't need to set the
789  * role, since the WM can use the title to identify the window when
790  * restoring the session.
791  * 
792  **/
793 void
794 gtk_window_set_role (GtkWindow   *window,
795                      const gchar *role)
796 {
797   g_return_if_fail (GTK_IS_WINDOW (window));
798
799   if (role == window->wm_role)
800     return;
801   
802   g_free (window->wm_role);
803   window->wm_role = g_strdup (role);
804   
805   if (GTK_WIDGET_REALIZED (window))
806     g_warning ("gtk_window_set_role(): shouldn't set role after window is realized!\n");
807 }
808
809 /**
810  * gtk_window_set_focus:
811  * @window: a #GtkWindow
812  * @focus: widget to be the new focus widget
813  *
814  * If @focus is not the current focus widget, and is focusable, emits
815  * the "set_focus" signal to set @focus as the focus widget for the
816  * window.  This function is more or less GTK-internal; to focus an
817  * entry widget or the like, you should use gtk_widget_grab_focus()
818  * instead of this function.
819  * 
820  **/
821 void
822 gtk_window_set_focus (GtkWindow *window,
823                       GtkWidget *focus)
824 {
825   g_return_if_fail (window != NULL);
826   g_return_if_fail (GTK_IS_WINDOW (window));
827   if (focus)
828     {
829       g_return_if_fail (GTK_IS_WIDGET (focus));
830       g_return_if_fail (GTK_WIDGET_CAN_FOCUS (focus));
831     }
832
833   if ((window->focus_widget != focus) ||
834       (focus && !GTK_WIDGET_HAS_FOCUS (focus)))
835     gtk_signal_emit (GTK_OBJECT (window), window_signals[SET_FOCUS], focus);
836 }
837
838 /**
839  * gtk_window_set_default:
840  * @window: a #GtkWindow
841  * @default_widget: widget to be the default
842  *
843  * The default widget is the widget that's activated when the user
844  * presses Enter in a dialog (for example). This function tells a
845  * #GtkWindow about the current default widget; it's really a GTK
846  * internal function and you shouldn't need it. Instead, to change the
847  * default widget, first set the #GTK_CAN_DEFAULT flag on the widget
848  * you'd like to make the default using GTK_WIDGET_SET_FLAGS(), then
849  * call gtk_widget_grab_default() to move the default.
850  * 
851  **/
852 void
853 gtk_window_set_default (GtkWindow *window,
854                         GtkWidget *default_widget)
855 {
856   g_return_if_fail (window != NULL);
857   g_return_if_fail (GTK_IS_WINDOW (window));
858
859   if (default_widget)
860     g_return_if_fail (GTK_WIDGET_CAN_DEFAULT (default_widget));
861
862   if (window->default_widget != default_widget)
863     {
864       if (window->default_widget)
865         {
866           if (window->focus_widget != window->default_widget ||
867               !GTK_WIDGET_RECEIVES_DEFAULT (window->default_widget))
868             GTK_WIDGET_UNSET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
869           gtk_widget_queue_draw (window->default_widget);
870         }
871
872       window->default_widget = default_widget;
873
874       if (window->default_widget)
875         {
876           if (window->focus_widget == NULL ||
877               !GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget))
878             GTK_WIDGET_SET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
879           gtk_widget_queue_draw (window->default_widget);
880         }
881     }
882 }
883
884 void
885 gtk_window_set_policy (GtkWindow *window,
886                        gboolean   allow_shrink,
887                        gboolean   allow_grow,
888                        gboolean   auto_shrink)
889 {
890   g_return_if_fail (window != NULL);
891   g_return_if_fail (GTK_IS_WINDOW (window));
892
893   window->allow_shrink = (allow_shrink != FALSE);
894   window->allow_grow = (allow_grow != FALSE);
895   window->auto_shrink = (auto_shrink != FALSE);
896
897   g_object_notify (G_OBJECT (window), "allow_shrink");
898   g_object_notify (G_OBJECT (window), "allow_grow");
899   g_object_notify (G_OBJECT (window), "auto_shrink");
900   
901   gtk_widget_queue_resize (GTK_WIDGET (window));
902 }
903
904 void
905 gtk_window_add_accel_group (GtkWindow        *window,
906                             GtkAccelGroup    *accel_group)
907 {
908   g_return_if_fail (window != NULL);
909   g_return_if_fail (GTK_IS_WINDOW (window));
910   g_return_if_fail (accel_group != NULL);
911
912   gtk_accel_group_attach (accel_group, GTK_OBJECT (window));
913 }
914
915 void
916 gtk_window_remove_accel_group (GtkWindow       *window,
917                                GtkAccelGroup   *accel_group)
918 {
919   g_return_if_fail (window != NULL);
920   g_return_if_fail (GTK_IS_WINDOW (window));
921   g_return_if_fail (accel_group != NULL);
922
923   gtk_accel_group_detach (accel_group, GTK_OBJECT (window));
924 }
925
926 void
927 gtk_window_add_mnemonic (GtkWindow *window,
928                          guint      keyval,
929                          GtkWidget *target)
930 {
931   GtkWindowMnemonic key;
932   GtkWindowMnemonic *mnemonic;
933
934   g_return_if_fail (GTK_IS_WINDOW (window));
935   g_return_if_fail (GTK_IS_WIDGET (target));
936   
937   key.window = window;
938   key.keyval = keyval;
939   mnemonic = g_hash_table_lookup (mnemonic_hash_table, &key);
940
941   if (mnemonic)
942     {
943       g_return_if_fail (g_slist_find (mnemonic->targets, target) == NULL);
944       mnemonic->targets = g_slist_prepend (mnemonic->targets, target);
945     }
946   else
947     {
948       mnemonic = g_new (GtkWindowMnemonic, 1);
949       *mnemonic = key;
950       mnemonic->targets = g_slist_prepend (NULL, target);
951       g_hash_table_insert (mnemonic_hash_table, mnemonic, mnemonic);
952     }
953 }
954
955 void
956 gtk_window_remove_mnemonic (GtkWindow *window,
957                             guint      keyval,
958                             GtkWidget *target)
959 {
960   GtkWindowMnemonic key;
961   GtkWindowMnemonic *mnemonic;
962
963   g_return_if_fail (GTK_IS_WINDOW (window));
964   g_return_if_fail (GTK_IS_WIDGET (target));
965   
966   key.window = window;
967   key.keyval = keyval;
968   mnemonic = g_hash_table_lookup (mnemonic_hash_table, &key);
969
970   g_return_if_fail (mnemonic && g_slist_find (mnemonic->targets, target) != NULL);
971
972   mnemonic->targets = g_slist_remove (mnemonic->targets, target);
973   if (mnemonic->targets == NULL)
974     {
975       g_hash_table_remove (mnemonic_hash_table, mnemonic);
976       g_free (mnemonic);
977     }
978 }
979
980 gboolean
981 gtk_window_mnemonic_activate (GtkWindow      *window,
982                               guint           keyval,
983                               GdkModifierType modifier)
984 {
985   GtkWindowMnemonic key;
986   GtkWindowMnemonic *mnemonic;
987   GSList *list;
988   GtkWidget *widget, *chosen_widget;
989   gboolean overloaded;
990
991   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
992
993   if (window->mnemonic_modifier != (modifier & gtk_accelerator_get_default_mod_mask ()))
994     return FALSE;
995   
996   key.window = window;
997   key.keyval = keyval;
998   mnemonic = g_hash_table_lookup (mnemonic_hash_table, &key);
999
1000   if (!mnemonic)
1001     return FALSE;
1002   
1003   overloaded = FALSE;
1004   chosen_widget = NULL;
1005   list = mnemonic->targets;
1006   while (list)
1007     {
1008       widget = GTK_WIDGET (list->data);
1009       
1010       if (GTK_WIDGET_IS_SENSITIVE (widget) &&
1011           GTK_WIDGET_MAPPED (widget))
1012         {
1013           if (chosen_widget)
1014             {
1015               overloaded = TRUE;
1016               break;
1017             }
1018           else
1019             chosen_widget = widget;
1020         }
1021       list = g_slist_next (list);
1022     }
1023
1024   if (chosen_widget)
1025     {
1026       /* For round robin we put the activated entry on
1027        * the end of the list after activation
1028        */
1029       mnemonic->targets = g_slist_remove (mnemonic->targets, chosen_widget);
1030       mnemonic->targets = g_slist_append (mnemonic->targets, chosen_widget);
1031
1032       return gtk_widget_mnemonic_activate (chosen_widget, overloaded);
1033     }
1034   return FALSE;
1035 }
1036
1037 void
1038 gtk_window_set_mnemonic_modifier (GtkWindow      *window,
1039                                   GdkModifierType modifier)
1040 {
1041   g_return_if_fail (GTK_IS_WINDOW (window));
1042   g_return_if_fail ((modifier & ~GDK_MODIFIER_MASK) == 0);
1043
1044   window->mnemonic_modifier = modifier;
1045 }
1046
1047 void
1048 gtk_window_set_position (GtkWindow         *window,
1049                          GtkWindowPosition  position)
1050 {
1051   g_return_if_fail (GTK_IS_WINDOW (window));
1052
1053   window->position = position;
1054
1055   g_object_notify (G_OBJECT (window), "window_position");
1056 }
1057
1058 gboolean 
1059 gtk_window_activate_focus (GtkWindow *window)
1060 {
1061   g_return_val_if_fail (window != NULL, FALSE);
1062   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
1063
1064   if (window->focus_widget)
1065     {
1066       if (GTK_WIDGET_IS_SENSITIVE (window->focus_widget))
1067         gtk_widget_activate (window->focus_widget);
1068       return TRUE;
1069     }
1070
1071   return FALSE;
1072 }
1073
1074 gboolean
1075 gtk_window_activate_default (GtkWindow *window)
1076 {
1077   g_return_val_if_fail (window != NULL, FALSE);
1078   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
1079
1080   if (window->default_widget && GTK_WIDGET_IS_SENSITIVE (window->default_widget) &&
1081       (!window->focus_widget || !GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget)))
1082     {
1083       gtk_widget_activate (window->default_widget);
1084       return TRUE;
1085     }
1086   else if (window->focus_widget)
1087     {
1088       if (GTK_WIDGET_IS_SENSITIVE (window->focus_widget))
1089         gtk_widget_activate (window->focus_widget);
1090       return TRUE;
1091     }
1092
1093   return FALSE;
1094 }
1095
1096 /**
1097  * gtk_window_set_modal:
1098  * @window: a #GtkWindow
1099  * @modal: whether the window is modal
1100  * 
1101  * Sets a window modal or non-modal. Modal windows prevent interaction
1102  * with other windows in the same application. To keep modal dialogs
1103  * on top of main application windows, use
1104  * gtk_window_set_transient_for() to make the dialog transient for the
1105  * parent; most window managers will then disallow lowering the dialog
1106  * below the parent.
1107  * 
1108  * 
1109  **/
1110 void
1111 gtk_window_set_modal (GtkWindow *window,
1112                       gboolean   modal)
1113 {
1114   g_return_if_fail (window != NULL);
1115   g_return_if_fail (GTK_IS_WINDOW (window));
1116
1117   window->modal = modal != FALSE;
1118   
1119   /* adjust desired modality state */
1120   if (GTK_WIDGET_VISIBLE (window) && window->modal)
1121     gtk_grab_add (GTK_WIDGET (window));
1122   else
1123     gtk_grab_remove (GTK_WIDGET (window));
1124
1125   g_object_notify (G_OBJECT (window), "modal");
1126 }
1127
1128 /**
1129  * gtk_window_list_toplevels:
1130  * 
1131  * Returns a list of all existing toplevel windows. The widgets
1132  * in the list are not individually referenced. If you want
1133  * to iterate through the list and perform actions involving
1134  * callbacks that might destroy the widgets, you MUST call
1135  * g_list_foreach (result, (GFunc)g_object_ref, NULL) first, and
1136  * then unref all the widgets afterwards.
1137  * 
1138  * Return value: list of toplevel widgets
1139  **/
1140 GList*
1141 gtk_window_list_toplevels (void)
1142 {
1143   GList *list = NULL;
1144   GSList *slist;
1145
1146   for (slist = toplevel_list; slist; slist = slist->next)
1147     list = g_list_prepend (list, slist->data);
1148
1149   return list;
1150 }
1151
1152 void
1153 gtk_window_add_embedded_xid (GtkWindow *window, guint xid)
1154 {
1155   GList *embedded_windows;
1156
1157   g_return_if_fail (window != NULL);
1158   g_return_if_fail (GTK_IS_WINDOW (window));
1159
1160   embedded_windows = gtk_object_get_data (GTK_OBJECT (window), "gtk-embedded");
1161   if (embedded_windows)
1162     gtk_object_remove_no_notify_by_id (GTK_OBJECT (window), 
1163                                        g_quark_from_static_string ("gtk-embedded"));
1164   embedded_windows = g_list_prepend (embedded_windows,
1165                                      GUINT_TO_POINTER (xid));
1166
1167   gtk_object_set_data_full (GTK_OBJECT (window), "gtk-embedded", 
1168                             embedded_windows,
1169                             embedded_windows ?
1170                               (GtkDestroyNotify) g_list_free : NULL);
1171 }
1172
1173 void
1174 gtk_window_remove_embedded_xid (GtkWindow *window, guint xid)
1175 {
1176   GList *embedded_windows;
1177   GList *node;
1178
1179   g_return_if_fail (window != NULL);
1180   g_return_if_fail (GTK_IS_WINDOW (window));
1181   
1182   embedded_windows = gtk_object_get_data (GTK_OBJECT (window), "gtk-embedded");
1183   if (embedded_windows)
1184     gtk_object_remove_no_notify_by_id (GTK_OBJECT (window), 
1185                                        g_quark_from_static_string ("gtk-embedded"));
1186
1187   node = g_list_find (embedded_windows, GUINT_TO_POINTER (xid));
1188   if (node)
1189     {
1190       embedded_windows = g_list_remove_link (embedded_windows, node);
1191       g_list_free_1 (node);
1192     }
1193   
1194   gtk_object_set_data_full (GTK_OBJECT (window), 
1195                             "gtk-embedded", embedded_windows,
1196                             embedded_windows ?
1197                               (GtkDestroyNotify) g_list_free : NULL);
1198 }
1199
1200 void       
1201 _gtk_window_reposition (GtkWindow *window,
1202                         gint       x,
1203                         gint       y)
1204 {
1205   GtkWindowGeometryInfo *info;
1206   
1207   g_return_if_fail (window != NULL);
1208   g_return_if_fail (GTK_IS_WINDOW (window));
1209
1210   /* keep this in sync with gtk_window_compute_reposition()
1211    */
1212   if (GTK_WIDGET_REALIZED (window))
1213     {
1214       info = gtk_window_get_geometry_info (window, TRUE);
1215
1216       if (!(info->last.flags & GDK_HINT_POS))
1217         {
1218           info->last.flags |= GDK_HINT_POS;
1219           gdk_window_set_geometry_hints (GTK_WIDGET (window)->window,
1220                                          &info->last.geometry,
1221                                          info->last.flags);
1222         }
1223
1224       if (window->frame)
1225         gdk_window_move (window->frame,  x - window->frame_left, y - window->frame_top);
1226       else
1227         gdk_window_move (GTK_WIDGET (window)->window, x, y);
1228     }
1229 }
1230
1231 static void
1232 gtk_window_shutdown (GObject *object)
1233 {
1234   GtkWindow *window;
1235
1236   g_return_if_fail (GTK_IS_WINDOW (object));
1237
1238   window = GTK_WINDOW (object);
1239
1240   gtk_window_set_focus (window, NULL);
1241   gtk_window_set_default (window, NULL);
1242
1243   G_OBJECT_CLASS (parent_class)->shutdown (object);
1244 }
1245
1246 static void
1247 parent_destroyed_callback (GtkWindow *parent, GtkWindow *child)
1248 {
1249   gtk_widget_destroy (GTK_WIDGET (child));
1250 }
1251
1252 static void
1253 connect_parent_destroyed (GtkWindow *window)
1254 {
1255   if (window->transient_parent)
1256     {
1257       gtk_signal_connect (GTK_OBJECT (window->transient_parent),
1258                           "destroy",
1259                           GTK_SIGNAL_FUNC (parent_destroyed_callback),
1260                           window);
1261     }  
1262 }
1263
1264 static void
1265 disconnect_parent_destroyed (GtkWindow *window)
1266 {
1267   if (window->transient_parent)
1268     {
1269       gtk_signal_disconnect_by_func (GTK_OBJECT (window->transient_parent),
1270                                      GTK_SIGNAL_FUNC (parent_destroyed_callback),
1271                                      window);
1272     }
1273 }
1274
1275 static void
1276 gtk_window_transient_parent_realized (GtkWidget *parent,
1277                                       GtkWidget *window)
1278 {
1279   if (GTK_WIDGET_REALIZED (window))
1280     gdk_window_set_transient_for (window->window, parent->window);
1281 }
1282
1283 static void
1284 gtk_window_transient_parent_unrealized (GtkWidget *parent,
1285                                         GtkWidget *window)
1286 {
1287   if (GTK_WIDGET_REALIZED (window))
1288     gdk_property_delete (window->window, 
1289                          gdk_atom_intern ("WM_TRANSIENT_FOR", FALSE));
1290 }
1291
1292 static void       
1293 gtk_window_unset_transient_for  (GtkWindow *window)
1294 {
1295   if (window->transient_parent)
1296     {
1297       gtk_signal_disconnect_by_func (GTK_OBJECT (window->transient_parent),
1298                                      GTK_SIGNAL_FUNC (gtk_window_transient_parent_realized),
1299                                      window);
1300       gtk_signal_disconnect_by_func (GTK_OBJECT (window->transient_parent),
1301                                      GTK_SIGNAL_FUNC (gtk_window_transient_parent_unrealized),
1302                                      window);
1303       gtk_signal_disconnect_by_func (GTK_OBJECT (window->transient_parent),
1304                                      GTK_SIGNAL_FUNC (gtk_widget_destroyed),
1305                                      &window->transient_parent);
1306
1307       if (window->destroy_with_parent)
1308         disconnect_parent_destroyed (window);
1309       
1310       window->transient_parent = NULL;
1311     }
1312 }
1313
1314 /**
1315  * gtk_window_set_transient_for:
1316  * @window: a #GtkWindow
1317  * @parent: parent window
1318  *
1319  * Dialog windows should be set transient for the main application
1320  * window they were spawned from. This allows window managers to
1321  * e.g. keep the dialog on top of the main window, or center the
1322  * dialog over the main window. gtk_dialog_new_with_buttons() and
1323  * other convenience functions in GTK+ will sometimes call
1324  * gtk_window_set_transient_for() on your behalf.
1325  * 
1326  **/
1327 void       
1328 gtk_window_set_transient_for  (GtkWindow *window, 
1329                                GtkWindow *parent)
1330 {
1331   g_return_if_fail (GTK_IS_WINDOW (window));
1332   g_return_if_fail (parent == NULL || GTK_IS_WINDOW (parent));
1333   g_return_if_fail (window != parent);
1334
1335     
1336   if (window->transient_parent)
1337     {
1338       if (GTK_WIDGET_REALIZED (window) && 
1339           GTK_WIDGET_REALIZED (window->transient_parent) && 
1340           (!parent || !GTK_WIDGET_REALIZED (parent)))
1341         gtk_window_transient_parent_unrealized (GTK_WIDGET (window->transient_parent),
1342                                                 GTK_WIDGET (window));
1343
1344       gtk_window_unset_transient_for (window);
1345     }
1346
1347   window->transient_parent = parent;
1348
1349   if (parent)
1350     {
1351       gtk_signal_connect (GTK_OBJECT (parent), "destroy",
1352                           GTK_SIGNAL_FUNC (gtk_widget_destroyed),
1353                           &window->transient_parent);
1354       gtk_signal_connect (GTK_OBJECT (parent), "realize",
1355                           GTK_SIGNAL_FUNC (gtk_window_transient_parent_realized),
1356                           window);
1357       gtk_signal_connect (GTK_OBJECT (parent), "unrealize",
1358                           GTK_SIGNAL_FUNC (gtk_window_transient_parent_unrealized),
1359                           window);
1360
1361       if (window->destroy_with_parent)
1362         connect_parent_destroyed (window);
1363       
1364       if (GTK_WIDGET_REALIZED (window) &&
1365           GTK_WIDGET_REALIZED (parent))
1366         gtk_window_transient_parent_realized (GTK_WIDGET (parent),
1367                                               GTK_WIDGET (window));
1368     }
1369 }
1370
1371 /**
1372  * gtk_window_set_type_hint:
1373  * @window: a #GtkWindow
1374  * @hint: the window type
1375  *
1376  * By setting the type hint for the window, you allow the window
1377  * manager to decorate and handle the window in a way which is
1378  * suitable to the function of the window in your application.
1379  *
1380  * This function should be called before the window becomes visible.
1381  *
1382  * gtk_dialog_new_with_buttons() and other convenience functions in GTK+
1383  * will sometimes call gtk_window_set_type_hint() on your behalf.
1384  * 
1385  **/
1386 void
1387 gtk_window_set_type_hint (GtkWindow           *window, 
1388                           GdkWindowTypeHint    hint)
1389 {
1390   g_return_if_fail (GTK_IS_WINDOW (window));
1391   g_return_if_fail (!GTK_WIDGET_VISIBLE (window));
1392   window->type_hint = hint;
1393 }
1394
1395 /**
1396  * gtk_window_set_destroy_with_parent:
1397  * @window: a #GtkWindow
1398  * @setting: whether to destroy @window with its transient parent
1399  * 
1400  * If @setting is TRUE, then destroying the transient parent of @window
1401  * will also destroy @window itself. This is useful for dialogs that
1402  * shouldn't persist beyond the lifetime of the main window they're
1403  * associated with, for example.
1404  **/
1405 void
1406 gtk_window_set_destroy_with_parent  (GtkWindow *window,
1407                                      gboolean   setting)
1408 {
1409   g_return_if_fail (GTK_IS_WINDOW (window));
1410
1411   if (window->destroy_with_parent == (setting != FALSE))
1412     return;
1413
1414   if (window->destroy_with_parent)
1415     {
1416       disconnect_parent_destroyed (window);
1417     }
1418   else
1419     {
1420       connect_parent_destroyed (window);
1421     }
1422   
1423   window->destroy_with_parent = setting;
1424
1425   g_object_notify (G_OBJECT (window), "destroy_with_parent");
1426 }
1427
1428 static GtkWindowGeometryInfo*
1429 gtk_window_get_geometry_info (GtkWindow *window,
1430                               gboolean   create)
1431 {
1432   GtkWindowGeometryInfo *info;
1433
1434   info = window->geometry_info;
1435   if (!info && create)
1436     {
1437       info = g_new0 (GtkWindowGeometryInfo, 1);
1438
1439       info->width = 0;
1440       info->height = 0;
1441       info->last.width = -1;
1442       info->last.height = -1;
1443       info->widget = NULL;
1444       info->mask = 0;
1445       info->may_shrink = FALSE;
1446       window->geometry_info = info;
1447     }
1448
1449   return info;
1450 }
1451
1452 /**
1453  * gtk_window_set_geometry_hints:
1454  * @window: a #GdkWindow
1455  * @geometry_widget: widget the geometry hints will be applied to
1456  * @geometry: struct containing geometry information
1457  * @geom_mask: mask indicating which struct fields should be paid attention to
1458  *
1459  * This function sets up hints about how a window can be resized by
1460  * the user.  You can set a minimum and maximum size; allowed resize
1461  * increments (e.g. for xterm, you can only resize by the size of a
1462  * character); aspect ratios; and more. See the #GdkGeometry struct.
1463  * 
1464  **/
1465 void       
1466 gtk_window_set_geometry_hints (GtkWindow       *window,
1467                                GtkWidget       *geometry_widget,
1468                                GdkGeometry     *geometry,
1469                                GdkWindowHints   geom_mask)
1470 {
1471   GtkWindowGeometryInfo *info;
1472
1473   g_return_if_fail (window != NULL);
1474
1475   info = gtk_window_get_geometry_info (window, TRUE);
1476   
1477   if (info->widget)
1478     gtk_signal_disconnect_by_func (GTK_OBJECT (info->widget),
1479                                    GTK_SIGNAL_FUNC (gtk_widget_destroyed),
1480                                    &info->widget);
1481   
1482   info->widget = geometry_widget;
1483   if (info->widget)
1484     gtk_signal_connect (GTK_OBJECT (geometry_widget), "destroy",
1485                         GTK_SIGNAL_FUNC (gtk_widget_destroyed),
1486                         &info->widget);
1487
1488   if (geometry)
1489     info->geometry = *geometry;
1490
1491   info->mask = geom_mask;
1492
1493   gtk_widget_queue_resize (GTK_WIDGET (window));
1494 }
1495
1496 /**
1497  * gtk_window_set_decorated:
1498  * @window: a #GtkWindow
1499  * @setting: %TRUE to decorate the window
1500  *
1501  * By default, windows are decorated with a title bar, resize
1502  * controls, etc.  Some window managers allow GTK+ to disable these
1503  * decorations, creating a borderless window. If you set the decorated
1504  * property to %FALSE using this function, GTK+ will do its best to
1505  * convince the window manager not to decorate the window.
1506  * 
1507  **/
1508 void
1509 gtk_window_set_decorated (GtkWindow *window,
1510                           gboolean   setting)
1511 {
1512   g_return_if_fail (GTK_IS_WINDOW (window));
1513
1514   setting = setting != FALSE;
1515
1516   if (setting == window->decorated)
1517     return;
1518
1519   if (GTK_WIDGET (window)->window)
1520     {
1521       if (window->decorated)
1522         gdk_window_set_decorations (GTK_WIDGET (window)->window,
1523                                     GDK_DECOR_ALL);
1524       else
1525         gdk_window_set_decorations (GTK_WIDGET (window)->window,
1526                                     0);
1527     }
1528 }
1529
1530 /**
1531  * gtk_window_set_default_size:
1532  * @window: a #GtkWindow
1533  * @width: width in pixels, 0 to unset, or -1 to leave the width unchanged
1534  * @height: height in pixels, 0 to unset, or -1 to leave the height unchanged
1535  *
1536  * Sets the default size of a window. If the window's "natural" size
1537  * (its size request) is larger than the default, the default will be
1538  * ignored. So the default size is a minimum initial size.  Unlike
1539  * gtk_widget_set_usize(), which sets a size request for a widget and
1540  * thus would keep users from shrinking the window, this function only
1541  * sets the initial size, just as if the user had resized the window
1542  * themselves. Users can still shrink the window again as they
1543  * normally would. Setting a default size of 0 means to use the
1544  * "natural" default size (the size request of the window).
1545  *
1546  * For more control over a window's initial size and how resizing works,
1547  * investigate gtk_window_set_geometry_hints().
1548  *
1549  * A useful feature: if you set the "geometry widget" via
1550  * gtk_window_set_geometry_hints(), the default size specified by
1551  * gtk_window_set_default_size() will be the default size of that
1552  * widget, not of the entire window.
1553  * 
1554  **/
1555 void       
1556 gtk_window_set_default_size (GtkWindow   *window,
1557                              gint         width,
1558                              gint         height)
1559 {
1560   GtkWindowGeometryInfo *info;
1561
1562   g_return_if_fail (GTK_IS_WINDOW (window));
1563
1564   info = gtk_window_get_geometry_info (window, TRUE);
1565
1566   g_object_freeze_notify (G_OBJECT (window));
1567   if (width >= 0)
1568     {
1569       info->width = width;
1570       g_object_notify (G_OBJECT (window), "default_width");
1571       info->may_shrink = TRUE;
1572     }
1573   if (height >= 0)
1574     {
1575       info->height = height;
1576       g_object_notify (G_OBJECT (window), "default_height");
1577       info->may_shrink = TRUE;
1578     }
1579   g_object_thaw_notify (G_OBJECT (window));
1580   
1581   gtk_widget_queue_resize (GTK_WIDGET (window));
1582 }
1583   
1584 static void
1585 gtk_window_destroy (GtkObject *object)
1586 {
1587   GtkWindow *window;
1588   
1589   g_return_if_fail (GTK_IS_WINDOW (object));
1590
1591   window = GTK_WINDOW (object);
1592
1593   if (window->transient_parent)
1594     gtk_window_set_transient_for (window, NULL);
1595
1596   if (window->has_user_ref_count)
1597     {
1598       window->has_user_ref_count = FALSE;
1599       gtk_widget_unref (GTK_WIDGET (window));
1600     }
1601
1602   GTK_OBJECT_CLASS (parent_class)->destroy (object);
1603 }
1604
1605 static gboolean
1606 gtk_window_mnemonic_hash_remove (gpointer       key,
1607                                  gpointer       value,
1608                                  gpointer       user)
1609 {
1610   GtkWindowMnemonic *mnemonic = key;
1611   GtkWindow *window = user;
1612
1613   if (mnemonic->window == window)
1614     {
1615       if (mnemonic->targets)
1616         {
1617           gchar *name = gtk_accelerator_name (mnemonic->keyval, 0);
1618
1619           g_warning ("mnemonic \"%s\" wasn't removed for widget (%p)",
1620                      name, mnemonic->targets->data);
1621           g_free (name);
1622         }
1623       g_slist_free (mnemonic->targets);
1624       g_free (mnemonic);
1625       
1626       return TRUE;
1627     }
1628   return FALSE;
1629 }
1630
1631 static void
1632 gtk_window_finalize (GObject *object)
1633 {
1634   GtkWindow *window;
1635
1636   g_return_if_fail (GTK_IS_WINDOW (object));
1637
1638   window = GTK_WINDOW (object);
1639
1640   toplevel_list = g_slist_remove (toplevel_list, window);
1641
1642   g_free (window->title);
1643   g_free (window->wmclass_name);
1644   g_free (window->wmclass_class);
1645   g_free (window->wm_role);
1646
1647   g_hash_table_foreach_remove (mnemonic_hash_table,
1648                                gtk_window_mnemonic_hash_remove,
1649                                window);
1650   if (window->geometry_info)
1651     {
1652       if (window->geometry_info->widget)
1653         gtk_signal_disconnect_by_func (GTK_OBJECT (window->geometry_info->widget),
1654                                        GTK_SIGNAL_FUNC (gtk_widget_destroyed),
1655                                        &window->geometry_info->widget);
1656       g_free (window->geometry_info);
1657     }
1658   
1659   G_OBJECT_CLASS (parent_class)->finalize (object);
1660 }
1661
1662 static void
1663 gtk_window_show (GtkWidget *widget)
1664 {
1665   GtkWindow *window = GTK_WINDOW (widget);
1666   GtkContainer *container = GTK_CONTAINER (window);
1667   gboolean need_resize;
1668   
1669   GTK_WIDGET_SET_FLAGS (widget, GTK_VISIBLE);
1670   
1671   need_resize = container->need_resize || !GTK_WIDGET_REALIZED (widget);
1672   container->need_resize = FALSE;
1673   
1674   if (need_resize)
1675     {
1676       GtkWindowGeometryInfo *info = gtk_window_get_geometry_info (window, TRUE);
1677       GtkAllocation allocation = { 0, 0 };
1678       GdkGeometry new_geometry;
1679       guint width, height, new_flags;
1680       gboolean was_realized;
1681       
1682       /* determine default size to initially show the window with */
1683       gtk_widget_size_request (widget, NULL);
1684       gtk_window_compute_default_size (window, &width, &height);
1685       
1686       /* save away the last default size for later comparisions */
1687       info->last.width = width;
1688       info->last.height = height;
1689
1690       /* constrain size to geometry */
1691       gtk_window_compute_hints (window, &new_geometry, &new_flags);
1692       gtk_window_constrain_size (window,
1693                                  &new_geometry, new_flags,
1694                                  width, height,
1695                                  &width, &height);
1696       
1697       /* and allocate the window */
1698       allocation.width  = width;
1699       allocation.height = height;
1700       gtk_widget_size_allocate (widget, &allocation);
1701       
1702       was_realized = FALSE;
1703       if (!GTK_WIDGET_REALIZED (widget))
1704         {
1705           gtk_widget_realize (widget);
1706           was_realized = TRUE;;
1707         }
1708
1709       /* Must be done after the windows are realized,
1710        * so that the decorations can be read
1711        */
1712       gtk_decorated_window_calculate_frame_size (window);
1713       
1714       if (!was_realized)
1715         gdk_window_resize (widget->window, width, height);
1716     }
1717   
1718   gtk_container_check_resize (container);
1719
1720   gtk_widget_map (widget);
1721
1722   if (window->modal)
1723     gtk_grab_add (widget);
1724 }
1725
1726 static void
1727 gtk_window_hide (GtkWidget *widget)
1728 {
1729   GtkWindow *window;
1730
1731   g_return_if_fail (widget != NULL);
1732   g_return_if_fail (GTK_IS_WINDOW (widget));
1733
1734   window = GTK_WINDOW (widget);
1735
1736   GTK_WIDGET_UNSET_FLAGS (widget, GTK_VISIBLE);
1737   gtk_widget_unmap (widget);
1738
1739   if (window->modal)
1740     gtk_grab_remove (widget);
1741 }
1742
1743 static void
1744 gtk_window_map (GtkWidget *widget)
1745 {
1746   GtkWindow *window;
1747   GdkWindow *toplevel;
1748   
1749   g_return_if_fail (widget != NULL);
1750   g_return_if_fail (GTK_IS_WINDOW (widget));
1751
1752   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1753
1754   window = GTK_WINDOW (widget);
1755
1756   if (window->bin.child &&
1757       GTK_WIDGET_VISIBLE (window->bin.child) &&
1758       !GTK_WIDGET_MAPPED (window->bin.child))
1759     gtk_widget_map (window->bin.child);
1760
1761   if (window->frame)
1762     toplevel = window->frame;
1763   else
1764     toplevel = widget->window;
1765   
1766   if (window->maximize_initially)
1767     gdk_window_maximize (toplevel);
1768   else
1769     gdk_window_unmaximize (toplevel);
1770   
1771   if (window->stick_initially)
1772     gdk_window_stick (toplevel);
1773   else
1774     gdk_window_unstick (toplevel);
1775   
1776   if (window->iconify_initially)
1777     gdk_window_iconify (toplevel);
1778   else
1779     gdk_window_deiconify (toplevel);
1780   
1781   gdk_window_show (widget->window);
1782
1783   if (window->frame)
1784     gdk_window_show (window->frame);
1785 }
1786
1787 static void
1788 gtk_window_unmap (GtkWidget *widget)
1789 {
1790   GtkWindow *window;
1791
1792   g_return_if_fail (widget != NULL);
1793   g_return_if_fail (GTK_IS_WINDOW (widget));
1794
1795   window = GTK_WINDOW (widget);
1796   
1797   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1798   if (window->frame)
1799     gdk_window_withdraw (window->frame);
1800   else 
1801     gdk_window_withdraw (widget->window);
1802
1803   window->use_uposition = TRUE;
1804   window->resize_count = 0;
1805   window->handling_resize = FALSE;
1806
1807 }
1808
1809 static void
1810 gtk_window_realize (GtkWidget *widget)
1811 {
1812   GtkWindow *window;
1813   GdkWindow *parent_window;
1814   GdkWindowAttr attributes;
1815   gint attributes_mask;
1816   
1817   g_return_if_fail (GTK_IS_WINDOW (widget));
1818
1819   window = GTK_WINDOW (widget);
1820
1821   /* ensure widget tree is properly size allocated */
1822   if (widget->allocation.x == -1 &&
1823       widget->allocation.y == -1 &&
1824       widget->allocation.width == 1 &&
1825       widget->allocation.height == 1)
1826     {
1827       GtkRequisition requisition;
1828       GtkAllocation allocation = { 0, 0, 200, 200 };
1829
1830       gtk_widget_size_request (widget, &requisition);
1831       if (requisition.width || requisition.height)
1832         {
1833           /* non-empty window */
1834           allocation.width = requisition.width;
1835           allocation.height = requisition.height;
1836         }
1837       gtk_widget_size_allocate (widget, &allocation);
1838       
1839       gtk_container_queue_resize (GTK_CONTAINER (widget));
1840
1841       g_return_if_fail (!GTK_WIDGET_REALIZED (widget));
1842     }
1843   
1844   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1845   
1846   switch (window->type)
1847     {
1848     case GTK_WINDOW_TOPLEVEL:
1849       attributes.window_type = GDK_WINDOW_TOPLEVEL;
1850       break;
1851     case GTK_WINDOW_POPUP:
1852       attributes.window_type = GDK_WINDOW_TEMP;
1853       break;
1854     default:
1855       g_warning (G_STRLOC": Unknown window type %d!", window->type);
1856       break;
1857     }
1858    
1859   attributes.title = window->title;
1860   attributes.wmclass_name = window->wmclass_name;
1861   attributes.wmclass_class = window->wmclass_class;
1862   attributes.wclass = GDK_INPUT_OUTPUT;
1863   attributes.visual = gtk_widget_get_visual (widget);
1864   attributes.colormap = gtk_widget_get_colormap (widget);
1865
1866   if (window->has_frame)
1867     {
1868       attributes.width = widget->allocation.width + window->frame_left + window->frame_right;
1869       attributes.height = widget->allocation.height + window->frame_top + window->frame_bottom;
1870       attributes.event_mask = (GDK_EXPOSURE_MASK |
1871                                GDK_KEY_PRESS_MASK |
1872                                GDK_ENTER_NOTIFY_MASK |
1873                                GDK_LEAVE_NOTIFY_MASK |
1874                                GDK_FOCUS_CHANGE_MASK |
1875                                GDK_STRUCTURE_MASK |
1876                                GDK_BUTTON_MOTION_MASK |
1877                                GDK_POINTER_MOTION_HINT_MASK |
1878                                GDK_BUTTON_PRESS_MASK |
1879                                GDK_BUTTON_RELEASE_MASK);
1880       
1881       attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP;
1882       
1883       window->frame = gdk_window_new (NULL, &attributes, attributes_mask);
1884       gdk_window_set_user_data (window->frame, widget);
1885       
1886       attributes.window_type = GDK_WINDOW_CHILD;
1887       attributes.x = window->frame_left;
1888       attributes.y = window->frame_right;
1889     
1890       attributes_mask = GDK_WA_X | GDK_WA_Y;
1891
1892       parent_window = window->frame;
1893     }
1894   else
1895     {
1896       attributes_mask = 0;
1897       parent_window = NULL;
1898     }
1899   
1900   attributes.width = widget->allocation.width;
1901   attributes.height = widget->allocation.height;
1902   attributes.event_mask = gtk_widget_get_events (widget);
1903   attributes.event_mask |= (GDK_EXPOSURE_MASK |
1904                             GDK_KEY_PRESS_MASK |
1905                             GDK_ENTER_NOTIFY_MASK |
1906                             GDK_LEAVE_NOTIFY_MASK |
1907                             GDK_FOCUS_CHANGE_MASK |
1908                             GDK_STRUCTURE_MASK);
1909
1910   attributes_mask |= GDK_WA_VISUAL | GDK_WA_COLORMAP;
1911   attributes_mask |= (window->title ? GDK_WA_TITLE : 0);
1912   attributes_mask |= (window->wmclass_name ? GDK_WA_WMCLASS : 0);
1913   widget->window = gdk_window_new (parent_window, &attributes, attributes_mask);
1914   gdk_window_set_user_data (widget->window, window);
1915       
1916   widget->style = gtk_style_attach (widget->style, widget->window);
1917   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
1918   if (window->frame)
1919     gtk_style_set_background (widget->style, window->frame, GTK_STATE_NORMAL);
1920
1921   /* This is a bad hack to set the window background. */
1922   gtk_window_paint (widget, NULL);
1923   
1924   if (window->transient_parent &&
1925       GTK_WIDGET_REALIZED (window->transient_parent))
1926     gdk_window_set_transient_for (widget->window,
1927                                   GTK_WIDGET (window->transient_parent)->window);
1928
1929   if (window->wm_role)
1930     gdk_window_set_role (widget->window, window->wm_role);
1931   
1932   if (!window->decorated)
1933     gdk_window_set_decorations (widget->window, 0);
1934
1935   gdk_window_set_type_hint (widget->window, window->type_hint);
1936
1937   /* transient_for must be set to allow the modal hint */
1938   if (window->transient_parent && window->modal)
1939     gdk_window_set_modal_hint (widget->window, TRUE);
1940   else
1941     gdk_window_set_modal_hint (widget->window, FALSE);
1942 }
1943
1944 static void
1945 gtk_window_unrealize (GtkWidget *widget)
1946 {
1947   GtkWindow *window;
1948
1949   g_return_if_fail (widget != NULL);
1950   g_return_if_fail (GTK_IS_WINDOW (widget));
1951
1952   window = GTK_WINDOW (widget);
1953
1954   if (window->frame)
1955     {
1956       gdk_window_set_user_data (window->frame, NULL);
1957       gdk_window_destroy (window->frame);
1958       window->frame = NULL;
1959     }
1960   
1961   (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1962 }
1963
1964 static void
1965 gtk_window_size_request (GtkWidget      *widget,
1966                          GtkRequisition *requisition)
1967 {
1968   GtkWindow *window;
1969   GtkBin *bin;
1970
1971   g_return_if_fail (widget != NULL);
1972   g_return_if_fail (GTK_IS_WINDOW (widget));
1973   g_return_if_fail (requisition != NULL);
1974
1975   window = GTK_WINDOW (widget);
1976   bin = GTK_BIN (window);
1977   
1978   requisition->width = GTK_CONTAINER (window)->border_width * 2;
1979   requisition->height = GTK_CONTAINER (window)->border_width * 2;
1980
1981   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
1982     {
1983       GtkRequisition child_requisition;
1984       
1985       gtk_widget_size_request (bin->child, &child_requisition);
1986
1987       requisition->width += child_requisition.width;
1988       requisition->height += child_requisition.height;
1989     }
1990 }
1991
1992 static void
1993 gtk_window_size_allocate (GtkWidget     *widget,
1994                           GtkAllocation *allocation)
1995 {
1996   GtkWindow *window;
1997   GtkAllocation child_allocation;
1998
1999   g_return_if_fail (widget != NULL);
2000   g_return_if_fail (GTK_IS_WINDOW (widget));
2001   g_return_if_fail (allocation != NULL);
2002
2003   window = GTK_WINDOW (widget);
2004   widget->allocation = *allocation;
2005
2006   if (window->bin.child && GTK_WIDGET_VISIBLE (window->bin.child))
2007     {
2008       child_allocation.x = GTK_CONTAINER (window)->border_width;
2009       child_allocation.y = GTK_CONTAINER (window)->border_width;
2010       child_allocation.width =
2011         MAX (1, (gint)allocation->width - child_allocation.x * 2);
2012       child_allocation.height =
2013         MAX (1, (gint)allocation->height - child_allocation.y * 2);
2014
2015       gtk_widget_size_allocate (window->bin.child, &child_allocation);
2016     }
2017
2018   if (GTK_WIDGET_REALIZED (widget) && window->frame)
2019     {
2020       gdk_window_resize (window->frame,
2021                          allocation->width + window->frame_left + window->frame_right,
2022                          allocation->height + window->frame_top + window->frame_bottom);
2023     }
2024 }
2025
2026 static gint
2027 gtk_window_event (GtkWidget *widget, GdkEvent *event)
2028 {
2029   GtkWindow *window;
2030   gboolean return_val;
2031
2032   
2033   g_return_val_if_fail (widget != NULL, FALSE);
2034   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
2035   g_return_val_if_fail (event != NULL, FALSE);
2036   
2037   window = GTK_WINDOW (widget);
2038
2039   if (window->frame && (event->any.window == window->frame))
2040     {
2041       if ((event->type != GDK_KEY_PRESS) &&
2042           (event->type != GDK_KEY_RELEASE) &&
2043           (event->type != GDK_FOCUS_CHANGE))
2044         {
2045           gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "event");
2046           return_val = FALSE;
2047           gtk_signal_emit (GTK_OBJECT (widget), window_signals[FRAME_EVENT], event, &return_val);
2048           return TRUE;
2049         }
2050       else
2051         {
2052           g_object_unref (event->any.window);
2053           event->any.window = g_object_ref (widget->window);
2054         }
2055     }
2056
2057   return FALSE;
2058 }
2059
2060 static gboolean
2061 gtk_window_frame_event (GtkWidget *widget, GdkEvent *event)
2062 {
2063   GdkEventConfigure *configure_event;
2064   GtkWindow *window = GTK_WINDOW (widget);
2065   GdkRectangle rect;
2066
2067   switch (event->type)
2068     {
2069     case GDK_CONFIGURE:
2070       configure_event = (GdkEventConfigure *)event;
2071       
2072       /* Invalidate the decorations */
2073       rect.x = 0;
2074       rect.y = 0;
2075       rect.width = configure_event->width;
2076       rect.height = configure_event->height;
2077       
2078       gdk_window_invalidate_rect (window->frame, &rect, FALSE);
2079
2080       /* Pass on the (modified) configure event */
2081       configure_event->width -= window->frame_left + window->frame_right;
2082       configure_event->height -= window->frame_top + window->frame_bottom;
2083       return gtk_window_configure_event (widget, configure_event);
2084       break;
2085     default:
2086       break;
2087     }
2088   return FALSE;
2089 }
2090
2091 static gint
2092 gtk_window_configure_event (GtkWidget         *widget,
2093                             GdkEventConfigure *event)
2094 {
2095   GtkWindow *window;
2096   
2097   g_return_val_if_fail (widget != NULL, FALSE);
2098   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
2099   g_return_val_if_fail (event != NULL, FALSE);
2100   
2101   window = GTK_WINDOW (widget);
2102
2103   /* we got a configure event specifying the new window size and position,
2104    * in principle we have to distinguish 4 cases here:
2105    * 1) the size didn't change and resize_count == 0
2106    *    -> the window was merely moved (sometimes not even that)
2107    * 2) the size didn't change and resize_count > 0
2108    *    -> we requested a new size, but didn't get it
2109    * 3) the size changed and resize_count > 0
2110    *    -> we asked for a new size and we got one
2111    * 4) the size changed and resize_count == 0
2112    *    -> we got resized from outside the toolkit, and have to
2113    *    accept that size since we don't want to fight neither the
2114    *    window manager nor the user
2115    * in the three latter cases we have to reallocate the widget tree,
2116    * which happens in gtk_window_move_resize(), so we set a flag for
2117    * that function and assign the new size. if resize_count > 1,
2118    * we simply do nothing and wait for more configure events.
2119    */
2120
2121   if (window->resize_count > 0 ||
2122       widget->allocation.width != event->width ||
2123       widget->allocation.height != event->height)
2124     {
2125       if (window->resize_count > 0)
2126         window->resize_count -= 1;
2127
2128       if (window->resize_count == 0)
2129         {
2130           window->handling_resize = TRUE;
2131           
2132           widget->allocation.width = event->width;
2133           widget->allocation.height = event->height;
2134           
2135           gtk_widget_queue_resize (widget);
2136         }
2137     }
2138
2139   return TRUE;
2140 }
2141
2142 static gint
2143 gtk_window_key_press_event (GtkWidget   *widget,
2144                             GdkEventKey *event)
2145 {
2146   GtkWindow *window;
2147   gboolean handled;
2148
2149   g_return_val_if_fail (widget != NULL, FALSE);
2150   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
2151   g_return_val_if_fail (event != NULL, FALSE);
2152
2153   window = GTK_WINDOW (widget);
2154
2155   handled = FALSE;
2156   
2157   if (window->focus_widget && window->focus_widget != widget &&
2158       GTK_WIDGET_IS_SENSITIVE (window->focus_widget))
2159     handled = gtk_widget_event (window->focus_widget, (GdkEvent*) event);
2160
2161   if (!handled)
2162     handled = gtk_window_mnemonic_activate (window,
2163                                             event->keyval,
2164                                             event->state);
2165
2166   if (!handled)
2167     handled = gtk_accel_groups_activate (GTK_OBJECT (window), event->keyval, event->state);
2168
2169   /* Chain up, invokes binding set */
2170   if (!handled && GTK_WIDGET_CLASS (parent_class)->key_press_event)
2171     handled = GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
2172
2173   return handled;
2174 }
2175
2176
2177 static void
2178 gtk_window_real_activate_default (GtkWindow *window)
2179 {
2180   gtk_window_activate_default (window);
2181 }
2182
2183 static void
2184 gtk_window_real_activate_focus (GtkWindow *window)
2185 {
2186   gtk_window_activate_focus (window);
2187 }
2188
2189 static void
2190 gtk_window_move_focus (GtkWindow       *window,
2191                        GtkDirectionType dir)
2192 {
2193   gtk_container_focus (GTK_CONTAINER (window), dir);
2194   
2195   if (!GTK_CONTAINER (window)->focus_child)
2196     gtk_window_set_focus (window, NULL);
2197 }
2198
2199 static gint
2200 gtk_window_key_release_event (GtkWidget   *widget,
2201                               GdkEventKey *event)
2202 {
2203   GtkWindow *window;
2204   gint handled;
2205   
2206   g_return_val_if_fail (widget != NULL, FALSE);
2207   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
2208   g_return_val_if_fail (event != NULL, FALSE);
2209   
2210   window = GTK_WINDOW (widget);
2211   handled = FALSE;
2212   if (window->focus_widget &&
2213       window->focus_widget != widget &&
2214       GTK_WIDGET_SENSITIVE (window->focus_widget))
2215     {
2216       handled = gtk_widget_event (window->focus_widget, (GdkEvent*) event);
2217     }
2218
2219   if (!handled && GTK_WIDGET_CLASS (parent_class)->key_release_event)
2220     handled = GTK_WIDGET_CLASS (parent_class)->key_release_event (widget, event);
2221
2222   return handled;
2223 }
2224
2225 static gint
2226 gtk_window_enter_notify_event (GtkWidget        *widget,
2227                                GdkEventCrossing *event)
2228 {
2229   g_return_val_if_fail (widget != NULL, FALSE);
2230   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
2231   g_return_val_if_fail (event != NULL, FALSE);
2232
2233   return FALSE;
2234 }
2235
2236 static gint
2237 gtk_window_leave_notify_event (GtkWidget        *widget,
2238                                GdkEventCrossing *event)
2239 {
2240   g_return_val_if_fail (widget != NULL, FALSE);
2241   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
2242   g_return_val_if_fail (event != NULL, FALSE);
2243
2244   return FALSE;
2245 }
2246
2247 static gint
2248 gtk_window_focus_in_event (GtkWidget     *widget,
2249                            GdkEventFocus *event)
2250 {
2251   GtkWindow *window;
2252   GdkEventFocus fevent;
2253
2254   g_return_val_if_fail (widget != NULL, FALSE);
2255   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
2256   g_return_val_if_fail (event != NULL, FALSE);
2257
2258   /* It appears spurious focus in events can occur when
2259    *  the window is hidden. So we'll just check to see if
2260    *  the window is visible before actually handling the
2261    *  event
2262    */
2263   if (GTK_WIDGET_VISIBLE (widget))
2264     {
2265       window = GTK_WINDOW (widget);
2266       if (window->focus_widget &&
2267           window->focus_widget != widget &&
2268           !GTK_WIDGET_HAS_FOCUS (window->focus_widget))
2269         {
2270           fevent.type = GDK_FOCUS_CHANGE;
2271           fevent.window = window->focus_widget->window;
2272           fevent.in = TRUE;
2273
2274           gtk_widget_event (window->focus_widget, (GdkEvent*) &fevent);
2275         }
2276     }
2277
2278   return FALSE;
2279 }
2280
2281 static gint
2282 gtk_window_focus_out_event (GtkWidget     *widget,
2283                             GdkEventFocus *event)
2284 {
2285   GtkWindow *window;
2286   GdkEventFocus fevent;
2287
2288   g_return_val_if_fail (widget != NULL, FALSE);
2289   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
2290   g_return_val_if_fail (event != NULL, FALSE);
2291
2292   window = GTK_WINDOW (widget);
2293   if (window->focus_widget &&
2294       window->focus_widget != widget &&
2295       GTK_WIDGET_HAS_FOCUS (window->focus_widget))
2296     {
2297       fevent.type = GDK_FOCUS_CHANGE;
2298       fevent.window = window->focus_widget->window;
2299       fevent.in = FALSE;
2300
2301       gtk_widget_event (window->focus_widget, (GdkEvent*) &fevent);
2302     }
2303
2304   return FALSE;
2305 }
2306
2307 static GdkAtom atom_rcfiles = GDK_NONE;
2308
2309 static void
2310 gtk_window_read_rcfiles (GtkWidget *widget,
2311                          GdkEventClient *event)
2312 {
2313   GList *embedded_windows;
2314
2315   embedded_windows = gtk_object_get_data (GTK_OBJECT (widget), "gtk-embedded");
2316   if (embedded_windows)
2317     {
2318       GdkEventClient sev;
2319       int i;
2320       
2321       for(i = 0; i < 5; i++)
2322         sev.data.l[i] = 0;
2323       sev.data_format = 32;
2324       sev.message_type = atom_rcfiles;
2325       
2326       while (embedded_windows)
2327         {
2328           guint xid = GPOINTER_TO_UINT (embedded_windows->data);
2329           gdk_event_send_client_message ((GdkEvent *) &sev, xid);
2330           embedded_windows = embedded_windows->next;
2331         }
2332     }
2333
2334   if (gtk_rc_reparse_all ())
2335     {
2336       /* If the above returned true, some of our RC files are out
2337        * of date, so we need to reset all our widgets. Our other
2338        * toplevel windows will also get the message, but by
2339        * then, the RC file will up to date, so we have to tell
2340        * them now. Also, we have to invalidate cached icons in
2341        * icon sets so they get re-rendered.
2342        */
2343       GList *list, *toplevels;
2344
2345       _gtk_icon_set_invalidate_caches ();
2346       
2347       toplevels = gtk_window_list_toplevels ();
2348       g_list_foreach (toplevels, (GFunc)g_object_ref, NULL);
2349       
2350       for (list = toplevels; list; list = list->next)
2351         {
2352           gtk_widget_reset_rc_styles (list->data);
2353           gtk_widget_unref (list->data);
2354         }
2355       g_list_free (toplevels);
2356     }
2357 }
2358
2359 static gint
2360 gtk_window_client_event (GtkWidget      *widget,
2361                          GdkEventClient *event)
2362 {
2363   g_return_val_if_fail (widget != NULL, FALSE);
2364   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
2365   g_return_val_if_fail (event != NULL, FALSE);
2366
2367   if (!atom_rcfiles)
2368     atom_rcfiles = gdk_atom_intern("_GTK_READ_RCFILES", FALSE);
2369
2370   if(event->message_type == atom_rcfiles) 
2371     gtk_window_read_rcfiles (widget, event);    
2372
2373   return FALSE;
2374 }
2375
2376 static void
2377 gtk_window_check_resize (GtkContainer *container)
2378 {
2379   GtkWindow *window;
2380
2381   g_return_if_fail (container != NULL);
2382   g_return_if_fail (GTK_IS_WINDOW (container));
2383
2384   window = GTK_WINDOW (container);
2385
2386   if (GTK_WIDGET_VISIBLE (container))
2387     gtk_window_move_resize (window);
2388 }
2389
2390 static gboolean
2391 gtk_window_focus (GtkContainer     *container,
2392                   GtkDirectionType  direction)
2393 {
2394   GtkBin *bin = GTK_BIN (container);
2395   GtkWindow *window = GTK_WINDOW (container);
2396   GtkWidget *old_focus_child = container->focus_child;
2397   GtkWidget *parent;
2398   
2399   /* We need a special implementation here to deal properly with wrapping
2400    * around in the tab chain without the danger of going into an
2401    * infinite loop.
2402    */
2403   if (old_focus_child)
2404     {
2405       if (GTK_IS_CONTAINER (old_focus_child) &&
2406           GTK_WIDGET_DRAWABLE (old_focus_child) &&
2407           GTK_WIDGET_IS_SENSITIVE (old_focus_child) &&
2408           gtk_container_focus (GTK_CONTAINER (old_focus_child), direction))
2409         return TRUE;
2410     }
2411
2412   if (window->focus_widget)
2413     {
2414       /* Wrapped off the end, clear the focus setting for the toplpevel */
2415       parent = window->focus_widget->parent;
2416       while (parent)
2417         {
2418           gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
2419           parent = GTK_WIDGET (parent)->parent;
2420         }
2421       
2422       gtk_window_set_focus (GTK_WINDOW (container), NULL);
2423     }
2424
2425   /* Now try to focus the first widget in the window */
2426   if (GTK_WIDGET_DRAWABLE (bin->child) &&
2427       GTK_WIDGET_IS_SENSITIVE (bin->child))
2428     {
2429       if (GTK_IS_CONTAINER (bin->child))
2430         {
2431           if (gtk_container_focus (GTK_CONTAINER (bin->child), direction))
2432             return TRUE;
2433         }
2434       else if (GTK_WIDGET_CAN_FOCUS (bin->child))
2435         {
2436           gtk_widget_grab_focus (bin->child);
2437           return TRUE;
2438         }
2439     }
2440
2441   return FALSE;
2442 }
2443
2444 static void
2445 gtk_window_real_set_focus (GtkWindow *window,
2446                            GtkWidget *focus)
2447 {
2448   GdkEventFocus event;
2449   gboolean def_flags = 0;
2450
2451   g_return_if_fail (window != NULL);
2452   g_return_if_fail (GTK_IS_WINDOW (window));
2453   
2454   if (window->default_widget)
2455     def_flags = GTK_WIDGET_HAS_DEFAULT (window->default_widget);
2456   
2457   if (window->focus_widget)
2458     {
2459       event.type = GDK_FOCUS_CHANGE;
2460       event.window = window->focus_widget->window;
2461       event.in = FALSE;
2462       
2463       if (GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget) &&
2464           (window->focus_widget != window->default_widget))
2465         {
2466           GTK_WIDGET_UNSET_FLAGS (window->focus_widget, GTK_HAS_DEFAULT);
2467           /* if any widget had the default set there should be
2468              a default_widget, but might not so this is a sanity
2469              check */
2470           if (window->default_widget)
2471             GTK_WIDGET_SET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
2472         }
2473         
2474       gtk_widget_event (window->focus_widget, (GdkEvent*) &event);
2475     }
2476   
2477   window->focus_widget = focus;
2478   
2479   if (window->focus_widget)
2480     {
2481       event.type = GDK_FOCUS_CHANGE;
2482       event.window = window->focus_widget->window;
2483       event.in = TRUE;
2484
2485       if (GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget) &&
2486           (window->focus_widget != window->default_widget))
2487         {
2488           if (GTK_WIDGET_CAN_DEFAULT (window->focus_widget))
2489             GTK_WIDGET_SET_FLAGS (window->focus_widget, GTK_HAS_DEFAULT);
2490
2491           if (window->default_widget)
2492             GTK_WIDGET_UNSET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
2493         }
2494       
2495       gtk_widget_event (window->focus_widget, (GdkEvent*) &event);
2496     }
2497   
2498   if (window->default_widget &&
2499       (def_flags != GTK_WIDGET_FLAGS (window->default_widget)))
2500     gtk_widget_queue_draw (window->default_widget);
2501 }
2502
2503
2504
2505 /*********************************
2506  * Functions related to resizing *
2507  *********************************/
2508
2509 static void
2510 gtk_window_move_resize (GtkWindow *window)
2511 {
2512   GtkWidget *widget;
2513   GtkContainer *container;
2514   GtkWindowGeometryInfo *info;
2515   GtkWindowLastGeometryInfo saved_last_info;
2516   GdkGeometry new_geometry;
2517   guint new_flags;
2518   gint x, y;
2519   gint width, height;
2520   gint new_width, new_height;
2521   gboolean need_reposition;
2522   gboolean default_size_changed = FALSE;
2523   gboolean hints_changed = FALSE;
2524   gboolean may_shrink = window->auto_shrink;
2525
2526   g_return_if_fail (GTK_WIDGET_REALIZED (window));
2527
2528   widget = GTK_WIDGET (window);
2529   container = GTK_CONTAINER (widget);
2530   info = gtk_window_get_geometry_info (window, TRUE);
2531   saved_last_info = info->last;
2532
2533   gtk_widget_size_request (widget, NULL);
2534   gtk_window_compute_default_size (window, &new_width, &new_height);
2535   
2536   if (info->last.width < 0 ||
2537       info->last.width != new_width ||
2538       info->last.height != new_height)
2539     {
2540       default_size_changed = TRUE;
2541       may_shrink |= info->may_shrink;
2542       info->last.width = new_width;
2543       info->last.height = new_height;
2544
2545       /* We need to force a reposition in this case
2546        */
2547       if (window->position == GTK_WIN_POS_CENTER_ALWAYS)
2548         window->use_uposition = TRUE;
2549     }
2550   info->may_shrink = FALSE;
2551   
2552   /* Compute new set of hints for the window
2553    */
2554   gtk_window_compute_hints (window, &new_geometry, &new_flags);
2555   if (!gtk_window_compare_hints (&info->last.geometry, info->last.flags,
2556                                  &new_geometry, new_flags))
2557     {
2558       hints_changed = TRUE;
2559       info->last.geometry = new_geometry;
2560       info->last.flags = new_flags;
2561     }
2562
2563   /* From the default size and the allocation, figure out the size
2564    * the window should be.
2565    */
2566   if (!default_size_changed ||
2567       (!may_shrink &&
2568        new_width <= widget->allocation.width &&
2569        new_height <= widget->allocation.height))
2570     {
2571       new_width = widget->allocation.width;
2572       new_height = widget->allocation.height;
2573     }
2574
2575   /* constrain the window size to the specified geometry */
2576   gtk_window_constrain_size (window,
2577                              &new_geometry, new_flags,
2578                              new_width, new_height,
2579                              &new_width, &new_height);
2580
2581   /* compute new window position if a move is required
2582    */
2583   need_reposition = gtk_window_compute_reposition (window, new_width, new_height, &x, &y);
2584   if (need_reposition && !(new_flags & GDK_HINT_POS))
2585     {
2586       new_flags |= GDK_HINT_POS;
2587       hints_changed = TRUE;
2588     }
2589
2590
2591   /* handle actual resizing:
2592    * - handle reallocations due to configure events
2593    * - figure whether we need to request a new window size
2594    * - handle simple resizes within our widget tree
2595    * - reposition window if neccessary
2596    */
2597   width = widget->allocation.width;
2598   height = widget->allocation.height;
2599
2600   if (window->handling_resize)
2601     { 
2602       GtkAllocation allocation;
2603       
2604       /* if we are just responding to a configure event, which
2605        * might be due to a resize by the window manager, the
2606        * user, or a response to a resizing request we made
2607        * earlier, we go ahead, allocate the new size and we're done
2608        * (see gtk_window_configure_event() for more details).
2609        */
2610       
2611       window->handling_resize = FALSE;
2612       
2613       allocation = widget->allocation;
2614       
2615       gtk_widget_size_allocate (widget, &allocation);
2616       gtk_widget_queue_draw (widget);
2617
2618       if ((default_size_changed || hints_changed) && (width != new_width || height != new_height))
2619         {
2620           /* We could be here for two reasons
2621            *  1) We coincidentally got a resize while handling
2622            *     another resize.
2623            *  2) Our computation of default_size_changed was completely
2624            *     screwed up, probably because one of our children
2625            *     is changed requisition during size allocation).
2626            *
2627            * For 1), we could just go ahead and ask for the
2628            * new size right now, but doing that for 2)
2629            * might well be fighting the user (and can even
2630            * trigger a loop). Since we really don't want to
2631            * do that, we requeue a resize in hopes that
2632            * by the time it gets handled, the child has seen
2633            * the light and is willing to go along with the
2634            * new size. (this happens for the zvt widget, since
2635            * the size_allocate() above will have stored the
2636            * requisition corresponding to the new size in the
2637            * zvt widget)
2638            *
2639            * This doesn't buy us anything for 1), but it shouldn't
2640            * hurt us too badly, since it is what would have
2641            * happened if we had gotten the configure event before
2642            * the new size had been set.
2643            */
2644           
2645           if (need_reposition)
2646             {
2647               if (window->frame)
2648                 gdk_window_move (window->frame, x - window->frame_left, y - window->frame_top);
2649               else
2650                 gdk_window_move (GTK_WIDGET (window)->window, x, y);
2651             }
2652
2653           /* we have to preserve the values and flags that are used
2654            * for computation of default_size_changed and hints_changed
2655            */
2656           info->last = saved_last_info;
2657           
2658           gtk_widget_queue_resize (widget);
2659
2660           return;
2661         }
2662     }
2663
2664   /* Now set hints if necessary
2665    */
2666   if (hints_changed)
2667     gdk_window_set_geometry_hints (widget->window,
2668                                    &new_geometry,
2669                                    new_flags);
2670
2671   if ((default_size_changed || hints_changed) &&
2672       (width != new_width || height != new_height))
2673     {
2674       /* given that (width != new_width || height != new_height), we are in one
2675        * of the following situations:
2676        * 
2677        * default_size_changed
2678        *   our requisition has changed and we need a different window size,
2679        *   so we request it from the window manager.
2680        *
2681        * !default_size_changed
2682        *   the window manager wouldn't assign us the size we requested, in this
2683        *   case we don't try to request a new size with every resize.
2684        *
2685        * !default_size_changed && hints_changed
2686        *   the window manager rejects our size, but we have just changed the
2687        *   window manager hints, so there's a certain chance our request will
2688        *   be honoured this time, so we try again.
2689        */
2690       
2691       /* request a new window size */
2692       if (need_reposition)
2693         {
2694           if (window->frame)
2695             {
2696               gdk_window_move_resize (window->frame,
2697                                       x - window->frame_left, y - window->frame_top,
2698                                       new_width + window->frame_left + window->frame_right,
2699                                       new_height + window->frame_top + window->frame_bottom);
2700               gdk_window_resize (GTK_WIDGET (window)->window, new_width, new_height);
2701             }
2702           else
2703             gdk_window_move_resize (GTK_WIDGET (window)->window, x, y, new_width, new_height);
2704         }
2705       else
2706         {
2707           if (window->frame)
2708             gdk_window_resize (window->frame,
2709                                new_width + window->frame_left + window->frame_right,
2710                                new_height + window->frame_top + window->frame_bottom);
2711           gdk_window_resize (GTK_WIDGET (window)->window, new_width, new_height);
2712         }
2713       window->resize_count += 1;
2714       
2715       /* we are now awaiting the new configure event in response to our
2716        * resizing request. the configure event will cause a new resize
2717        * with ->handling_resize=TRUE.
2718        * until then, we want to
2719        * - discard expose events
2720        * - coalesce resizes for our children
2721        * - defer any window resizes until the configure event arrived
2722        * to achive this, we queue a resize for the window, but remove its
2723        * resizing handler, so resizing will not be handled from the next
2724        * idle handler but when the configure event arrives.
2725        *
2726        * FIXME: we should also dequeue the pending redraws here, since
2727        * we handle those ourselves in ->handling_resize==TRUE.
2728        */
2729       gtk_widget_queue_resize (GTK_WIDGET (container));
2730       if (container->resize_mode == GTK_RESIZE_QUEUE)
2731         gtk_container_dequeue_resize_handler (container);
2732     }
2733   else
2734     {
2735       if (need_reposition)
2736         {
2737           if (window->frame)
2738             gdk_window_move (window->frame, x - window->frame_left, y - window->frame_top);
2739           else
2740             gdk_window_move (widget->window, x, y);
2741         }
2742
2743       if (container->resize_widgets)
2744         gtk_container_resize_children (GTK_CONTAINER (window));
2745     }
2746 }
2747
2748 /* Compare two sets of Geometry hints for equality.
2749  */
2750 static gboolean
2751 gtk_window_compare_hints (GdkGeometry *geometry_a,
2752                           guint        flags_a,
2753                           GdkGeometry *geometry_b,
2754                           guint        flags_b)
2755 {
2756   if (flags_a != flags_b)
2757     return FALSE;
2758   
2759   if ((flags_a & GDK_HINT_MIN_SIZE) &&
2760       (geometry_a->min_width != geometry_b->min_width ||
2761        geometry_a->min_height != geometry_b->min_height))
2762     return FALSE;
2763
2764   if ((flags_a & GDK_HINT_MAX_SIZE) &&
2765       (geometry_a->max_width != geometry_b->max_width ||
2766        geometry_a->max_height != geometry_b->max_height))
2767     return FALSE;
2768
2769   if ((flags_a & GDK_HINT_BASE_SIZE) &&
2770       (geometry_a->base_width != geometry_b->base_width ||
2771        geometry_a->base_height != geometry_b->base_height))
2772     return FALSE;
2773
2774   if ((flags_a & GDK_HINT_ASPECT) &&
2775       (geometry_a->min_aspect != geometry_b->min_aspect ||
2776        geometry_a->max_aspect != geometry_b->max_aspect))
2777     return FALSE;
2778
2779   if ((flags_a & GDK_HINT_RESIZE_INC) &&
2780       (geometry_a->width_inc != geometry_b->width_inc ||
2781        geometry_a->height_inc != geometry_b->height_inc))
2782     return FALSE;
2783
2784   if ((flags_a & GDK_HINT_WIN_GRAVITY) &&
2785       geometry_a->win_gravity != geometry_b->win_gravity)
2786     return FALSE;
2787
2788   return TRUE;
2789 }
2790
2791 /* Compute the default_size for a window. The result will
2792  * be stored in *width and *height. The default size is
2793  * the size the window should have when initially mapped.
2794  * This routine does not attempt to constrain the size
2795  * to obey the geometry hints - that must be done elsewhere.
2796  */
2797 static void 
2798 gtk_window_compute_default_size (GtkWindow       *window,
2799                                  guint           *width,
2800                                  guint           *height)
2801 {
2802   GtkRequisition requisition;
2803   GtkWindowGeometryInfo *info;
2804   
2805   gtk_widget_get_child_requisition (GTK_WIDGET (window), &requisition);
2806   *width = requisition.width;
2807   *height = requisition.height;
2808
2809   info = gtk_window_get_geometry_info (window, FALSE);
2810   
2811   if (*width == 0 && *height == 0)
2812     {
2813       /* empty window */
2814       *width = 200;
2815       *height = 200;
2816     }
2817   
2818   if (info)
2819     {
2820       *width = info->width > 0 ? info->width : *width;
2821       *height = info->height > 0 ? info->height : *height;
2822     }
2823 }
2824
2825 void
2826 _gtk_window_constrain_size (GtkWindow   *window,
2827                             gint         width,
2828                             gint         height,
2829                             gint        *new_width,
2830                             gint        *new_height)
2831 {
2832   GtkWindowGeometryInfo *info;
2833
2834   g_return_if_fail (GTK_IS_WINDOW (window));
2835
2836   info = window->geometry_info;
2837   if (info)
2838     {
2839       GdkWindowHints flags = info->last.flags;
2840       GdkGeometry *geometry = &info->last.geometry;
2841       
2842       gtk_window_constrain_size (window,
2843                                  geometry,
2844                                  flags,
2845                                  width,
2846                                  height,
2847                                  new_width,
2848                                  new_height);
2849     }
2850 }
2851
2852 static void 
2853 gtk_window_constrain_size (GtkWindow   *window,
2854                            GdkGeometry *geometry,
2855                            guint        flags,
2856                            gint         width,
2857                            gint         height,
2858                            gint        *new_width,
2859                            gint        *new_height)
2860 {
2861   gdk_window_constrain_size (geometry, flags, width, height,
2862                              new_width, new_height);
2863 }
2864
2865 /* Compute the set of geometry hints and flags for a window
2866  * based on the application set geometry, and requisiition
2867  * of the window. gtk_widget_size_request() must have been
2868  * called first.
2869  */
2870 static void
2871 gtk_window_compute_hints (GtkWindow   *window,
2872                           GdkGeometry *new_geometry,
2873                           guint       *new_flags)
2874 {
2875   GtkWidget *widget;
2876   GtkWidgetAuxInfo *aux_info;
2877   gint ux, uy;
2878   gint extra_width = 0;
2879   gint extra_height = 0;
2880   GtkWindowGeometryInfo *geometry_info;
2881   GtkRequisition requisition;
2882
2883   g_return_if_fail (GTK_IS_WINDOW (window));
2884
2885   widget = GTK_WIDGET (window);
2886   
2887   gtk_widget_get_child_requisition (widget, &requisition);
2888   geometry_info = gtk_window_get_geometry_info (GTK_WINDOW (widget), FALSE);
2889
2890   g_return_if_fail (geometry_info != NULL);
2891   
2892   *new_flags = geometry_info->mask;
2893   *new_geometry = geometry_info->geometry;
2894   
2895   if (geometry_info->widget)
2896     {
2897       extra_width = widget->requisition.width - geometry_info->widget->requisition.width;
2898       extra_height = widget->requisition.height - geometry_info->widget->requisition.height;
2899     }
2900   
2901   ux = 0;
2902   uy = 0;
2903   
2904   aux_info = _gtk_widget_get_aux_info (widget, FALSE);
2905   if (aux_info && aux_info->x_set && aux_info->y_set)
2906     {
2907       ux = aux_info->x;
2908       uy = aux_info->y;
2909       *new_flags |= GDK_HINT_POS;
2910     }
2911   
2912   if (*new_flags & GDK_HINT_BASE_SIZE)
2913     {
2914       new_geometry->base_width += extra_width;
2915       new_geometry->base_height += extra_height;
2916     }
2917   else if (!(*new_flags & GDK_HINT_MIN_SIZE) &&
2918            (*new_flags & GDK_HINT_RESIZE_INC) &&
2919            ((extra_width != 0) || (extra_height != 0)))
2920     {
2921       *new_flags |= GDK_HINT_BASE_SIZE;
2922       
2923       new_geometry->base_width = extra_width;
2924       new_geometry->base_height = extra_height;
2925     }
2926   
2927   if (*new_flags & GDK_HINT_MIN_SIZE)
2928     {
2929       if (new_geometry->min_width < 0)
2930         new_geometry->min_width = requisition.width;
2931       else
2932         new_geometry->min_width += extra_width;
2933
2934       if (new_geometry->min_height < 0)
2935         new_geometry->min_width = requisition.height;
2936       else
2937         new_geometry->min_height += extra_height;
2938     }
2939   else if (!window->allow_shrink)
2940     {
2941       *new_flags |= GDK_HINT_MIN_SIZE;
2942       
2943       new_geometry->min_width = requisition.width;
2944       new_geometry->min_height = requisition.height;
2945     }
2946   
2947   if (*new_flags & GDK_HINT_MAX_SIZE)
2948     {
2949       if (new_geometry->max_width < 0)
2950         new_geometry->max_width = requisition.width;
2951       else
2952         new_geometry->max_width += extra_width;
2953
2954       if (new_geometry->max_height < 0)
2955         new_geometry->max_width = requisition.height;
2956       else
2957         new_geometry->max_height += extra_height;
2958     }
2959   else if (!window->allow_grow)
2960     {
2961       *new_flags |= GDK_HINT_MAX_SIZE;
2962       
2963       new_geometry->max_width = requisition.width;
2964       new_geometry->max_height = requisition.height;
2965     }
2966
2967   *new_flags |= GDK_HINT_WIN_GRAVITY;
2968   new_geometry->win_gravity = window->gravity;
2969 }
2970
2971 /* Compute a new position for the window based on a new
2972  * size. *x and *y will be set to the new coordinates. Returns
2973  * TRUE if the window needs to be moved (and thus x and y got
2974  * assigned)
2975  */
2976 static gint
2977 gtk_window_compute_reposition (GtkWindow *window,
2978                                gint       new_width,
2979                                gint       new_height,
2980                                gint      *x,
2981                                gint      *y)
2982 {
2983   GtkWidget *widget = GTK_WIDGET (window);
2984   GtkWindowPosition pos;
2985   GtkWidget *parent_widget;
2986   gboolean needs_move = FALSE;
2987
2988   parent_widget = (GtkWidget*) window->transient_parent;
2989   
2990   pos = window->position;
2991   if (pos == GTK_WIN_POS_CENTER_ON_PARENT &&
2992       (parent_widget == NULL ||
2993        !GTK_WIDGET_MAPPED (parent_widget)))
2994     pos = GTK_WIN_POS_NONE;
2995   
2996   switch (pos)
2997   {
2998     case GTK_WIN_POS_CENTER:
2999     case GTK_WIN_POS_CENTER_ALWAYS:
3000       if (window->use_uposition)
3001         {
3002           gint screen_width = gdk_screen_width ();
3003           gint screen_height = gdk_screen_height ();
3004           
3005           *x = (screen_width - new_width) / 2;
3006           *y = (screen_height - new_height) / 2;
3007           needs_move = TRUE;
3008         }
3009       break;
3010
3011     case GTK_WIN_POS_CENTER_ON_PARENT:
3012       if (window->use_uposition)
3013         {
3014           gint ox, oy;
3015           gdk_window_get_origin (parent_widget->window,
3016                                    &ox, &oy);
3017                                  
3018           *x = ox + (parent_widget->allocation.width - new_width) / 2;
3019           *y = oy + (parent_widget->allocation.height - new_height) / 2;
3020           needs_move = TRUE;
3021         }
3022       break;
3023
3024     case GTK_WIN_POS_MOUSE:
3025       if (window->use_uposition)
3026         {
3027           gint screen_width = gdk_screen_width ();
3028           gint screen_height = gdk_screen_height ();
3029           
3030           gdk_window_get_pointer (NULL, x, y, NULL);
3031           *x -= new_width / 2;
3032           *y -= new_height / 2;
3033           *x = CLAMP (*x, 0, screen_width - new_width);
3034           *y = CLAMP (*y, 0, screen_height - new_height);
3035           needs_move = TRUE;
3036         }
3037       break;
3038     default:
3039       if (window->use_uposition)
3040         {
3041           GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (widget, FALSE);
3042
3043           if (aux_info && aux_info->x_set && aux_info->y_set)
3044             {
3045               *x = aux_info->x;
3046               *y = aux_info->y;
3047               needs_move = TRUE;
3048             }
3049         }
3050       break;
3051     }
3052
3053   if (needs_move)
3054     {
3055       GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (widget, TRUE);
3056
3057       /* we handle necessary window positioning by hand here,
3058        * so we can coalesce the window movement with possible
3059        * resizes to get only one configure event.
3060        */
3061       aux_info->x_set = TRUE;
3062       aux_info->y_set = TRUE;
3063       aux_info->x = *x;
3064       aux_info->y = *y;
3065       window->use_uposition = FALSE;
3066     }
3067
3068   return needs_move;
3069 }
3070
3071 /***********************
3072  * Redrawing functions *
3073  ***********************/
3074
3075 static void
3076 gtk_window_paint (GtkWidget     *widget,
3077                   GdkRectangle *area)
3078 {
3079   gtk_paint_flat_box (widget->style, widget->window, GTK_STATE_NORMAL, 
3080                       GTK_SHADOW_NONE, area, widget, "base", 0, 0, -1, -1);
3081 }
3082
3083 static gint
3084 gtk_window_expose (GtkWidget      *widget,
3085                    GdkEventExpose *event)
3086 {
3087   g_return_val_if_fail (widget != NULL, FALSE);
3088   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
3089   g_return_val_if_fail (event != NULL, FALSE);
3090
3091   if (!GTK_WIDGET_APP_PAINTABLE (widget))
3092     gtk_window_paint (widget, &event->area);
3093   
3094   if (GTK_WIDGET_CLASS (parent_class)->expose_event)
3095     return GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
3096
3097   return TRUE;
3098 }
3099
3100 /**
3101  * gtk_window_set_has_frame:
3102  * @window: a #GtkWindow
3103  * 
3104  * If this function is called on a window before it is realized
3105  * or showed it will have a "frame" window around widget-window,
3106  * accessible in window->frame. Using the signal frame_event
3107  * you can recieve all events targeted at the frame.
3108  * 
3109  * This function is used by the linux-fb port to implement managed
3110  * windows, but it could concievably be used by X-programs that
3111  * want to do their own window decorations.
3112  **/
3113 void
3114 gtk_window_set_has_frame (GtkWindow *window)
3115 {
3116   g_return_if_fail (window != NULL);
3117   g_return_if_fail (GTK_IS_WINDOW (window));
3118   g_return_if_fail (!GTK_WIDGET_REALIZED (window));
3119
3120   window->has_frame = TRUE;
3121 }
3122
3123 /**
3124  * gtk_window_set_frame_dimensions:
3125  * @window: a #GtkWindow that has a frame
3126  * @left: The width of the left border
3127  * @top: The height of the top border
3128  * @right: The width of the right border
3129  * @bottom: The height of the bottom border
3130  *
3131  * For windows with frames (see #gtk_window_set_has_frame) this function
3132  * can be used to change the size of the frame border.
3133  **/
3134 void
3135 gtk_window_set_frame_dimensions (GtkWindow *window, 
3136                                  gint       left,
3137                                  gint       top,
3138                                  gint       right,
3139                                  gint       bottom)
3140 {
3141   GtkWidget *widget = GTK_WIDGET (window);
3142
3143   g_return_if_fail (window != NULL);
3144   g_return_if_fail (GTK_IS_WINDOW (window));
3145
3146   if (window->frame_left == left &&
3147       window->frame_top == top &&
3148       window->frame_right == right && 
3149       window->frame_bottom == bottom)
3150     return;
3151
3152   window->frame_left = left;
3153   window->frame_top = top;
3154   window->frame_right = right;
3155   window->frame_bottom = bottom;
3156
3157   if (GTK_WIDGET_REALIZED (widget) && window->frame)
3158     {
3159       gint width = widget->allocation.width + left + right;
3160       gint height = widget->allocation.height + top + bottom;
3161       gdk_window_resize (window->frame, width, height);
3162       gtk_decorated_window_move_resize_window (window,
3163                                                left, top,
3164                                                widget->allocation.width,
3165                                                widget->allocation.height);
3166     }
3167 }
3168
3169
3170
3171 /**
3172  * gtk_window_present:
3173  * @window: a #GtkWindow
3174  *
3175  * Presents a window to the user. This may mean raising the window
3176  * in the stacking order, deiconifying it, moving it to the current
3177  * desktop, and/or giving it the keyboard focus, possibly dependent
3178  * on the user's platform, window manager, and preferences.
3179  *
3180  * If @window is hidden, this function calls gtk_widget_show()
3181  * as well.
3182  * 
3183  * This function should be used when the user tries to open a window
3184  * that's already open. Say for example the preferences dialog is
3185  * currently open, and the user chooses Preferences from the menu
3186  * a second time; use gtk_window_present() to move the already-open dialog
3187  * where the user can see it.
3188  * 
3189  **/
3190 void
3191 gtk_window_present (GtkWindow *window)
3192 {
3193   GtkWidget *widget;
3194
3195   g_return_if_fail (GTK_IS_WINDOW (window));
3196
3197   widget = GTK_WIDGET (window);
3198
3199   if (GTK_WIDGET_VISIBLE (window))
3200     {
3201       g_assert (widget->window != NULL);
3202       
3203       gdk_window_show (widget->window);
3204
3205       /* note that gdk_window_focus() will also move the window to
3206        * the current desktop, for WM spec compliant window managers.
3207        */
3208       gdk_window_focus (widget->window,
3209                         gtk_get_current_event_time ());
3210     }
3211   else
3212     {
3213       gtk_widget_show (widget);
3214     }
3215 }
3216
3217 /**
3218  * gtk_window_iconify:
3219  * @window: a #GtkWindow
3220  *
3221  * Asks to iconify @window. Note that you shouldn't assume the window
3222  * is definitely iconified afterward, because other entities (e.g. the
3223  * user or window manager) could deiconify it again, or there may not
3224  * be a window manager in which case iconification isn't possible,
3225  * etc. But normally the window will end up iconified. Just don't write
3226  * code that crashes if not.
3227  *
3228  * It's permitted to call this function before showing a window,
3229  * in which case the window will be iconified before it ever appears
3230  * onscreen.
3231  *
3232  * You can track iconification via the "window_state_event" signal
3233  * on #GtkWidget.
3234  * 
3235  **/
3236 void
3237 gtk_window_iconify (GtkWindow *window)
3238 {
3239   GtkWidget *widget;
3240   GdkWindow *toplevel;
3241   
3242   g_return_if_fail (GTK_IS_WINDOW (window));
3243
3244   widget = GTK_WIDGET (window);
3245
3246   window->iconify_initially = TRUE;
3247
3248   if (window->frame)
3249     toplevel = window->frame;
3250   else
3251     toplevel = widget->window;
3252   
3253   if (toplevel != NULL)
3254     gdk_window_iconify (toplevel);
3255 }
3256
3257 /**
3258  * gtk_window_deiconify:
3259  * @window: a #GtkWindow
3260  *
3261  * Asks to deiconify @window. Note that you shouldn't assume the
3262  * window is definitely deiconified afterward, because other entities
3263  * (e.g. the user or window manager) could iconify it again before
3264  * your code which assumes deiconification gets to run.
3265  *
3266  * You can track iconification via the "window_state_event" signal
3267  * on #GtkWidget.
3268  **/
3269 void
3270 gtk_window_deiconify (GtkWindow *window)
3271 {
3272   GtkWidget *widget;
3273   GdkWindow *toplevel;
3274   
3275   g_return_if_fail (GTK_IS_WINDOW (window));
3276
3277   widget = GTK_WIDGET (window);
3278
3279   window->iconify_initially = FALSE;
3280
3281   if (window->frame)
3282     toplevel = window->frame;
3283   else
3284     toplevel = widget->window;
3285   
3286   if (toplevel != NULL)
3287     gdk_window_deiconify (toplevel);
3288 }
3289
3290 /**
3291  * gtk_window_stick:
3292  * @window: a #GtkWindow
3293  *
3294  * Asks to stick @window, which means that it will appear on all user
3295  * desktops. Note that you shouldn't assume the window is definitely
3296  * stuck afterward, because other entities (e.g. the user or window
3297  * manager) could unstick it again, and some window managers do not
3298  * support sticking windows. But normally the window will end up
3299  * stuck. Just don't write code that crashes if not.
3300  *
3301  * It's permitted to call this function before showing a window.
3302  *
3303  * You can track stickiness via the "window_state_event" signal
3304  * on #GtkWidget.
3305  * 
3306  **/
3307 void
3308 gtk_window_stick (GtkWindow *window)
3309 {
3310   GtkWidget *widget;
3311   GdkWindow *toplevel;
3312   
3313   g_return_if_fail (GTK_IS_WINDOW (window));
3314
3315   widget = GTK_WIDGET (window);
3316
3317   window->stick_initially = TRUE;
3318
3319   if (window->frame)
3320     toplevel = window->frame;
3321   else
3322     toplevel = widget->window;
3323   
3324   if (toplevel != NULL)
3325     gdk_window_stick (toplevel);
3326 }
3327
3328 /**
3329  * gtk_window_unstick:
3330  * @window: a #GtkWindow
3331  *
3332  * Asks to unstick @window, which means that it will appear on only
3333  * one of the user's desktops. Note that you shouldn't assume the
3334  * window is definitely unstuck afterward, because other entities
3335  * (e.g. the user or window manager) could stick it again. But
3336  * normally the window will end up stuck. Just don't write code that
3337  * crashes if not.
3338  *
3339  * You can track stickiness via the "window_state_event" signal
3340  * on #GtkWidget.
3341  * 
3342  **/
3343 void
3344 gtk_window_unstick (GtkWindow *window)
3345 {
3346   GtkWidget *widget;
3347   GdkWindow *toplevel;
3348   
3349   g_return_if_fail (GTK_IS_WINDOW (window));
3350
3351   widget = GTK_WIDGET (window);
3352
3353   window->stick_initially = FALSE;
3354
3355   if (window->frame)
3356     toplevel = window->frame;
3357   else
3358     toplevel = widget->window;
3359   
3360   if (toplevel != NULL)
3361     gdk_window_unstick (toplevel);
3362 }
3363
3364 /**
3365  * gtk_window_maximize:
3366  * @window: a #GtkWindow
3367  *
3368  * Asks to maximize @window, so that it becomes full-screen. Note that
3369  * you shouldn't assume the window is definitely maximized afterward,
3370  * because other entities (e.g. the user or window manager) could
3371  * unmaximize it again, and not all window managers support
3372  * maximization. But normally the window will end up maximized. Just
3373  * don't write code that crashes if not.
3374  *
3375  * It's permitted to call this function before showing a window,
3376  * in which case the window will be maximized when it appears onscreen
3377  * initially.
3378  *
3379  * You can track maximization via the "window_state_event" signal
3380  * on #GtkWidget.
3381  * 
3382  **/
3383 void
3384 gtk_window_maximize (GtkWindow *window)
3385 {
3386   GtkWidget *widget;
3387   GdkWindow *toplevel;
3388   
3389   g_return_if_fail (GTK_IS_WINDOW (window));
3390
3391   widget = GTK_WIDGET (window);
3392
3393   window->maximize_initially = TRUE;
3394
3395   if (window->frame)
3396     toplevel = window->frame;
3397   else
3398     toplevel = widget->window;
3399   
3400   if (toplevel != NULL)
3401     gdk_window_maximize (toplevel);
3402 }
3403
3404 /**
3405  * gtk_window_unmaximize:
3406  * @window: a #GtkWindow
3407  *
3408  * Asks to unmaximize @window. Note that you shouldn't assume the
3409  * window is definitely unmaximized afterward, because other entities
3410  * (e.g. the user or window manager) could maximize it again, and not
3411  * all window managers honor requests to unmaximize. But normally the
3412  * window will end up unmaximized. Just don't write code that crashes
3413  * if not.
3414  *
3415  * You can track maximization via the "window_state_event" signal
3416  * on #GtkWidget.
3417  * 
3418  **/
3419 void
3420 gtk_window_unmaximize (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->maximize_initially = FALSE;
3430
3431   if (window->frame)
3432     toplevel = window->frame;
3433   else
3434     toplevel = widget->window;
3435   
3436   if (toplevel != NULL)
3437     gdk_window_unmaximize (toplevel);
3438 }
3439
3440 /**
3441  * gtk_window_set_resizeable:
3442  * @window: a #GtkWindow
3443  * @resizeable: %TRUE if the user can resize this window
3444  *
3445  * Sets whether the user can resize a window. Windows are user resizeable
3446  * by default.
3447  **/
3448 void
3449 gtk_window_set_resizeable (GtkWindow *window,
3450                            gboolean   resizeable)
3451 {
3452   g_return_if_fail (GTK_IS_WINDOW (window));
3453
3454   gtk_window_set_policy (window, FALSE, resizeable, FALSE);
3455 }
3456
3457 /**
3458  * gtk_window_get_resizeable:
3459  * @window: a #GtkWindow
3460  *
3461  * Gets the value set by gtk_window_set_resizeable().
3462  *
3463  * Return value: %TRUE if the user can resize the window
3464  **/
3465 gboolean
3466 gtk_window_get_resizeable (GtkWindow *window)
3467 {
3468   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
3469
3470   /* allow_grow is most likely to indicate the semantic concept we
3471    * mean by "resizeable" (and will be a reliable indicator if
3472    * set_policy() hasn't been called)
3473    */
3474   return window->allow_grow;
3475 }
3476
3477 /**
3478  * gtk_window_set_gravity:
3479  * @window: a #GtkWindow
3480  * @gravity: window gravity
3481  *
3482  * Window gravity defines the "reference point" to be used when
3483  * positioning or resizing a window. Calls to
3484  * gtk_widget_set_uposition() will position a different point on the
3485  * window depending on the window gravity. When the window changes size
3486  * the reference point determined by the window's gravity will stay in
3487  * a fixed location.
3488  *
3489  * See #GdkGravity for full details. To briefly summarize,
3490  * #GDK_GRAVITY_NORTH_WEST means that the reference point is the
3491  * northwest (top left) corner of the window
3492  * frame. #GDK_GRAVITY_SOUTH_EAST would be the bottom right corner of
3493  * the frame, and so on. If you want to position the window contents,
3494  * rather than the window manager's frame, #GDK_GRAVITY_STATIC moves
3495  * the reference point to the northwest corner of the #GtkWindow
3496  * itself.
3497  *
3498  * The default window gravity is #GDK_GRAVITY_NORTH_WEST.
3499  *
3500  **/
3501 void
3502 gtk_window_set_gravity (GtkWindow *window,
3503                         GdkGravity gravity)
3504 {
3505   g_return_if_fail (GTK_IS_WINDOW (window));
3506
3507   if (gravity != window->gravity)
3508     {
3509       window->gravity = gravity;
3510
3511       /* gtk_window_move_resize() will adapt gravity
3512        */
3513       gtk_widget_queue_resize (GTK_WIDGET (window));
3514     }
3515 }
3516
3517 /**
3518  * gtk_window_get_gravity:
3519  * @window: a #GtkWindow
3520  *
3521  * Gets the value set by gtk_window_set_gravity().
3522  *
3523  * Return value: window gravity
3524  **/
3525 GdkGravity
3526 gtk_window_get_gravity (GtkWindow *window)
3527 {
3528   g_return_val_if_fail (GTK_IS_WINDOW (window), 0);
3529
3530   return window->gravity;
3531 }
3532
3533 /**
3534  * gtk_window_begin_resize_drag:
3535  * @window: a #GtkWindow
3536  * @button: mouse button that initiated the drag
3537  * @edge: position of the resize control
3538  * @root_x: X position where the user clicked to initiate the drag, in root window coordinates
3539  * @root_y: Y position where the user clicked to initiate the drag
3540  * @timestamp: timestamp from the click event that initiated the drag
3541  *
3542  * Starts resizing a window. This function is used if an application
3543  * has window resizing controls. When GDK can support it, the resize
3544  * will be done using the standard mechanism for the window manager or
3545  * windowing system. Otherwise, GDK will try to emulate window
3546  * resizing, potentially not all that well, depending on the windowing system.
3547  * 
3548  **/
3549 void
3550 gtk_window_begin_resize_drag  (GtkWindow    *window,
3551                                GdkWindowEdge edge,
3552                                gint          button,
3553                                gint          root_x,
3554                                gint          root_y,
3555                                guint32       timestamp)
3556 {
3557   GtkWidget *widget;
3558   GdkWindow *toplevel;
3559   
3560   g_return_if_fail (GTK_IS_WINDOW (window));
3561   g_return_if_fail (GTK_WIDGET_VISIBLE (window));
3562   
3563   widget = GTK_WIDGET (window);
3564   
3565   if (window->frame)
3566     toplevel = window->frame;
3567   else
3568     toplevel = widget->window;
3569   
3570   gdk_window_begin_resize_drag (toplevel,
3571                                 edge, button,
3572                                 root_x, root_y,
3573                                 timestamp);
3574 }
3575
3576
3577 /**
3578  * gtk_window_begin_move_drag:
3579  * @window: a #GtkWindow
3580  * @button: mouse button that initiated the drag
3581  * @root_x: X position where the user clicked to initiate the drag, in root window coordinates
3582  * @root_y: Y position where the user clicked to initiate the drag
3583  * @timestamp: timestamp from the click event that initiated the drag
3584  *
3585  * Starts moving a window. This function is used if an application
3586  * has window movement grips. When GDK can support it, the window movement
3587  * will be done using the standard mechanism for the window manager or
3588  * windowing system. Otherwise, GDK will try to emulate window
3589  * movement, potentially not all that well, depending on the windowing system.
3590  * 
3591  **/
3592 void
3593 gtk_window_begin_move_drag  (GtkWindow *window,
3594                              gint       button,
3595                              gint       root_x,
3596                              gint       root_y,
3597                              guint32    timestamp)
3598 {
3599   GtkWidget *widget;
3600   GdkWindow *toplevel;
3601   
3602   g_return_if_fail (GTK_IS_WINDOW (window));
3603   g_return_if_fail (GTK_WIDGET_VISIBLE (window));
3604   
3605   widget = GTK_WIDGET (window);
3606   
3607   if (window->frame)
3608     toplevel = window->frame;
3609   else
3610     toplevel = widget->window;
3611   
3612   gdk_window_begin_move_drag (toplevel,
3613                               button,
3614                               root_x, root_y,
3615                               timestamp);
3616 }