]> Pileus Git - ~andy/gtk/blob - gtk/gtkwindow.c
fix g_object_notify
[~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   /* Normal Props */
68   PROP_TITLE,
69   PROP_ALLOW_SHRINK,
70   PROP_ALLOW_GROW,
71   PROP_RESIZABLE,
72   PROP_MODAL,
73   PROP_WIN_POS,
74   PROP_DEFAULT_WIDTH,
75   PROP_DEFAULT_HEIGHT,
76   PROP_DESTROY_WITH_PARENT,
77   PROP_ICON,
78   
79   LAST_ARG
80 };
81
82 typedef struct
83 {
84   GList     *icon_list;
85   GdkPixmap *icon_pixmap;
86   GdkPixmap *icon_mask;
87   guint      realized : 1;
88   guint      using_default_icon : 1;
89   guint      using_parent_icon : 1;
90 } GtkWindowIconInfo;
91
92 typedef struct {
93   GdkGeometry    geometry; /* Last set of geometry hints we set */
94   GdkWindowHints flags;
95   GdkRectangle   configure_request;
96 } GtkWindowLastGeometryInfo;
97
98 struct _GtkWindowGeometryInfo
99 {
100   /* Properties that the app has set on the window
101    */
102   GdkGeometry    geometry;      /* Geometry hints */
103   GdkWindowHints mask;
104   GtkWidget     *widget;        /* subwidget to which hints apply */
105   /* from last gtk_window_resize () - if > 0, indicates that
106    * we should resize to this size.
107    */
108   gint           resize_width;  
109   gint           resize_height;
110
111   /* From last gtk_window_move () prior to mapping -
112    * only used if initial_pos_set
113    */
114   gint           initial_x;
115   gint           initial_y;
116   
117   /* Default size - used only the FIRST time we map a window,
118    * only if > 0.
119    */
120   gint           default_width; 
121   gint           default_height;
122   /* whether to use initial_x, initial_y */
123   guint          initial_pos_set : 1;
124   /* CENTER_ALWAYS or other position constraint changed since
125    * we sent the last configure request.
126    */
127   guint          position_constraints_changed : 1;
128   
129   GtkWindowLastGeometryInfo last;
130 };
131
132 typedef struct {
133   GtkWindow *window;
134   guint keyval;
135
136   GSList *targets;
137 } GtkWindowMnemonic;
138
139
140 static void gtk_window_class_init         (GtkWindowClass    *klass);
141 static void gtk_window_init               (GtkWindow         *window);
142 static void gtk_window_dispose            (GObject           *object);
143 static void gtk_window_destroy            (GtkObject         *object);
144 static void gtk_window_finalize           (GObject           *object);
145 static void gtk_window_show               (GtkWidget         *widget);
146 static void gtk_window_hide               (GtkWidget         *widget);
147 static void gtk_window_map                (GtkWidget         *widget);
148 static void gtk_window_unmap              (GtkWidget         *widget);
149 static void gtk_window_realize            (GtkWidget         *widget);
150 static void gtk_window_unrealize          (GtkWidget         *widget);
151 static void gtk_window_size_request       (GtkWidget         *widget,
152                                            GtkRequisition    *requisition);
153 static void gtk_window_size_allocate      (GtkWidget         *widget,
154                                            GtkAllocation     *allocation);
155 static gint gtk_window_event              (GtkWidget *widget,
156                                            GdkEvent *event);
157 static gboolean gtk_window_frame_event    (GtkWidget *widget,
158                                            GdkEvent *event);
159 static gint gtk_window_configure_event    (GtkWidget         *widget,
160                                            GdkEventConfigure *event);
161 static gint gtk_window_key_press_event    (GtkWidget         *widget,
162                                            GdkEventKey       *event);
163 static gint gtk_window_key_release_event  (GtkWidget         *widget,
164                                            GdkEventKey       *event);
165 static gint gtk_window_enter_notify_event (GtkWidget         *widget,
166                                            GdkEventCrossing  *event);
167 static gint gtk_window_leave_notify_event (GtkWidget         *widget,
168                                            GdkEventCrossing  *event);
169 static gint gtk_window_focus_in_event     (GtkWidget         *widget,
170                                            GdkEventFocus     *event);
171 static gint gtk_window_focus_out_event    (GtkWidget         *widget,
172                                            GdkEventFocus     *event);
173 static gint gtk_window_client_event       (GtkWidget         *widget,
174                                            GdkEventClient    *event);
175 static void gtk_window_check_resize       (GtkContainer      *container);
176 static gint gtk_window_focus              (GtkWidget        *widget,
177                                            GtkDirectionType  direction);
178 static void gtk_window_real_set_focus     (GtkWindow         *window,
179                                            GtkWidget         *focus);
180
181 static void gtk_window_real_activate_default (GtkWindow         *window);
182 static void gtk_window_real_activate_focus   (GtkWindow         *window);
183 static void gtk_window_move_focus            (GtkWindow         *window,
184                                               GtkDirectionType   dir);
185 static void gtk_window_read_rcfiles       (GtkWidget         *widget,
186                                            GdkEventClient    *event);
187 static void gtk_window_paint              (GtkWidget         *widget,
188                                            GdkRectangle      *area);
189 static gint gtk_window_expose             (GtkWidget         *widget,
190                                            GdkEventExpose    *event);
191 static void gtk_window_unset_transient_for         (GtkWindow  *window);
192 static void gtk_window_transient_parent_realized   (GtkWidget  *parent,
193                                                     GtkWidget  *window);
194 static void gtk_window_transient_parent_unrealized (GtkWidget  *parent,
195                                                     GtkWidget  *window);
196
197 static GtkWindowGeometryInfo* gtk_window_get_geometry_info         (GtkWindow    *window,
198                                                                     gboolean      create);
199
200 static void     gtk_window_move_resize               (GtkWindow    *window);
201 static gboolean gtk_window_compare_hints             (GdkGeometry  *geometry_a,
202                                                       guint         flags_a,
203                                                       GdkGeometry  *geometry_b,
204                                                       guint         flags_b);
205 static void     gtk_window_constrain_size            (GtkWindow    *window,
206                                                       GdkGeometry  *geometry,
207                                                       guint         flags,
208                                                       gint          width,
209                                                       gint          height,
210                                                       gint         *new_width,
211                                                       gint         *new_height);
212 static void     gtk_window_constrain_position        (GtkWindow    *window,
213                                                       gint          new_width,
214                                                       gint          new_height,
215                                                       gint         *x,
216                                                       gint         *y);
217 static void     gtk_window_compute_hints             (GtkWindow    *window,
218                                                       GdkGeometry  *new_geometry,
219                                                       guint        *new_flags);
220 static void     gtk_window_compute_configure_request (GtkWindow    *window,
221                                                       GdkRectangle *request,
222                                                       GdkGeometry  *geometry,
223                                                       guint        *flags);
224
225 static void     gtk_window_set_default_size_internal (GtkWindow    *window,
226                                                       gboolean      change_width,
227                                                       gint          width,
228                                                       gboolean      change_height,
229                                                       gint          height);
230
231 static void     gtk_window_realize_icon               (GtkWindow    *window);
232 static void     gtk_window_unrealize_icon             (GtkWindow    *window);
233
234 static GSList      *toplevel_list = NULL;
235 static GHashTable  *mnemonic_hash_table = NULL;
236 static GtkBinClass *parent_class = NULL;
237 static guint        window_signals[LAST_SIGNAL] = { 0 };
238 static GList       *default_icon_list = NULL;
239 /* FIXME need to be per-screen */
240 static GdkPixmap   *default_icon_pixmap = NULL;
241 static GdkPixmap   *default_icon_mask = NULL;
242
243 static void gtk_window_set_property (GObject         *object,
244                                      guint            prop_id,
245                                      const GValue    *value,
246                                      GParamSpec      *pspec);
247 static void gtk_window_get_property (GObject         *object,
248                                      guint            prop_id,
249                                      GValue          *value,
250                                      GParamSpec      *pspec);
251
252
253 static guint
254 mnemonic_hash (gconstpointer key)
255 {
256   const GtkWindowMnemonic *k;
257   guint h;
258   
259   k = (GtkWindowMnemonic *)key;
260   
261   h = (gulong) k->window;
262   h ^= k->keyval << 16;
263   h ^= k->keyval >> 16;
264
265   return h;
266 }
267
268 static gboolean
269 mnemonic_equal (gconstpointer a, gconstpointer b)
270 {
271   const GtkWindowMnemonic *ka;
272   const GtkWindowMnemonic *kb;
273   
274   ka = (GtkWindowMnemonic *)a;
275   kb = (GtkWindowMnemonic *)b;
276
277   return
278     (ka->window == kb->window) &&
279     (ka->keyval == kb->keyval);
280 }
281
282 GtkType
283 gtk_window_get_type (void)
284 {
285   static GtkType window_type = 0;
286
287   if (!window_type)
288     {
289       static const GtkTypeInfo window_info =
290       {
291         "GtkWindow",
292         sizeof (GtkWindow),
293         sizeof (GtkWindowClass),
294         (GtkClassInitFunc) gtk_window_class_init,
295         (GtkObjectInitFunc) gtk_window_init,
296         /* reserved_1 */ NULL,
297         /* reserved_2 */ NULL,
298         (GtkClassInitFunc) NULL,
299       };
300
301       window_type = gtk_type_unique (gtk_bin_get_type (), &window_info);
302     }
303
304   return window_type;
305 }
306
307 static void
308 gtk_window_class_init (GtkWindowClass *klass)
309 {
310   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
311   GtkObjectClass *object_class;
312   GtkWidgetClass *widget_class;
313   GtkContainerClass *container_class;
314   GtkBindingSet *binding_set;
315   
316   object_class = (GtkObjectClass*) klass;
317   widget_class = (GtkWidgetClass*) klass;
318   container_class = (GtkContainerClass*) klass;
319   
320   parent_class = gtk_type_class (gtk_bin_get_type ());
321
322   gobject_class->dispose = gtk_window_dispose;
323   gobject_class->finalize = gtk_window_finalize;
324
325   gobject_class->set_property = gtk_window_set_property;
326   gobject_class->get_property = gtk_window_get_property;
327   
328   object_class->destroy = gtk_window_destroy;
329
330   widget_class->show = gtk_window_show;
331   widget_class->hide = gtk_window_hide;
332   widget_class->map = gtk_window_map;
333   widget_class->unmap = gtk_window_unmap;
334   widget_class->realize = gtk_window_realize;
335   widget_class->unrealize = gtk_window_unrealize;
336   widget_class->size_request = gtk_window_size_request;
337   widget_class->size_allocate = gtk_window_size_allocate;
338   widget_class->configure_event = gtk_window_configure_event;
339   widget_class->key_press_event = gtk_window_key_press_event;
340   widget_class->key_release_event = gtk_window_key_release_event;
341   widget_class->enter_notify_event = gtk_window_enter_notify_event;
342   widget_class->leave_notify_event = gtk_window_leave_notify_event;
343   widget_class->focus_in_event = gtk_window_focus_in_event;
344   widget_class->focus_out_event = gtk_window_focus_out_event;
345   widget_class->client_event = gtk_window_client_event;
346   widget_class->focus = gtk_window_focus;
347   
348   widget_class->expose_event = gtk_window_expose;
349    
350   container_class->check_resize = gtk_window_check_resize;
351
352   klass->set_focus = gtk_window_real_set_focus;
353   klass->frame_event = gtk_window_frame_event;
354
355   klass->activate_default = gtk_window_real_activate_default;
356   klass->activate_focus = gtk_window_real_activate_focus;
357   klass->move_focus = gtk_window_move_focus;
358   
359   /* Construct */
360   g_object_class_install_property (gobject_class,
361                                    PROP_TYPE,
362                                    g_param_spec_enum ("type",
363                                                       _("Window Type"),
364                                                       _("The type of the window"),
365                                                       GTK_TYPE_WINDOW_TYPE,
366                                                       GTK_WINDOW_TOPLEVEL,
367                                                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
368
369   /* Regular Props */
370   g_object_class_install_property (gobject_class,
371                                    PROP_TITLE,
372                                    g_param_spec_string ("title",
373                                                         _("Window Title"),
374                                                         _("The title of the window"),
375                                                         NULL,
376                                                         G_PARAM_READWRITE));
377
378   g_object_class_install_property (gobject_class,
379                                    PROP_ALLOW_SHRINK,
380                                    g_param_spec_boolean ("allow_shrink",
381                                                          _("Allow Shrink"),
382                                                          _("If TRUE, the window has no mimimum size. Setting this to TRUE is 99% of the time a bad idea."),
383                                                          FALSE,
384                                                          G_PARAM_READWRITE));
385
386   g_object_class_install_property (gobject_class,
387                                    PROP_ALLOW_GROW,
388                                    g_param_spec_boolean ("allow_grow",
389                                                          _("Allow Grow"),
390                                                          _("If TRUE, users can expand the window beyond its minimum size."),
391                                                          TRUE,
392                                                          G_PARAM_READWRITE));
393
394   g_object_class_install_property (gobject_class,
395                                    PROP_RESIZABLE,
396                                    g_param_spec_boolean ("resizable",
397                                                          _("Resizable"),
398                                                          _("If TRUE, users can resize the window."),
399                                                          TRUE,
400                                                          G_PARAM_READWRITE));
401   
402   g_object_class_install_property (gobject_class,
403                                    PROP_MODAL,
404                                    g_param_spec_boolean ("modal",
405                                                          _("Modal"),
406                                                          _("If TRUE, the window is modal (other windows are not usable while this one is up)."),
407                                                          FALSE,
408                                                          G_PARAM_READWRITE));
409
410   g_object_class_install_property (gobject_class,
411                                    PROP_WIN_POS,
412                                    g_param_spec_enum ("window_position",
413                                                       _("Window Position"),
414                                                       _("The initial position of the window."),
415                                                       GTK_TYPE_WINDOW_POSITION,
416                                                       GTK_WIN_POS_NONE,
417                                                       G_PARAM_READWRITE));
418  
419   g_object_class_install_property (gobject_class,
420                                    PROP_DEFAULT_WIDTH,
421                                    g_param_spec_int ("default_width",
422                                                      _("Default Width"),
423                                                      _("The default width of the window, used when initially showing the window."),
424                                                      -1,
425                                                      G_MAXINT,
426                                                      -1,
427                                                      G_PARAM_READWRITE));
428   
429   g_object_class_install_property (gobject_class,
430                                    PROP_DEFAULT_HEIGHT,
431                                    g_param_spec_int ("default_height",
432                                                      _("Default Height"),
433                                                      _("The default height of the window, used when initially showing the window."),
434                                                      -1,
435                                                      G_MAXINT,
436                                                      -1,
437                                                      G_PARAM_READWRITE));
438   
439   g_object_class_install_property (gobject_class,
440                                    PROP_DESTROY_WITH_PARENT,
441                                    g_param_spec_boolean ("destroy_with_parent",
442                                                          _("Destroy with Parent"),
443                                                          _("If this window should be destroyed when the parent is destroyed"),
444                                                          FALSE,
445                                                          G_PARAM_READWRITE));
446
447   g_object_class_install_property (gobject_class,
448                                    PROP_ICON,
449                                    g_param_spec_object ("icon",
450                                                         _("Icon"),
451                                                         _("Icon for this window"),
452                                                         GDK_TYPE_PIXBUF,
453                                                         G_PARAM_READWRITE));
454   
455   window_signals[SET_FOCUS] =
456     g_signal_new ("set_focus",
457                   G_TYPE_FROM_CLASS (object_class),
458                   G_SIGNAL_RUN_LAST,
459                   G_STRUCT_OFFSET (GtkWindowClass, set_focus),
460                   NULL, NULL,
461                   gtk_marshal_VOID__OBJECT,
462                   G_TYPE_NONE, 1,
463                   GTK_TYPE_WIDGET);
464   
465   window_signals[FRAME_EVENT] =
466     g_signal_new ("frame_event",
467                   G_TYPE_FROM_CLASS(object_class),
468                   G_SIGNAL_RUN_LAST,
469                   G_STRUCT_OFFSET(GtkWindowClass, frame_event),
470                   _gtk_boolean_handled_accumulator, NULL,
471                   gtk_marshal_BOOLEAN__BOXED,
472                   G_TYPE_BOOLEAN, 1,
473                   GDK_TYPE_EVENT);
474
475   window_signals[ACTIVATE_FOCUS] =
476     g_signal_new ("activate_focus",
477                   G_OBJECT_CLASS_TYPE (object_class),
478                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
479                   GTK_SIGNAL_OFFSET (GtkWindowClass, activate_focus),
480                   NULL, NULL,
481                   gtk_marshal_VOID__VOID,
482                   G_TYPE_NONE,
483                   0);
484
485   window_signals[ACTIVATE_DEFAULT] =
486     g_signal_new ("activate_default",
487                   G_OBJECT_CLASS_TYPE (object_class),
488                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
489                   GTK_SIGNAL_OFFSET (GtkWindowClass, activate_default),
490                   NULL, NULL,
491                   gtk_marshal_VOID__VOID,
492                   G_TYPE_NONE,
493                   0);
494
495   window_signals[MOVE_FOCUS] =
496     g_signal_new ("move_focus",
497                   G_OBJECT_CLASS_TYPE (object_class),
498                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
499                   GTK_SIGNAL_OFFSET (GtkWindowClass, move_focus),
500                   NULL, NULL,
501                   gtk_marshal_VOID__ENUM,
502                   G_TYPE_NONE,
503                   1,
504                   GTK_TYPE_DIRECTION_TYPE);
505   
506   if (!mnemonic_hash_table)
507     mnemonic_hash_table = g_hash_table_new (mnemonic_hash,
508                                             mnemonic_equal);
509
510   /*
511    * Key bindings
512    */
513
514   binding_set = gtk_binding_set_by_class (klass);
515
516   gtk_binding_entry_add_signal (binding_set, GDK_space, 0,
517                                 "activate_focus", 0);
518   gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, 0,
519                                 "activate_focus", 0);
520   
521   gtk_binding_entry_add_signal (binding_set, GDK_Return, 0,
522                                 "activate_default", 0);
523
524   gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0,
525                                 "activate_default", 0);
526
527   gtk_binding_entry_add_signal (binding_set, GDK_Up, 0,
528                                 "move_focus", 1,
529                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_UP);
530   gtk_binding_entry_add_signal (binding_set, GDK_KP_Up, 0,
531                                 "move_focus", 1,
532                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_UP);
533
534   gtk_binding_entry_add_signal (binding_set, GDK_Down, 0,
535                                 "move_focus", 1,
536                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_DOWN);
537   gtk_binding_entry_add_signal (binding_set, GDK_KP_Down, 0,
538                                 "move_focus", 1,
539                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_DOWN);
540
541   gtk_binding_entry_add_signal (binding_set, GDK_Left, 0,
542                                 "move_focus", 1,
543                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_LEFT);
544   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0,
545                                 "move_focus", 1,
546                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_LEFT);  
547
548   gtk_binding_entry_add_signal (binding_set, GDK_Right, 0,
549                                 "move_focus", 1,
550                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_RIGHT);
551   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0,
552                                 "move_focus", 1,
553                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_RIGHT);  
554
555   gtk_binding_entry_add_signal (binding_set, GDK_Tab, 0,
556                                 "move_focus", 1,
557                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_FORWARD);
558   gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, 0,
559                                 "move_focus", 1,
560                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_FORWARD);
561   gtk_binding_entry_add_signal (binding_set, GDK_ISO_Left_Tab, 0,
562                                 "move_focus", 1,
563                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_FORWARD);
564
565   gtk_binding_entry_add_signal (binding_set, GDK_Tab, GDK_SHIFT_MASK,
566                                 "move_focus", 1,
567                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_BACKWARD);
568   gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, GDK_SHIFT_MASK,
569                                 "move_focus", 1,
570                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_BACKWARD);
571   gtk_binding_entry_add_signal (binding_set, GDK_ISO_Left_Tab, GDK_SHIFT_MASK,
572                                 "move_focus", 1,
573                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_BACKWARD);
574 }
575
576 static void
577 gtk_window_init (GtkWindow *window)
578 {
579   GTK_WIDGET_UNSET_FLAGS (window, GTK_NO_WINDOW);
580   GTK_WIDGET_SET_FLAGS (window, GTK_TOPLEVEL);
581
582   GTK_PRIVATE_SET_FLAG (window, GTK_ANCHORED);
583
584   gtk_container_set_resize_mode (GTK_CONTAINER (window), GTK_RESIZE_QUEUE);
585
586   window->title = NULL;
587   window->wmclass_name = g_strdup (g_get_prgname ());
588   window->wmclass_class = g_strdup (gdk_progclass);
589   window->wm_role = NULL;
590   window->geometry_info = NULL;
591   window->type = GTK_WINDOW_TOPLEVEL;
592   window->focus_widget = NULL;
593   window->default_widget = NULL;
594   window->configure_request_count = 0;
595   window->allow_shrink = FALSE;
596   window->allow_grow = TRUE;
597   window->configure_notify_received = FALSE;
598   window->position = GTK_WIN_POS_NONE;
599   window->need_default_size = TRUE;
600   window->need_default_position = TRUE;
601   window->modal = FALSE;
602   window->frame = NULL;
603   window->has_frame = FALSE;
604   window->frame_left = 0;
605   window->frame_right = 0;
606   window->frame_top = 0;
607   window->frame_bottom = 0;
608   window->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
609   window->gravity = GDK_GRAVITY_NORTH_WEST;
610   window->decorated = TRUE;
611   window->mnemonic_modifier = GDK_MOD1_MASK;
612   
613   gtk_widget_ref (GTK_WIDGET (window));
614   gtk_object_sink (GTK_OBJECT (window));
615   window->has_user_ref_count = TRUE;
616   toplevel_list = g_slist_prepend (toplevel_list, window);
617
618   gtk_decorated_window_init (window);
619
620   gtk_signal_connect (GTK_OBJECT (window),
621                       "event",
622                       GTK_SIGNAL_FUNC (gtk_window_event),
623                       NULL);
624 }
625
626 static void
627 gtk_window_set_property (GObject      *object,
628                          guint         prop_id,
629                          const GValue *value,
630                          GParamSpec   *pspec)
631 {
632   GtkWindow  *window;
633   
634   window = GTK_WINDOW (object);
635
636   switch (prop_id)
637     {
638     case PROP_TYPE:
639       window->type = g_value_get_enum (value);
640       break;
641     case PROP_TITLE:
642       gtk_window_set_title (window, g_value_get_string (value));
643       break;
644     case PROP_ALLOW_SHRINK:
645       window->allow_shrink = g_value_get_boolean (value);
646       gtk_widget_queue_resize (GTK_WIDGET (window));
647       break;
648     case PROP_ALLOW_GROW:
649       window->allow_grow = g_value_get_boolean (value);
650       gtk_widget_queue_resize (GTK_WIDGET (window));
651       g_object_notify (G_OBJECT (window), "resizable");
652       break;
653     case PROP_RESIZABLE:
654       window->allow_grow = g_value_get_boolean (value);
655       gtk_widget_queue_resize (GTK_WIDGET (window));
656       g_object_notify (G_OBJECT (window), "allow_grow");
657       break;
658     case PROP_MODAL:
659       gtk_window_set_modal (window, g_value_get_boolean (value));
660       break;
661     case PROP_WIN_POS:
662       gtk_window_set_position (window, g_value_get_enum (value));
663       break;
664     case PROP_DEFAULT_WIDTH:
665       gtk_window_set_default_size_internal (window,
666                                             TRUE, g_value_get_int (value),
667                                             FALSE, -1);
668       break;
669     case PROP_DEFAULT_HEIGHT:
670       gtk_window_set_default_size_internal (window,
671                                             FALSE, -1,
672                                             TRUE, g_value_get_int (value));
673       break;
674     case PROP_DESTROY_WITH_PARENT:
675       gtk_window_set_destroy_with_parent (window, g_value_get_boolean (value));
676       break;
677     case PROP_ICON:
678       gtk_window_set_icon (window,
679                            g_value_get_object (value));
680       break;
681
682     default:
683       break;
684     }
685 }
686
687 static void
688 gtk_window_get_property (GObject      *object,
689                          guint         prop_id,
690                          GValue       *value,
691                          GParamSpec   *pspec)
692 {
693   GtkWindow  *window;
694
695   window = GTK_WINDOW (object);
696
697   switch (prop_id)
698     {
699       GtkWindowGeometryInfo *info;
700     case PROP_TYPE:
701       g_value_set_enum (value, window->type);
702       break;
703     case PROP_TITLE:
704       g_value_set_string (value, window->title);
705       break;
706     case PROP_ALLOW_SHRINK:
707       g_value_set_boolean (value, window->allow_shrink);
708       break;
709     case PROP_ALLOW_GROW:
710       g_value_set_boolean (value, window->allow_grow);
711       break;
712     case PROP_RESIZABLE:
713       g_value_set_boolean (value, window->allow_grow);
714       break;
715     case PROP_MODAL:
716       g_value_set_boolean (value, window->modal);
717       break;
718     case PROP_WIN_POS:
719       g_value_set_enum (value, window->position);
720       break;
721     case PROP_DEFAULT_WIDTH:
722       info = gtk_window_get_geometry_info (window, FALSE);
723       if (!info)
724         g_value_set_int (value, -1);
725       else
726         g_value_set_int (value, info->default_width);
727       break;
728     case PROP_DEFAULT_HEIGHT:
729       info = gtk_window_get_geometry_info (window, FALSE);
730       if (!info)
731         g_value_set_int (value, -1);
732       else
733         g_value_set_int (value, info->default_height);
734       break;
735     case PROP_DESTROY_WITH_PARENT:
736       g_value_set_boolean (value, window->destroy_with_parent);
737       break;
738     case PROP_ICON:
739       g_value_set_object (value,
740                           G_OBJECT (gtk_window_get_icon (window)));
741       break;
742     default:
743       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
744       break;
745     }
746 }
747
748 /**
749  * gtk_window_new:
750  * @type: type of window
751  * 
752  * Creates a new #GtkWindow, which is a toplevel window that can
753  * contain other widgets. Nearly always, the type of the window should
754  * be #GTK_WINDOW_TOPLEVEL. If you're implementing something like a
755  * popup menu from scratch (which is a bad idea, just use #GtkMenu),
756  * you might use #GTK_WINDOW_POPUP. #GTK_WINDOW_POPUP is not for
757  * dialogs, though in some other toolkits dialogs are called "popups."
758  * In GTK+, #GTK_WINDOW_POPUP means a pop-up menu or pop-up tooltip.
759  * Popup windows are not controlled by the window manager.
760  *
761  * If you simply want an undecorated window (no window borders), use
762  * gtk_window_set_decorated(), don't use #GTK_WINDOW_POPUP.
763  * 
764  * Return value: a new #GtkWindow.
765  **/
766 GtkWidget*
767 gtk_window_new (GtkWindowType type)
768 {
769   GtkWindow *window;
770
771   g_return_val_if_fail (type >= GTK_WINDOW_TOPLEVEL && type <= GTK_WINDOW_POPUP, NULL);
772
773   window = gtk_type_new (GTK_TYPE_WINDOW);
774
775   window->type = type;
776
777   return GTK_WIDGET (window);
778 }
779
780 /**
781  * gtk_window_set_title:
782  * @window: a #GtkWindow
783  * @title: title of the window
784  * 
785  * Sets the title of the #GtkWindow. The title of a window will be displayed in
786  * its title bar; on the X Window System, the title bar is rendered by the
787  * window manager, so exactly how the title appears to users may vary according
788  * to a user's exact configuration. The title should help a user distinguish
789  * this window from other windows they may have open. A good title might
790  * include the application name and current document filename, for example.
791  * 
792  **/
793 void
794 gtk_window_set_title (GtkWindow   *window,
795                       const gchar *title)
796 {
797   g_return_if_fail (GTK_IS_WINDOW (window));
798
799   if (window->title)
800     g_free (window->title);
801   window->title = g_strdup (title);
802
803   if (GTK_WIDGET_REALIZED (window))
804     {
805       gdk_window_set_title (GTK_WIDGET (window)->window, window->title);
806
807       gtk_decorated_window_set_title (window, title);
808     }
809
810   g_object_notify (G_OBJECT (window), "title");
811 }
812
813 /**
814  * gtk_window_get_title:
815  * @window: a #GtkWindow
816  *
817  * Retrieves the title of the window. See gtk_window_set_title().
818  *
819  * Return value: the title of the window, or %NULL if none has
820  *    been set explicitely. The returned string is owned by the widget
821  *    and must not be modified or freed.
822  **/
823 G_CONST_RETURN gchar *
824 gtk_window_get_title (GtkWindow *window)
825 {
826   g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
827
828   return window->title;
829 }
830
831 /**
832  * gtk_window_set_wmclass:
833  * @window: a #GtkWindow
834  * @wmclass_name: window name hint
835  * @wmclass_class: window class hint
836  *
837  * Don't use this function. It sets the X Window System "class" and
838  * "name" hints for a window.  According to the ICCCM, you should
839  * always set these to the same value for all windows in an
840  * application, and GTK sets them to that value by default, so calling
841  * this function is sort of pointless. However, you may want to call
842  * gtk_window_set_role() on each window in your application, for the
843  * benefit of the session manager. Setting the role allows the window
844  * manager to restore window positions when loading a saved session.
845  * 
846  **/
847 void
848 gtk_window_set_wmclass (GtkWindow *window,
849                         const gchar *wmclass_name,
850                         const gchar *wmclass_class)
851 {
852   g_return_if_fail (GTK_IS_WINDOW (window));
853
854   g_free (window->wmclass_name);
855   window->wmclass_name = g_strdup (wmclass_name);
856
857   g_free (window->wmclass_class);
858   window->wmclass_class = g_strdup (wmclass_class);
859
860   if (GTK_WIDGET_REALIZED (window))
861     g_warning ("gtk_window_set_wmclass: shouldn't set wmclass after window is realized!\n");
862 }
863
864 /**
865  * gtk_window_set_role:
866  * @window: a #GtkWindow
867  * @role: unique identifier for the window to be used when restoring a session
868  *
869  * In combination with the window title, the window role allows a
870  * window manager to identify "the same" window when an application is
871  * restarted. So for example you might set the "toolbox" role on your
872  * app's toolbox window, so that when the user restarts their session,
873  * the window manager can put the toolbox back in the same place.
874  *
875  * If a window already has a unique title, you don't need to set the
876  * role, since the WM can use the title to identify the window when
877  * restoring the session.
878  * 
879  **/
880 void
881 gtk_window_set_role (GtkWindow   *window,
882                      const gchar *role)
883 {
884   g_return_if_fail (GTK_IS_WINDOW (window));
885
886   if (role == window->wm_role)
887     return;
888   
889   g_free (window->wm_role);
890   window->wm_role = g_strdup (role);
891   
892   if (GTK_WIDGET_REALIZED (window))
893     g_warning ("gtk_window_set_role(): shouldn't set role after window is realized!\n");
894 }
895
896 /**
897  * gtk_window_get_role:
898  * @window: a #GtkWindow
899  *
900  * Returns the role of the window. See gtk_window_set_role() for
901  * further explanation.
902  *
903  * Return value: the role of the window if set, or %NULL. The
904  *   returned is owned by the widget and must not be modified
905  *   or freed.
906  **/
907 G_CONST_RETURN gchar *
908 gtk_window_get_role (GtkWindow *window)
909 {
910   g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
911
912   return window->wm_role;
913 }
914
915 /**
916  * gtk_window_set_focus:
917  * @window: a #GtkWindow
918  * @focus: widget to be the new focus widget
919  *
920  * If @focus is not the current focus widget, and is focusable, emits
921  * the "set_focus" signal to set @focus as the focus widget for the
922  * window.  This function is more or less GTK-internal; to focus an
923  * entry widget or the like, you should use gtk_widget_grab_focus()
924  * instead of this function.
925  * 
926  **/
927 void
928 gtk_window_set_focus (GtkWindow *window,
929                       GtkWidget *focus)
930 {
931   g_return_if_fail (GTK_IS_WINDOW (window));
932   if (focus)
933     {
934       g_return_if_fail (GTK_IS_WIDGET (focus));
935       g_return_if_fail (GTK_WIDGET_CAN_FOCUS (focus));
936     }
937
938   if ((window->focus_widget != focus) ||
939       (focus && !GTK_WIDGET_HAS_FOCUS (focus)))
940     gtk_signal_emit (GTK_OBJECT (window), window_signals[SET_FOCUS], focus);
941 }
942
943 /**
944  * gtk_window_set_default:
945  * @window: a #GtkWindow
946  * @default_widget: widget to be the default
947  *
948  * The default widget is the widget that's activated when the user
949  * presses Enter in a dialog (for example). This function tells a
950  * #GtkWindow about the current default widget; it's really a GTK
951  * internal function and you shouldn't need it. Instead, to change the
952  * default widget, first set the #GTK_CAN_DEFAULT flag on the widget
953  * you'd like to make the default using GTK_WIDGET_SET_FLAGS(), then
954  * call gtk_widget_grab_default() to move the default.
955  * 
956  **/
957 void
958 gtk_window_set_default (GtkWindow *window,
959                         GtkWidget *default_widget)
960 {
961   g_return_if_fail (GTK_IS_WINDOW (window));
962
963   if (default_widget)
964     g_return_if_fail (GTK_WIDGET_CAN_DEFAULT (default_widget));
965
966   if (window->default_widget != default_widget)
967     {
968       if (window->default_widget)
969         {
970           if (window->focus_widget != window->default_widget ||
971               !GTK_WIDGET_RECEIVES_DEFAULT (window->default_widget))
972             GTK_WIDGET_UNSET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
973           gtk_widget_queue_draw (window->default_widget);
974         }
975
976       window->default_widget = default_widget;
977
978       if (window->default_widget)
979         {
980           if (window->focus_widget == NULL ||
981               !GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget))
982             GTK_WIDGET_SET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
983           gtk_widget_queue_draw (window->default_widget);
984         }
985     }
986 }
987
988 void
989 gtk_window_set_policy (GtkWindow *window,
990                        gboolean   allow_shrink,
991                        gboolean   allow_grow,
992                        gboolean   auto_shrink)
993 {
994   g_return_if_fail (GTK_IS_WINDOW (window));
995
996   window->allow_shrink = (allow_shrink != FALSE);
997   window->allow_grow = (allow_grow != FALSE);
998
999   g_object_freeze_notify (G_OBJECT (window));
1000   g_object_notify (G_OBJECT (window), "allow_shrink");
1001   g_object_notify (G_OBJECT (window), "allow_grow");
1002   g_object_notify (G_OBJECT (window), "resizable");
1003   g_object_thaw_notify (G_OBJECT (window));
1004   
1005   gtk_widget_queue_resize (GTK_WIDGET (window));
1006 }
1007
1008 void
1009 gtk_window_add_accel_group (GtkWindow        *window,
1010                             GtkAccelGroup    *accel_group)
1011 {
1012   g_return_if_fail (GTK_IS_WINDOW (window));
1013   g_return_if_fail (accel_group != NULL);
1014
1015   gtk_accel_group_attach (accel_group, G_OBJECT (window));
1016 }
1017
1018 void
1019 gtk_window_remove_accel_group (GtkWindow       *window,
1020                                GtkAccelGroup   *accel_group)
1021 {
1022   g_return_if_fail (GTK_IS_WINDOW (window));
1023   g_return_if_fail (accel_group != NULL);
1024
1025   gtk_accel_group_detach (accel_group, G_OBJECT (window));
1026 }
1027
1028 void
1029 gtk_window_add_mnemonic (GtkWindow *window,
1030                          guint      keyval,
1031                          GtkWidget *target)
1032 {
1033   GtkWindowMnemonic key;
1034   GtkWindowMnemonic *mnemonic;
1035
1036   g_return_if_fail (GTK_IS_WINDOW (window));
1037   g_return_if_fail (GTK_IS_WIDGET (target));
1038   
1039   key.window = window;
1040   key.keyval = keyval;
1041   mnemonic = g_hash_table_lookup (mnemonic_hash_table, &key);
1042
1043   if (mnemonic)
1044     {
1045       g_return_if_fail (g_slist_find (mnemonic->targets, target) == NULL);
1046       mnemonic->targets = g_slist_prepend (mnemonic->targets, target);
1047     }
1048   else
1049     {
1050       mnemonic = g_new (GtkWindowMnemonic, 1);
1051       *mnemonic = key;
1052       mnemonic->targets = g_slist_prepend (NULL, target);
1053       g_hash_table_insert (mnemonic_hash_table, mnemonic, mnemonic);
1054     }
1055 }
1056
1057 void
1058 gtk_window_remove_mnemonic (GtkWindow *window,
1059                             guint      keyval,
1060                             GtkWidget *target)
1061 {
1062   GtkWindowMnemonic key;
1063   GtkWindowMnemonic *mnemonic;
1064
1065   g_return_if_fail (GTK_IS_WINDOW (window));
1066   g_return_if_fail (GTK_IS_WIDGET (target));
1067   
1068   key.window = window;
1069   key.keyval = keyval;
1070   mnemonic = g_hash_table_lookup (mnemonic_hash_table, &key);
1071
1072   g_return_if_fail (mnemonic && g_slist_find (mnemonic->targets, target) != NULL);
1073
1074   mnemonic->targets = g_slist_remove (mnemonic->targets, target);
1075   if (mnemonic->targets == NULL)
1076     {
1077       g_hash_table_remove (mnemonic_hash_table, mnemonic);
1078       g_free (mnemonic);
1079     }
1080 }
1081
1082 gboolean
1083 gtk_window_mnemonic_activate (GtkWindow      *window,
1084                               guint           keyval,
1085                               GdkModifierType modifier)
1086 {
1087   GtkWindowMnemonic key;
1088   GtkWindowMnemonic *mnemonic;
1089   GSList *list;
1090   GtkWidget *widget, *chosen_widget;
1091   gboolean overloaded;
1092
1093   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
1094
1095   if (window->mnemonic_modifier != (modifier & gtk_accelerator_get_default_mod_mask ()))
1096     return FALSE;
1097   
1098   key.window = window;
1099   key.keyval = keyval;
1100   mnemonic = g_hash_table_lookup (mnemonic_hash_table, &key);
1101
1102   if (!mnemonic)
1103     return FALSE;
1104   
1105   overloaded = FALSE;
1106   chosen_widget = NULL;
1107   list = mnemonic->targets;
1108   while (list)
1109     {
1110       widget = GTK_WIDGET (list->data);
1111       
1112       if (GTK_WIDGET_IS_SENSITIVE (widget) &&
1113           GTK_WIDGET_MAPPED (widget))
1114         {
1115           if (chosen_widget)
1116             {
1117               overloaded = TRUE;
1118               break;
1119             }
1120           else
1121             chosen_widget = widget;
1122         }
1123       list = g_slist_next (list);
1124     }
1125
1126   if (chosen_widget)
1127     {
1128       /* For round robin we put the activated entry on
1129        * the end of the list after activation
1130        */
1131       mnemonic->targets = g_slist_remove (mnemonic->targets, chosen_widget);
1132       mnemonic->targets = g_slist_append (mnemonic->targets, chosen_widget);
1133
1134       return gtk_widget_mnemonic_activate (chosen_widget, overloaded);
1135     }
1136   return FALSE;
1137 }
1138
1139 void
1140 gtk_window_set_mnemonic_modifier (GtkWindow      *window,
1141                                   GdkModifierType modifier)
1142 {
1143   g_return_if_fail (GTK_IS_WINDOW (window));
1144   g_return_if_fail ((modifier & ~GDK_MODIFIER_MASK) == 0);
1145
1146   window->mnemonic_modifier = modifier;
1147 }
1148
1149 /**
1150  * gtk_window_get_mnemonic_modifier:
1151  * @window: a #GtkWindow
1152  *
1153  * Returns the mnemonic modifier for this window. See
1154  * gtk_window_set_mnemonic_modifier().
1155  *
1156  * Return value: the modifier mask used to activate
1157  *               mnemonics on this window.
1158  **/
1159 GdkModifierType
1160 gtk_window_get_mnemonic_modifier (GtkWindow *window)
1161 {
1162   g_return_val_if_fail (GTK_IS_WINDOW (window), 0);
1163
1164   return window->mnemonic_modifier;
1165 }
1166
1167 void
1168 gtk_window_set_position (GtkWindow         *window,
1169                          GtkWindowPosition  position)
1170 {
1171   g_return_if_fail (GTK_IS_WINDOW (window));
1172
1173   if (position == GTK_WIN_POS_CENTER_ALWAYS ||
1174       window->position == GTK_WIN_POS_CENTER_ALWAYS)
1175     {
1176       GtkWindowGeometryInfo *info;
1177
1178       info = gtk_window_get_geometry_info (window, TRUE);
1179
1180       /* this flag causes us to re-request the CENTER_ALWAYS
1181        * constraint in gtk_window_move_resize(), see
1182        * comment in that function.
1183        */
1184       info->position_constraints_changed = TRUE;
1185
1186       gtk_widget_queue_resize (GTK_WIDGET (window));
1187     }
1188
1189   window->position = position;
1190   
1191   g_object_notify (G_OBJECT (window), "window_position");
1192 }
1193
1194 gboolean 
1195 gtk_window_activate_focus (GtkWindow *window)
1196 {
1197   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
1198
1199   if (window->focus_widget)
1200     {
1201       if (GTK_WIDGET_IS_SENSITIVE (window->focus_widget))
1202         gtk_widget_activate (window->focus_widget);
1203       return TRUE;
1204     }
1205
1206   return FALSE;
1207 }
1208
1209 gboolean
1210 gtk_window_activate_default (GtkWindow *window)
1211 {
1212   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
1213
1214   if (window->default_widget && GTK_WIDGET_IS_SENSITIVE (window->default_widget) &&
1215       (!window->focus_widget || !GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget)))
1216     {
1217       gtk_widget_activate (window->default_widget);
1218       return TRUE;
1219     }
1220   else if (window->focus_widget)
1221     {
1222       if (GTK_WIDGET_IS_SENSITIVE (window->focus_widget))
1223         gtk_widget_activate (window->focus_widget);
1224       return TRUE;
1225     }
1226
1227   return FALSE;
1228 }
1229
1230 /**
1231  * gtk_window_set_modal:
1232  * @window: a #GtkWindow
1233  * @modal: whether the window is modal
1234  * 
1235  * Sets a window modal or non-modal. Modal windows prevent interaction
1236  * with other windows in the same application. To keep modal dialogs
1237  * on top of main application windows, use
1238  * gtk_window_set_transient_for() to make the dialog transient for the
1239  * parent; most window managers will then disallow lowering the dialog
1240  * below the parent.
1241  * 
1242  * 
1243  **/
1244 void
1245 gtk_window_set_modal (GtkWindow *window,
1246                       gboolean   modal)
1247 {
1248   g_return_if_fail (GTK_IS_WINDOW (window));
1249
1250   window->modal = modal != FALSE;
1251   
1252   /* adjust desired modality state */
1253   if (GTK_WIDGET_VISIBLE (window) && window->modal)
1254     gtk_grab_add (GTK_WIDGET (window));
1255   else
1256     gtk_grab_remove (GTK_WIDGET (window));
1257
1258   g_object_notify (G_OBJECT (window), "modal");
1259 }
1260
1261 /**
1262  * gtk_window_get_modal:
1263  * @window: a #GtkWindow
1264  * 
1265  * Returns whether the window is modal. See gtk_window_set_modal().
1266  *
1267  * Return value: %TRUE if the window is set to be modal and
1268  *               establishes a grab when shown
1269  **/
1270 gboolean
1271 gtk_window_get_modal (GtkWindow *window)
1272 {
1273   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
1274
1275   return window->modal;
1276 }
1277
1278 /**
1279  * gtk_window_list_toplevels:
1280  * 
1281  * Returns a list of all existing toplevel windows. The widgets
1282  * in the list are not individually referenced. If you want
1283  * to iterate through the list and perform actions involving
1284  * callbacks that might destroy the widgets, you MUST call
1285  * g_list_foreach (result, (GFunc)g_object_ref, NULL) first, and
1286  * then unref all the widgets afterwards.
1287  * 
1288  * Return value: list of toplevel widgets
1289  **/
1290 GList*
1291 gtk_window_list_toplevels (void)
1292 {
1293   GList *list = NULL;
1294   GSList *slist;
1295
1296   for (slist = toplevel_list; slist; slist = slist->next)
1297     list = g_list_prepend (list, slist->data);
1298
1299   return list;
1300 }
1301
1302 void
1303 gtk_window_add_embedded_xid (GtkWindow *window, guint xid)
1304 {
1305   GList *embedded_windows;
1306
1307   g_return_if_fail (GTK_IS_WINDOW (window));
1308
1309   embedded_windows = gtk_object_get_data (GTK_OBJECT (window), "gtk-embedded");
1310   if (embedded_windows)
1311     gtk_object_remove_no_notify_by_id (GTK_OBJECT (window), 
1312                                        g_quark_from_static_string ("gtk-embedded"));
1313   embedded_windows = g_list_prepend (embedded_windows,
1314                                      GUINT_TO_POINTER (xid));
1315
1316   gtk_object_set_data_full (GTK_OBJECT (window), "gtk-embedded", 
1317                             embedded_windows,
1318                             embedded_windows ?
1319                               (GtkDestroyNotify) g_list_free : NULL);
1320 }
1321
1322 void
1323 gtk_window_remove_embedded_xid (GtkWindow *window, guint xid)
1324 {
1325   GList *embedded_windows;
1326   GList *node;
1327
1328   g_return_if_fail (GTK_IS_WINDOW (window));
1329   
1330   embedded_windows = gtk_object_get_data (GTK_OBJECT (window), "gtk-embedded");
1331   if (embedded_windows)
1332     gtk_object_remove_no_notify_by_id (GTK_OBJECT (window), 
1333                                        g_quark_from_static_string ("gtk-embedded"));
1334
1335   node = g_list_find (embedded_windows, GUINT_TO_POINTER (xid));
1336   if (node)
1337     {
1338       embedded_windows = g_list_remove_link (embedded_windows, node);
1339       g_list_free_1 (node);
1340     }
1341   
1342   gtk_object_set_data_full (GTK_OBJECT (window), 
1343                             "gtk-embedded", embedded_windows,
1344                             embedded_windows ?
1345                               (GtkDestroyNotify) g_list_free : NULL);
1346 }
1347
1348 void       
1349 _gtk_window_reposition (GtkWindow *window,
1350                         gint       x,
1351                         gint       y)
1352 {
1353   g_return_if_fail (GTK_IS_WINDOW (window));
1354
1355   gtk_window_move (window, x, y);
1356 }
1357
1358 static void
1359 gtk_window_dispose (GObject *object)
1360 {
1361   GtkWindow *window;
1362
1363   g_return_if_fail (GTK_IS_WINDOW (object));
1364
1365   window = GTK_WINDOW (object);
1366
1367   gtk_window_set_focus (window, NULL);
1368   gtk_window_set_default (window, NULL);
1369
1370   G_OBJECT_CLASS (parent_class)->dispose (object);
1371 }
1372
1373 static void
1374 parent_destroyed_callback (GtkWindow *parent, GtkWindow *child)
1375 {
1376   gtk_widget_destroy (GTK_WIDGET (child));
1377 }
1378
1379 static void
1380 connect_parent_destroyed (GtkWindow *window)
1381 {
1382   if (window->transient_parent)
1383     {
1384       gtk_signal_connect (GTK_OBJECT (window->transient_parent),
1385                           "destroy",
1386                           GTK_SIGNAL_FUNC (parent_destroyed_callback),
1387                           window);
1388     }  
1389 }
1390
1391 static void
1392 disconnect_parent_destroyed (GtkWindow *window)
1393 {
1394   if (window->transient_parent)
1395     {
1396       gtk_signal_disconnect_by_func (GTK_OBJECT (window->transient_parent),
1397                                      GTK_SIGNAL_FUNC (parent_destroyed_callback),
1398                                      window);
1399     }
1400 }
1401
1402 static void
1403 gtk_window_transient_parent_realized (GtkWidget *parent,
1404                                       GtkWidget *window)
1405 {
1406   if (GTK_WIDGET_REALIZED (window))
1407     gdk_window_set_transient_for (window->window, parent->window);
1408 }
1409
1410 static void
1411 gtk_window_transient_parent_unrealized (GtkWidget *parent,
1412                                         GtkWidget *window)
1413 {
1414   if (GTK_WIDGET_REALIZED (window))
1415     gdk_property_delete (window->window, 
1416                          gdk_atom_intern ("WM_TRANSIENT_FOR", FALSE));
1417 }
1418
1419 static void       
1420 gtk_window_unset_transient_for  (GtkWindow *window)
1421 {
1422   if (window->transient_parent)
1423     {
1424       gtk_signal_disconnect_by_func (GTK_OBJECT (window->transient_parent),
1425                                      GTK_SIGNAL_FUNC (gtk_window_transient_parent_realized),
1426                                      window);
1427       gtk_signal_disconnect_by_func (GTK_OBJECT (window->transient_parent),
1428                                      GTK_SIGNAL_FUNC (gtk_window_transient_parent_unrealized),
1429                                      window);
1430       gtk_signal_disconnect_by_func (GTK_OBJECT (window->transient_parent),
1431                                      GTK_SIGNAL_FUNC (gtk_widget_destroyed),
1432                                      &window->transient_parent);
1433
1434       if (window->destroy_with_parent)
1435         disconnect_parent_destroyed (window);
1436       
1437       window->transient_parent = NULL;
1438     }
1439 }
1440
1441 /**
1442  * gtk_window_set_transient_for:
1443  * @window: a #GtkWindow
1444  * @parent: parent window
1445  *
1446  * Dialog windows should be set transient for the main application
1447  * window they were spawned from. This allows window managers to
1448  * e.g. keep the dialog on top of the main window, or center the
1449  * dialog over the main window. gtk_dialog_new_with_buttons() and
1450  * other convenience functions in GTK+ will sometimes call
1451  * gtk_window_set_transient_for() on your behalf.
1452  * 
1453  **/
1454 void       
1455 gtk_window_set_transient_for  (GtkWindow *window, 
1456                                GtkWindow *parent)
1457 {
1458   g_return_if_fail (GTK_IS_WINDOW (window));
1459   g_return_if_fail (parent == NULL || GTK_IS_WINDOW (parent));
1460   g_return_if_fail (window != parent);
1461
1462     
1463   if (window->transient_parent)
1464     {
1465       if (GTK_WIDGET_REALIZED (window) && 
1466           GTK_WIDGET_REALIZED (window->transient_parent) && 
1467           (!parent || !GTK_WIDGET_REALIZED (parent)))
1468         gtk_window_transient_parent_unrealized (GTK_WIDGET (window->transient_parent),
1469                                                 GTK_WIDGET (window));
1470
1471       gtk_window_unset_transient_for (window);
1472     }
1473
1474   window->transient_parent = parent;
1475
1476   if (parent)
1477     {
1478       gtk_signal_connect (GTK_OBJECT (parent), "destroy",
1479                           GTK_SIGNAL_FUNC (gtk_widget_destroyed),
1480                           &window->transient_parent);
1481       gtk_signal_connect (GTK_OBJECT (parent), "realize",
1482                           GTK_SIGNAL_FUNC (gtk_window_transient_parent_realized),
1483                           window);
1484       gtk_signal_connect (GTK_OBJECT (parent), "unrealize",
1485                           GTK_SIGNAL_FUNC (gtk_window_transient_parent_unrealized),
1486                           window);
1487
1488       if (window->destroy_with_parent)
1489         connect_parent_destroyed (window);
1490       
1491       if (GTK_WIDGET_REALIZED (window) &&
1492           GTK_WIDGET_REALIZED (parent))
1493         gtk_window_transient_parent_realized (GTK_WIDGET (parent),
1494                                               GTK_WIDGET (window));
1495     }
1496 }
1497
1498 /**
1499  * gtk_window_get_transient_for:
1500  * @window: a #GtkWindow
1501  *
1502  * Fetches the transient parent for this window. See
1503  * gtk_window_set_transient_for().
1504  *
1505  * Return value: the transient parent for this window, or %NULL
1506  *    if no transient parent has been set.
1507  **/
1508 GtkWindow *
1509 gtk_window_get_transient_for (GtkWindow *window)
1510 {
1511   g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
1512
1513   return window->transient_parent;
1514 }
1515
1516 /**
1517  * gtk_window_set_type_hint:
1518  * @window: a #GtkWindow
1519  * @hint: the window type
1520  *
1521  * By setting the type hint for the window, you allow the window
1522  * manager to decorate and handle the window in a way which is
1523  * suitable to the function of the window in your application.
1524  *
1525  * This function should be called before the window becomes visible.
1526  *
1527  * gtk_dialog_new_with_buttons() and other convenience functions in GTK+
1528  * will sometimes call gtk_window_set_type_hint() on your behalf.
1529  * 
1530  **/
1531 void
1532 gtk_window_set_type_hint (GtkWindow           *window, 
1533                           GdkWindowTypeHint    hint)
1534 {
1535   g_return_if_fail (GTK_IS_WINDOW (window));
1536   g_return_if_fail (!GTK_WIDGET_VISIBLE (window));
1537   window->type_hint = hint;
1538 }
1539
1540 /**
1541  * gtk_window_get_type_hint:
1542  * @window: a #GtkWindow
1543  *
1544  * Gets the type hint for this window. See gtk_window_set_type_hint().
1545  *
1546  * Return value: the type hint for @window.
1547  **/
1548 GdkWindowTypeHint
1549 gtk_window_get_type_hint (GtkWindow *window)
1550 {
1551   g_return_val_if_fail (GTK_IS_WINDOW (window), GDK_WINDOW_TYPE_HINT_NORMAL);
1552
1553   return window->type_hint;
1554 }
1555
1556 /**
1557  * gtk_window_set_destroy_with_parent:
1558  * @window: a #GtkWindow
1559  * @setting: whether to destroy @window with its transient parent
1560  * 
1561  * If @setting is TRUE, then destroying the transient parent of @window
1562  * will also destroy @window itself. This is useful for dialogs that
1563  * shouldn't persist beyond the lifetime of the main window they're
1564  * associated with, for example.
1565  **/
1566 void
1567 gtk_window_set_destroy_with_parent  (GtkWindow *window,
1568                                      gboolean   setting)
1569 {
1570   g_return_if_fail (GTK_IS_WINDOW (window));
1571
1572   if (window->destroy_with_parent == (setting != FALSE))
1573     return;
1574
1575   if (window->destroy_with_parent)
1576     {
1577       disconnect_parent_destroyed (window);
1578     }
1579   else
1580     {
1581       connect_parent_destroyed (window);
1582     }
1583   
1584   window->destroy_with_parent = setting;
1585
1586   g_object_notify (G_OBJECT (window), "destroy_with_parent");
1587 }
1588
1589 /**
1590  * gtk_window_get_destroy_with_parent:
1591  * @window: a #GtkWindow
1592  * 
1593  * Returns whether the window will be destroyed with its transient parent. See
1594  * gtk_window_set_destroy_with_parent ().
1595  *
1596  * Return value: %TRUE if the window will be destroyed with its transient parent.
1597  **/
1598 gboolean
1599 gtk_window_get_destroy_with_parent (GtkWindow *window)
1600 {
1601   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
1602
1603   return window->destroy_with_parent;
1604 }
1605
1606 static GtkWindowGeometryInfo*
1607 gtk_window_get_geometry_info (GtkWindow *window,
1608                               gboolean   create)
1609 {
1610   GtkWindowGeometryInfo *info;
1611
1612   info = window->geometry_info;
1613   if (!info && create)
1614     {
1615       info = g_new0 (GtkWindowGeometryInfo, 1);
1616
1617       info->default_width = -1;
1618       info->default_height = -1;
1619       info->resize_width = -1;
1620       info->resize_height = -1;
1621       info->initial_x = 0;
1622       info->initial_y = 0;
1623       info->initial_pos_set = FALSE;
1624       info->position_constraints_changed = FALSE;
1625       info->last.configure_request.x = 0;
1626       info->last.configure_request.y = 0;
1627       info->last.configure_request.width = -1;
1628       info->last.configure_request.height = -1;
1629       info->widget = NULL;
1630       info->mask = 0;
1631       window->geometry_info = info;
1632     }
1633
1634   return info;
1635 }
1636
1637 /**
1638  * gtk_window_set_geometry_hints:
1639  * @window: a #GtkWindow
1640  * @geometry_widget: widget the geometry hints will be applied to
1641  * @geometry: struct containing geometry information
1642  * @geom_mask: mask indicating which struct fields should be paid attention to
1643  *
1644  * This function sets up hints about how a window can be resized by
1645  * the user.  You can set a minimum and maximum size; allowed resize
1646  * increments (e.g. for xterm, you can only resize by the size of a
1647  * character); aspect ratios; and more. See the #GdkGeometry struct.
1648  * 
1649  **/
1650 void       
1651 gtk_window_set_geometry_hints (GtkWindow       *window,
1652                                GtkWidget       *geometry_widget,
1653                                GdkGeometry     *geometry,
1654                                GdkWindowHints   geom_mask)
1655 {
1656   GtkWindowGeometryInfo *info;
1657
1658   g_return_if_fail (window != NULL);
1659
1660   info = gtk_window_get_geometry_info (window, TRUE);
1661   
1662   if (info->widget)
1663     gtk_signal_disconnect_by_func (GTK_OBJECT (info->widget),
1664                                    GTK_SIGNAL_FUNC (gtk_widget_destroyed),
1665                                    &info->widget);
1666   
1667   info->widget = geometry_widget;
1668   if (info->widget)
1669     gtk_signal_connect (GTK_OBJECT (geometry_widget), "destroy",
1670                         GTK_SIGNAL_FUNC (gtk_widget_destroyed),
1671                         &info->widget);
1672
1673   if (geometry)
1674     info->geometry = *geometry;
1675
1676   /* We store gravity in window->gravity not in the hints. */
1677   info->mask = geom_mask & ~(GDK_HINT_WIN_GRAVITY);
1678
1679   if (geom_mask & GDK_HINT_WIN_GRAVITY)
1680     {
1681       gtk_window_set_gravity (window, geometry->win_gravity);
1682     }
1683   
1684   gtk_widget_queue_resize (GTK_WIDGET (window));
1685 }
1686
1687 /**
1688  * gtk_window_set_decorated:
1689  * @window: a #GtkWindow
1690  * @setting: %TRUE to decorate the window
1691  *
1692  * By default, windows are decorated with a title bar, resize
1693  * controls, etc.  Some window managers allow GTK+ to disable these
1694  * decorations, creating a borderless window. If you set the decorated
1695  * property to %FALSE using this function, GTK+ will do its best to
1696  * convince the window manager not to decorate the window.
1697  * 
1698  **/
1699 void
1700 gtk_window_set_decorated (GtkWindow *window,
1701                           gboolean   setting)
1702 {
1703   g_return_if_fail (GTK_IS_WINDOW (window));
1704
1705   setting = setting != FALSE;
1706
1707   if (setting == window->decorated)
1708     return;
1709
1710   window->decorated = setting;
1711   
1712   if (GTK_WIDGET (window)->window)
1713     {
1714       if (window->decorated)
1715         gdk_window_set_decorations (GTK_WIDGET (window)->window,
1716                                     GDK_DECOR_ALL);
1717       else
1718         gdk_window_set_decorations (GTK_WIDGET (window)->window,
1719                                     0);
1720     }
1721 }
1722
1723 /**
1724  * gtk_window_get_decorated:
1725  * @window: a #GtkWindow
1726  *
1727  * Returns whether the window has been set to have decorations
1728  * such as a title bar via gtk_window_set_decorated().
1729  *
1730  * Return value: %TRUE if the window has been set to have decorations
1731  **/
1732 gboolean
1733 gtk_window_get_decorated (GtkWindow *window)
1734 {
1735   g_return_val_if_fail (GTK_IS_WINDOW (window), TRUE);
1736
1737   return window->decorated;
1738 }
1739
1740 static void
1741 gdk_pixbuf_render_pixmap_and_mask_with_colormap (GdkPixbuf   *pixbuf,
1742                                                  GdkPixmap  **pixmap_return,
1743                                                  GdkBitmap  **mask_return,
1744                                                  int          alpha_threshold,
1745                                                  GdkColormap *cmap)
1746 {
1747   g_return_if_fail (pixbuf != NULL);
1748   
1749   if (pixmap_return)
1750     {
1751       GdkGC *gc;
1752       
1753       *pixmap_return = gdk_pixmap_new (NULL, gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf),
1754                                        gdk_colormap_get_visual (cmap)->depth);
1755       gdk_drawable_set_colormap (GDK_DRAWABLE (*pixmap_return),
1756                                  cmap);
1757       gc = gdk_gc_new (*pixmap_return);
1758       gdk_pixbuf_render_to_drawable (pixbuf, *pixmap_return, gc,
1759                                      0, 0, 0, 0,
1760                                      gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf),
1761                                      GDK_RGB_DITHER_NORMAL,
1762                                      0, 0);
1763       gdk_gc_unref (gc);
1764     }
1765   
1766   if (mask_return)
1767     {
1768       if (gdk_pixbuf_get_has_alpha (pixbuf))
1769         {
1770           *mask_return = gdk_pixmap_new (NULL, gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf), 1);
1771           
1772           gdk_pixbuf_render_threshold_alpha (pixbuf, *mask_return,
1773                                              0, 0, 0, 0,
1774                                              gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf),
1775                                              alpha_threshold);
1776         }
1777       else
1778         *mask_return = NULL;
1779     }
1780 }
1781
1782 static GtkWindowIconInfo*
1783 get_icon_info (GtkWindow *window)
1784 {
1785   return g_object_get_data (G_OBJECT (window),
1786                             "gtk-window-icon-info");
1787 }
1788      
1789 static GtkWindowIconInfo*
1790 ensure_icon_info (GtkWindow *window)
1791 {
1792   GtkWindowIconInfo *info;
1793
1794   info = get_icon_info (window);
1795   
1796   if (info == NULL)
1797     {
1798       info = g_new0 (GtkWindowIconInfo, 1);
1799       g_object_set_data_full (G_OBJECT (window),
1800                               "gtk-window-icon-info",
1801                               info,
1802                               g_free);
1803     }
1804
1805   return info;
1806 }
1807
1808 static void
1809 get_pixmap_and_mask (GtkWindowIconInfo  *parent_info,
1810                      gboolean            is_default_list,
1811                      GList              *icon_list,
1812                      GdkPixmap         **pmap_return,
1813                      GdkBitmap         **mask_return)
1814 {
1815   GdkPixbuf *best_icon;
1816   GList *tmp_list;
1817   int best_size;
1818
1819   *pmap_return = NULL;
1820   *mask_return = NULL;
1821   
1822   if (is_default_list &&
1823       default_icon_pixmap != NULL)
1824     {
1825       /* Use shared icon pixmap (eventually will be stored on the
1826        * GdkScreen)
1827        */
1828       if (default_icon_pixmap)
1829         g_object_ref (G_OBJECT (default_icon_pixmap));
1830       if (default_icon_mask)
1831         g_object_ref (G_OBJECT (default_icon_mask));
1832       
1833       *pmap_return = default_icon_pixmap;
1834       *mask_return = default_icon_mask;
1835     }
1836   else if (parent_info && parent_info->icon_pixmap)
1837     {
1838       if (parent_info->icon_pixmap)
1839         g_object_ref (G_OBJECT (parent_info->icon_pixmap));
1840       if (parent_info->icon_mask)
1841         g_object_ref (G_OBJECT (parent_info->icon_mask));
1842       
1843       *pmap_return = parent_info->icon_pixmap;
1844       *mask_return = parent_info->icon_mask;
1845     }
1846   else
1847     {
1848 #define IDEAL_SIZE 48
1849   
1850       best_size = G_MAXINT;
1851       best_icon = NULL;
1852       tmp_list = icon_list;
1853       while (tmp_list != NULL)
1854         {
1855           GdkPixbuf *pixbuf = tmp_list->data;
1856           int this;
1857       
1858           /* average width and height - if someone passes in a rectangular
1859            * icon they deserve what they get.
1860            */
1861           this = gdk_pixbuf_get_width (pixbuf) + gdk_pixbuf_get_height (pixbuf);
1862           this /= 2;
1863       
1864           if (best_icon == NULL)
1865             {
1866               best_icon = pixbuf;
1867               best_size = this;
1868             }
1869           else
1870             {
1871               /* icon is better if it's 32 pixels or larger, and closer to
1872                * the ideal size than the current best.
1873                */
1874               if (this >= 32 &&
1875                   (ABS (best_size - IDEAL_SIZE) <
1876                    ABS (this - IDEAL_SIZE)))
1877                 {
1878                   best_icon = pixbuf;
1879                   best_size = this;
1880                 }
1881             }
1882
1883           tmp_list = tmp_list->next;
1884         }
1885
1886       if (best_icon)
1887         gdk_pixbuf_render_pixmap_and_mask_with_colormap (best_icon,
1888                                                          pmap_return,
1889                                                          mask_return,
1890                                                          128,
1891                                                          gdk_colormap_get_system ());
1892
1893       /* Save pmap/mask for others to use if appropriate */
1894       if (parent_info)
1895         {
1896           parent_info->icon_pixmap = *pmap_return;
1897           parent_info->icon_mask = *mask_return;
1898
1899           if (parent_info->icon_pixmap)
1900             g_object_ref (G_OBJECT (parent_info->icon_pixmap));
1901           if (parent_info->icon_mask)
1902             g_object_ref (G_OBJECT (parent_info->icon_mask));
1903         }
1904       else if (is_default_list)
1905         {
1906           default_icon_pixmap = *pmap_return;
1907           default_icon_mask = *mask_return;
1908
1909           if (default_icon_pixmap)
1910             g_object_add_weak_pointer (G_OBJECT (default_icon_pixmap),
1911                                        (gpointer*)&default_icon_pixmap);
1912           if (default_icon_mask)
1913             g_object_add_weak_pointer (G_OBJECT (default_icon_mask),
1914                                        (gpointer*)&default_icon_mask);
1915         }
1916     }
1917 }
1918
1919 static void
1920 gtk_window_realize_icon (GtkWindow *window)
1921 {
1922   GtkWidget *widget;
1923   GtkWindowIconInfo *info;
1924   GList *icon_list;
1925   
1926   widget = GTK_WIDGET (window);
1927
1928   g_return_if_fail (widget->window != NULL);
1929
1930   /* no point setting an icon on override-redirect */
1931   if (window->type == GTK_WINDOW_POPUP)
1932     return;
1933
1934   icon_list = NULL;
1935   
1936   info = ensure_icon_info (window);
1937
1938   if (info->realized)
1939     return;
1940
1941   g_return_if_fail (info->icon_pixmap == NULL);
1942   g_return_if_fail (info->icon_mask == NULL);
1943   
1944   info->using_default_icon = FALSE;
1945   info->using_parent_icon = FALSE;
1946   
1947   icon_list = info->icon_list;
1948   
1949   /* Inherit from transient parent */
1950   if (icon_list == NULL && window->transient_parent)
1951     {
1952       icon_list = ensure_icon_info (window->transient_parent)->icon_list;
1953       if (icon_list)
1954         info->using_parent_icon = TRUE;
1955     }      
1956
1957   /* Inherit from default */
1958   if (icon_list == NULL)
1959     {
1960       icon_list = default_icon_list;
1961       if (icon_list)
1962         info->using_default_icon = TRUE;
1963     }
1964   
1965   gdk_window_set_icon_list (widget->window, icon_list);
1966
1967   get_pixmap_and_mask (info->using_parent_icon ?
1968                        ensure_icon_info (window->transient_parent) : NULL,
1969                        info->using_default_icon,
1970                        icon_list,
1971                        &info->icon_pixmap,
1972                        &info->icon_mask);
1973   
1974   /* This is a slight ICCCM violation since it's a color pixmap not
1975    * a bitmap, but everyone does it.
1976    */
1977   gdk_window_set_icon (widget->window,
1978                        NULL,
1979                        info->icon_pixmap,
1980                        info->icon_mask);
1981
1982   info->realized = TRUE;
1983 }
1984
1985 static void
1986 gtk_window_unrealize_icon (GtkWindow *window)
1987 {
1988   GtkWindowIconInfo *info;
1989   GtkWidget *widget;
1990
1991   widget = GTK_WIDGET (window);
1992   
1993   info = get_icon_info (window);
1994
1995   if (info == NULL)
1996     return;
1997   
1998   if (info->icon_pixmap)
1999     g_object_unref (G_OBJECT (info->icon_pixmap));
2000
2001   if (info->icon_mask)
2002     g_object_unref (G_OBJECT (info->icon_mask));
2003
2004   info->icon_pixmap = NULL;
2005   info->icon_mask = NULL;
2006
2007   /* We don't clear the properties on the window, just figure the
2008    * window is going away.
2009    */
2010
2011   info->realized = FALSE;
2012 }
2013
2014 /**
2015  * gtk_window_set_icon_list:
2016  * @window: a #GtkWindow
2017  * @list: list of #GdkPixbuf
2018  *
2019  * Sets up the icon representing a #GtkWindow. The icon is used when
2020  * the window is minimized (also known as iconified).  Some window
2021  * managers or desktop environments may also place it in the window
2022  * frame, or display it in other contexts.
2023  *
2024  * gtk_window_set_icon_list() allows you to pass in the same icon in
2025  * several hand-drawn sizes. The list should contain the natural sizes
2026  * your icon is available in; that is, don't scale the image before
2027  * passing it to GTK+. Scaling is postponed until the last minute,
2028  * when the desired final size is known, to allow best quality.
2029  *
2030  * By passing several sizes, you may improve the final image quality
2031  * of the icon, by reducing or eliminating automatic image scaling.
2032  *
2033  * Recommended sizes to provide: 16x16, 32x32, 48x48 at minimum, and
2034  * larger images (64x64, 128x128) if you have them.
2035  *
2036  * See also gtk_window_set_default_icon_list() to set the icon
2037  * for all windows in your application in one go.
2038  *
2039  * Note that transient windows (those who have been set transient for another
2040  * window using gtk_window_set_transient_for()) will inherit their
2041  * icon from their transient parent. So there's no need to explicitly
2042  * set the icon on transient windows.
2043  **/
2044 void
2045 gtk_window_set_icon_list (GtkWindow  *window,
2046                           GList      *list)
2047 {
2048   GtkWindowIconInfo *info;
2049
2050   g_return_if_fail (GTK_IS_WINDOW (window));
2051
2052   info = ensure_icon_info (window);
2053
2054   if (info->icon_list == list) /* check for NULL mostly */
2055     return;
2056
2057   g_list_foreach (info->icon_list,
2058                   (GFunc) g_object_unref, NULL);
2059
2060   g_list_free (info->icon_list);
2061
2062   info->icon_list = g_list_copy (list);
2063   g_list_foreach (info->icon_list,
2064                   (GFunc) g_object_ref, NULL);
2065
2066   g_object_notify (G_OBJECT (window), "icon");
2067   
2068   gtk_window_unrealize_icon (window);
2069   
2070   if (GTK_WIDGET_REALIZED (window))
2071     gtk_window_realize_icon (window);
2072
2073   /* We could try to update our transient children, but I don't think
2074    * it's really worth it. If we did it, the best way would probably
2075    * be to have children connect to notify::icon_list
2076    */
2077 }
2078
2079 /**
2080  * gtk_window_get_icon_list:
2081  * @window: a #GtkWindow
2082  * 
2083  * Retrieves the list of icons set by gtk_window_set_icon_list().
2084  * The list is copied, but the reference count on each
2085  * member won't be incremented.
2086  * 
2087  * Return value: copy of window's icon list
2088  **/
2089 GList*
2090 gtk_window_get_icon_list (GtkWindow  *window)
2091 {
2092   GtkWindowIconInfo *info;
2093   
2094   g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
2095
2096   info = get_icon_info (window);
2097
2098   if (info)
2099     return g_list_copy (info->icon_list);
2100   else
2101     return NULL;  
2102 }
2103
2104 /**
2105  * gtk_window_set_icon:
2106  * @window: a #GtkWindow
2107  * @icon: icon image, or %NULL
2108  * 
2109  * Sets up the icon representing a #GtkWindow. This icon is used when
2110  * the window is minimized (also known as iconified).  Some window
2111  * managers or desktop environments may also place it in the window
2112  * frame, or display it in other contexts.
2113  *
2114  * The icon should be provided in whatever size it was naturally
2115  * drawn; that is, don't scale the image before passing it to
2116  * GTK+. Scaling is postponed until the last minute, when the desired
2117  * final size is known, to allow best quality.
2118  *
2119  * If you have your icon hand-drawn in multiple sizes, use
2120  * gtk_window_set_icon_list(). Then the best size will be used.
2121  *
2122  * This function is equivalent to calling gtk_window_set_icon_list()
2123  * with a 1-element list.
2124  *
2125  * See also gtk_window_set_default_icon_list() to set the icon
2126  * for all windows in your application in one go.
2127  **/
2128 void
2129 gtk_window_set_icon (GtkWindow  *window,
2130                      GdkPixbuf  *icon)
2131 {
2132   GList *list;
2133   
2134   g_return_if_fail (GTK_IS_WINDOW (window));
2135   g_return_if_fail (icon == NULL || GDK_IS_PIXBUF (icon));
2136
2137   list = NULL;
2138   list = g_list_append (list, icon);
2139   gtk_window_set_icon_list (window, list);
2140   g_list_free (list);  
2141 }
2142
2143 /**
2144  * gtk_window_get_icon:
2145  * @window: a #GtkWindow
2146  * 
2147  * Gets the value set by gtk_window_set_icon() (or if you've
2148  * called gtk_window_set_icon_list(), gets the first icon in
2149  * the icon list).
2150  * 
2151  * Return value: icon for window
2152  **/
2153 GdkPixbuf*
2154 gtk_window_get_icon (GtkWindow  *window)
2155 {
2156   GtkWindowIconInfo *info;
2157
2158   info = get_icon_info (window);
2159   if (info && info->icon_list)
2160     return GDK_PIXBUF (info->icon_list->data);
2161   else
2162     return NULL;
2163 }
2164
2165 /**
2166  * gtk_window_set_default_icon_list:
2167  * @list: a list of #GdkPixbuf
2168  *
2169  * Sets an icon list to be used as fallback for windows that haven't
2170  * had gtk_window_set_icon_list() called on them to set up a
2171  * window-specific icon list. This function allows you to set up the
2172  * icon for all windows in your app at once.
2173  *
2174  * See gtk_window_set_icon_list() for more details.
2175  * 
2176  **/
2177 void
2178 gtk_window_set_default_icon_list (GList *list)
2179 {
2180   GList *toplevels;
2181   GList *tmp_list;
2182   if (list == default_icon_list)
2183     return;
2184
2185   if (default_icon_pixmap)
2186     g_object_unref (G_OBJECT (default_icon_pixmap));
2187   if (default_icon_mask)
2188     g_object_unref (G_OBJECT (default_icon_mask));
2189
2190   default_icon_pixmap = NULL;
2191   default_icon_mask = NULL;
2192   
2193   g_list_foreach (default_icon_list,
2194                   (GFunc) g_object_unref, NULL);
2195
2196   g_list_free (default_icon_list);
2197
2198   default_icon_list = g_list_copy (list);
2199   g_list_foreach (default_icon_list,
2200                   (GFunc) g_object_ref, NULL);
2201   
2202   /* Update all toplevels */
2203   toplevels = gtk_window_list_toplevels ();
2204   tmp_list = toplevels;
2205   while (tmp_list != NULL)
2206     {
2207       GtkWindowIconInfo *info;
2208       GtkWindow *w = tmp_list->data;
2209       
2210       info = get_icon_info (w);
2211       if (info && info->using_default_icon)
2212         {
2213           gtk_window_unrealize_icon (w);
2214           if (GTK_WIDGET_REALIZED (w))
2215             gtk_window_realize_icon (w);
2216         }
2217
2218       tmp_list = tmp_list->next;
2219     }
2220   g_list_free (toplevels);
2221 }
2222
2223 /**
2224  * gtk_window_get_default_icon_list:
2225  * 
2226  * Gets the value set by gtk_window_set_default_icon_list().
2227  * The list is a copy and should be freed with g_list_free(),
2228  * but the pixbufs in the list have not had their reference count
2229  * incremented.
2230  * 
2231  * Return value: copy of default icon list 
2232  **/
2233 GList*
2234 gtk_window_get_default_icon_list (void)
2235 {
2236   return g_list_copy (default_icon_list);
2237 }
2238
2239 static void
2240 gtk_window_set_default_size_internal (GtkWindow    *window,
2241                                       gboolean      change_width,
2242                                       gint          width,
2243                                       gboolean      change_height,
2244                                       gint          height)
2245 {
2246   GtkWindowGeometryInfo *info;
2247
2248   g_return_if_fail (GTK_IS_WINDOW (window));
2249   g_return_if_fail (change_width == FALSE || width >= -1);
2250   g_return_if_fail (change_height == FALSE || height >= -1);
2251
2252   info = gtk_window_get_geometry_info (window, TRUE);
2253
2254   g_object_freeze_notify (G_OBJECT (window));
2255
2256   if (change_width)
2257     {
2258       if (width == 0)
2259         width = 1;
2260
2261       if (width < 0)
2262         width = -1;
2263
2264       info->default_width = width;
2265
2266       g_object_notify (G_OBJECT (window), "default_width");
2267     }
2268
2269   if (change_height)
2270     {
2271       if (height == 0)
2272         height = 1;
2273
2274       if (height < 0)
2275         height = -1;
2276
2277       info->default_height = height;
2278       
2279       g_object_notify (G_OBJECT (window), "default_height");
2280     }
2281   
2282   g_object_thaw_notify (G_OBJECT (window));
2283   
2284   gtk_widget_queue_resize (GTK_WIDGET (window));
2285 }
2286
2287 /**
2288  * gtk_window_set_default_size:
2289  * @window: a #GtkWindow
2290  * @width: width in pixels, or -1 to unset the default width
2291  * @height: height in pixels, or -1 to unset the default height
2292  *
2293  * Sets the default size of a window. If the window's "natural" size
2294  * (its size request) is larger than the default, the default will be
2295  * ignored. More generally, if the default size does not obey the
2296  * geometry hints for the window (gtk_window_set_geometry_hints() can
2297  * be used to set these explicitly), the default size will be clamped
2298  * to the nearest permitted size.
2299  * 
2300  * Unlike gtk_widget_set_size_request(), which sets a size request for
2301  * a widget and thus would keep users from shrinking the window, this
2302  * function only sets the initial size, just as if the user had
2303  * resized the window themselves. Users can still shrink the window
2304  * again as they normally would. Setting a default size of -1 means to
2305  * use the "natural" default size (the size request of the window).
2306  *
2307  * For more control over a window's initial size and how resizing works,
2308  * investigate gtk_window_set_geometry_hints().
2309  *
2310  * A useful feature: if you set the "geometry widget" via
2311  * gtk_window_set_geometry_hints(), the default size specified by
2312  * gtk_window_set_default_size() will be the default size of that
2313  * widget, not of the entire window.
2314  *
2315  * For some uses, gtk_window_resize() is a more appropriate function.
2316  * gtk_window_resize() changes the current size of the window, rather
2317  * than the size to be used on initial display. gtk_window_resize() always
2318  * affects the window itself, not the geometry widget.
2319  *
2320  * The default size of a window only affects the first time a window is
2321  * shown; if a window is hidden and re-shown, it will remember the size
2322  * it had prior to hiding, rather than using the default size.
2323  *
2324  * Windows can't actually be 0x0 in size, they must be at least 1x1, but
2325  * passing 0 for @width and @height is OK, resulting in a 1x1 default size.
2326  **/
2327 void       
2328 gtk_window_set_default_size (GtkWindow   *window,
2329                              gint         width,
2330                              gint         height)
2331 {
2332   g_return_if_fail (GTK_IS_WINDOW (window));
2333   g_return_if_fail (width >= -1);
2334   g_return_if_fail (height >= -1);
2335
2336   gtk_window_set_default_size_internal (window, TRUE, width, TRUE, height);
2337 }
2338
2339 /**
2340  * gtk_window_get_default_size:
2341  * @window: a #GtkWindow
2342  * @width: location to store the default width, or %NULL
2343  * @height: location to store the default height, or %NULL
2344  *
2345  * Gets the default size of the window. A value of -1 for the width or
2346  * height indicates that a default size has not been explicitly set
2347  * for that dimension, so the "natural" size of the window will be
2348  * used.
2349  * 
2350  **/
2351 void
2352 gtk_window_get_default_size (GtkWindow *window,
2353                              gint      *width,
2354                              gint      *height)
2355 {
2356   GtkWindowGeometryInfo *info;
2357
2358   g_return_if_fail (GTK_IS_WINDOW (window));
2359
2360   info = gtk_window_get_geometry_info (window, FALSE);
2361
2362   if (width)
2363     *width = info->default_width;
2364
2365   if (height)
2366     *height = info->default_height;
2367 }
2368
2369 /**
2370  * gtk_window_resize:
2371  * @window: a #GtkWindow
2372  * @width: width to resize the window to
2373  * @height: height to resize the window to
2374  *
2375  * Resizes the window as if the user had done so, obeying geometry
2376  * constraints. The default geometry constraint is that windows may
2377  * not be smaller than their size request; to override this
2378  * constraint, call gtk_widget_set_size_request() to set the window's
2379  * request to a smaller value.
2380  *
2381  * If gtk_window_resize() is called before showing a window for the
2382  * first time, it overrides any default size set with
2383  * gtk_window_set_default_size().
2384  *
2385  * Windows may not be resized smaller than 1 by 1 pixels.
2386  * 
2387  **/
2388 void
2389 gtk_window_resize (GtkWindow *window,
2390                    gint       width,
2391                    gint       height)
2392 {
2393   GtkWindowGeometryInfo *info;
2394   
2395   g_return_if_fail (GTK_IS_WINDOW (window));
2396   g_return_if_fail (width > 0);
2397   g_return_if_fail (height > 0);
2398
2399   info = gtk_window_get_geometry_info (window, TRUE);
2400
2401   info->resize_width = width;
2402   info->resize_height = height;
2403
2404   gtk_widget_queue_resize (GTK_WIDGET (window));
2405 }
2406
2407 /**
2408  * gtk_window_get_size:
2409  * @window: a #GtkWindow
2410  * @width: return location for width, or %NULL
2411  * @height: return location for height, or %NULL
2412  *
2413  * Obtains the current size of @window. If @window is not onscreen,
2414  * returns the size GTK+ will suggest to the window manager for the
2415  * initial window size (but this is not reliably the same as the size
2416  * the window manager will actually select). The size obtained by
2417  * gtk_window_get_size() is the last size received in a
2418  * #GdkEventConfigure, that is, GTK+ uses its locally-stored size,
2419  * rather than querying the X server for the size. As a result, if you
2420  * call gtk_window_resize() then immediately call
2421  * gtk_window_get_size(), the size won't have taken effect yet. After
2422  * the window manager processes the resize request, GTK+ receives
2423  * notification that the size has changed via a configure event, and
2424  * the size of the window gets updated.
2425  *
2426  * Note #1: Nearly any use of this function creates a race condition,
2427  * because the size of the window may change between the time that you
2428  * get the size and the time that you perform some action assuming
2429  * that size is the current size. To avoid race conditions, connect to
2430  * "configure_event" on the window and adjust your size-dependent
2431  * state to match the size delivered in the #GdkEventConfigure.
2432  *
2433  * Note #2: The returned size does NOT include the size of the window
2434  * manager decorations (aka the window frame or border). Those
2435  * are not drawn by GTK+ and GTK+ has no reliable method of
2436  * determining their size.
2437  *
2438  * Note #3: If you are getting a window size in order to position
2439  * the window onscreen, there may be a better way. The preferred
2440  * way is to simply set the window's semantic type with
2441  * gtk_window_set_type_hint(), which allows the window manager to
2442  * e.g. center dialogs. Also, if you set the transient parent of
2443  * dialogs with gtk_widget_set_transient_for() window managers
2444  * will often center the dialog over its parent window. It's
2445  * much preferred to let the window manager handle these
2446  * things rather than doing it yourself, because all apps will
2447  * behave consistently and according to user prefs if the window
2448  * manager handles it. Also, the window manager can take the size
2449  * of the window decorations/border into account, while your
2450  * application cannot.
2451  *
2452  * In any case, if you insist on application-specified window
2453  * positioning, there's STILL a better way than doing it yourself -
2454  * gtk_window_set_position() will frequently handle the details
2455  * for you.
2456  * 
2457  **/
2458 void
2459 gtk_window_get_size (GtkWindow *window,
2460                      gint      *width,
2461                      gint      *height)
2462 {
2463   gint w, h;
2464   GtkWidget *widget;
2465   
2466   g_return_if_fail (GTK_IS_WINDOW (window));
2467
2468   widget = GTK_WIDGET (window);
2469   
2470   if (width == NULL && height == NULL)
2471     return;
2472
2473   if (GTK_WIDGET_MAPPED (window))
2474     {
2475       gdk_drawable_get_size (GTK_WIDGET (window)->window,
2476                              &w, &h);
2477     }
2478   else
2479     {
2480       GdkRectangle configure_request;
2481
2482       gtk_window_compute_configure_request (window,
2483                                             &configure_request,
2484                                             NULL, NULL);
2485
2486       w = configure_request.width;
2487       h = configure_request.height;
2488     }
2489   
2490   if (width)
2491     *width = w;
2492   if (height)
2493     *height = h;
2494 }
2495
2496 /**
2497  * gtk_window_move:
2498  * @window: a #GtkWindow
2499  * @x: X coordinate to move window to
2500  * @y: Y coordinate to move window to
2501  *
2502  * Asks the window manager to move @window to the given position.
2503  * Window managers are free to ignore this; most window managers
2504  * ignore requests for initial window positions (instead using a
2505  * user-defined placement algorithm) and honor requests after the
2506  * window has already been shown.
2507  *
2508  * Note: the position is the position of the gravity-determined
2509  * reference point for the window. The gravity determines two things:
2510  * first, the location of the reference point in root window
2511  * coordinates; and second, which point on the window is positioned at
2512  * the reference point.
2513  *
2514  * By default the gravity is #GDK_GRAVITY_NORTH_WEST, so the reference
2515  * point is simply the @x, @y supplied to gtk_window_move(). The
2516  * top-left corner of the window decorations (aka window frame or
2517  * border) will be placed at @x, @y.  Therefore, to position a window
2518  * at the top left of the screen, you want to use the default gravity
2519  * (which is #GDK_GRAVITY_NORTH_WEST) and move the window to 0,0.
2520  *
2521  * To position a window at the bottom right corner of the screen, you
2522  * would set #GDK_GRAVITY_SOUTH_EAST, which means that the reference
2523  * point is at @x + the window width and @y + the window height, and
2524  * the bottom-right corner of the window border will be placed at that
2525  * reference point. So, to place a window in the bottom right corner
2526  * you would first set gravity to south east, then write:
2527  * gtk_window_move (window, gdk_screen_width () - window_width,
2528  * gdk_screen_height () - window_height).
2529  *
2530  * The extended window manager hints specification at
2531  * http://www.freedesktop.org/standards/wm-spec.html has a nice table
2532  * of gravities in the "implementation notes" section.
2533  *
2534  * The gtk_window_get_position() documentation may also be relevant.
2535  * 
2536  **/
2537 void
2538 gtk_window_move (GtkWindow *window,
2539                  gint       x,
2540                  gint       y)
2541 {
2542   GtkWindowGeometryInfo *info;
2543   GtkWidget *widget;
2544   
2545   g_return_if_fail (GTK_IS_WINDOW (window));
2546
2547   widget = GTK_WIDGET (window);
2548
2549   info = gtk_window_get_geometry_info (window, TRUE);  
2550   
2551   if (GTK_WIDGET_MAPPED (window))
2552     {
2553       /* we have now sent a request with this position
2554        * with currently-active constraints, so toggle flag.
2555        */
2556       info->position_constraints_changed = FALSE;
2557
2558       /* we only constrain if mapped - if not mapped,
2559        * then gtk_window_compute_configure_request()
2560        * will apply the constraints later, and we
2561        * don't want to lose information about
2562        * what position the user set before then.
2563        * i.e. if you do a move() then turn off POS_CENTER
2564        * then show the window, your move() will work.
2565        */
2566       gtk_window_constrain_position (window,
2567                                      widget->allocation.width,
2568                                      widget->allocation.height,
2569                                      &x, &y);
2570       
2571       /* Note that this request doesn't go through our standard request
2572        * framework, e.g. doesn't increment configure_request_count,
2573        * doesn't set info->last, etc.; that's because
2574        * we don't save the info needed to arrive at this same request
2575        * again.
2576        *
2577        * To gtk_window_move_resize(), this will end up looking exactly
2578        * the same as the position being changed by the window
2579        * manager.
2580        */
2581       
2582       /* FIXME are we handling gravity properly for framed windows? */
2583       if (window->frame)
2584         gdk_window_move (window->frame,
2585                          x - window->frame_left,
2586                          y - window->frame_top);
2587       else
2588         gdk_window_move (GTK_WIDGET (window)->window,
2589                          x, y);
2590     }
2591   else
2592     {
2593       /* Save this position to apply on mapping */
2594       info->initial_x = x;
2595       info->initial_y = y;
2596       info->initial_pos_set = TRUE;
2597     }
2598 }
2599
2600 /**
2601  * gtk_window_get_position:
2602  * @window: a #GtkWindow
2603  * @root_x: return location for X coordinate of gravity-determined reference p\oint
2604  * @root_y: return location for Y coordinate of gravity-determined reference p\oint
2605  *
2606  * This function returns the position you need to pass to
2607  * gtk_window_move() to keep @window in its current position.  This
2608  * means that the meaning of the returned value varies with window
2609  * gravity. See gtk_window_move() for more details.
2610  * 
2611  * If you haven't changed the window gravity, its gravity will be
2612  * #GDK_GRAVITY_NORTH_WEST. This means that gtk_window_get_position()
2613  * returns the position of the top-left corner of the window
2614  * manager frame for the window. gtk_window_move() sets the
2615  * position of this same top-left corner.
2616  *
2617  * gtk_window_get_position() is not 100% reliable because the X Window System
2618  * does not specify a way to obtain the geometry of the
2619  * decorations placed on a window by the window manager.
2620  * Thus GTK+ is using a "best guess" that works with most
2621  * window managers.
2622  *
2623  * Moreover, nearly all window managers are broken with respect to
2624  * their handling of window gravity. So moving a window to its current
2625  * position as returned by gtk_window_get_position() tends to
2626  * result in moving the window slightly.
2627  *
2628  * If a window has gravity #GDK_GRAVITY_STATIC the window manager
2629  * frame is not relevant, and thus gtk_window_get_position() will
2630  * always produce accurate results. However you can't use static
2631  * gravity to do things like place a window in a corner of the screen,
2632  * because static gravity ignores the window manager decorations.
2633  *
2634  * If you are saving and restoring your application's window
2635  * positions, you should know that it's impossible for applications to
2636  * do this without getting it somewhat wrong because applications do
2637  * not have sufficient knowledge of window manager state. The Correct
2638  * Mechanism is to support the session management protocol (see the
2639  * "GnomeClient" object in the GNOME libraries for example) and allow
2640  * the window manager to save your window sizes and positions.
2641  * 
2642  **/
2643
2644 void
2645 gtk_window_get_position (GtkWindow *window,
2646                          gint      *root_x,
2647                          gint      *root_y)
2648 {
2649   GtkWidget *widget;
2650
2651   g_return_if_fail (GTK_IS_WINDOW (window));
2652
2653   widget = GTK_WIDGET (window);
2654   
2655   if (window->gravity == GDK_GRAVITY_STATIC)
2656     {
2657       if (GTK_WIDGET_MAPPED (widget))
2658         {
2659           /* This does a server round-trip, which is sort of wrong;
2660            * but a server round-trip is inevitable for
2661            * gdk_window_get_frame_extents() in the usual
2662            * NorthWestGravity case below, so not sure what else to
2663            * do. We should likely be consistent about whether we get
2664            * the client-side info or the server-side info.
2665            */
2666           gdk_window_get_origin (widget->window, root_x, root_y);
2667         }
2668       else
2669         {
2670           GdkRectangle configure_request;
2671           
2672           gtk_window_compute_configure_request (window,
2673                                                 &configure_request,
2674                                                 NULL, NULL);
2675           
2676           *root_x = configure_request.x;
2677           *root_y = configure_request.y;
2678         }
2679     }
2680   else
2681     {
2682       GdkRectangle frame_extents;
2683       
2684       gint x, y;
2685       gint w, h;
2686       
2687       if (GTK_WIDGET_MAPPED (widget))
2688         {
2689           gdk_window_get_frame_extents (widget->window, &frame_extents);
2690           x = frame_extents.x;
2691           y = frame_extents.y;
2692           gtk_window_get_size (window, &w, &h);
2693         }
2694       else
2695         {
2696           /* We just say the frame has 0 size on all sides.
2697            * Not sure what else to do.
2698            */             
2699           gtk_window_compute_configure_request (window,
2700                                                 &frame_extents,
2701                                                 NULL, NULL);
2702           x = frame_extents.x;
2703           y = frame_extents.y;
2704           w = frame_extents.width;
2705           h = frame_extents.height;
2706         }
2707       
2708       switch (window->gravity)
2709         {
2710         case GDK_GRAVITY_NORTH:
2711         case GDK_GRAVITY_CENTER:
2712         case GDK_GRAVITY_SOUTH:
2713           /* Find center of frame. */
2714           x += frame_extents.width / 2;
2715           /* Center client window on that point. */
2716           x -= w / 2;
2717           break;
2718
2719         case GDK_GRAVITY_SOUTH_EAST:
2720         case GDK_GRAVITY_EAST:
2721         case GDK_GRAVITY_NORTH_EAST:
2722           /* Find right edge of frame */
2723           x += frame_extents.width;
2724           /* Align left edge of client at that point. */
2725           x -= w;
2726           break;
2727         default:
2728           break;
2729         }
2730
2731       switch (window->gravity)
2732         {
2733         case GDK_GRAVITY_WEST:
2734         case GDK_GRAVITY_CENTER:
2735         case GDK_GRAVITY_EAST:
2736           /* Find center of frame. */
2737           y += frame_extents.height / 2;
2738           /* Center client window there. */
2739           y -= h / 2;
2740           break;
2741         case GDK_GRAVITY_SOUTH_WEST:
2742         case GDK_GRAVITY_SOUTH:
2743         case GDK_GRAVITY_SOUTH_EAST:
2744           /* Find south edge of frame */
2745           y += frame_extents.height;
2746           /* Place bottom edge of client there */
2747           y -= h;
2748           break;
2749         default:
2750           break;
2751         }
2752       
2753       if (root_x)
2754         *root_x = x;
2755       if (root_y)
2756         *root_y = y;
2757     }
2758 }
2759
2760 /**
2761  * gtk_window_reshow_with_initial_size:
2762  * @window: a #GtkWindow
2763  * 
2764  * Hides @window, then reshows it, resetting the
2765  * default size and position of the window. Used
2766  * by GUI builders only.
2767  **/
2768 void
2769 gtk_window_reshow_with_initial_size (GtkWindow *window)
2770 {
2771   GtkWidget *widget;
2772   
2773   g_return_if_fail (GTK_IS_WINDOW (window));
2774
2775   widget = GTK_WIDGET (window);
2776   
2777   gtk_widget_hide (widget);
2778   gtk_widget_unrealize (widget);
2779   gtk_widget_show (widget);
2780 }
2781
2782 static void
2783 gtk_window_destroy (GtkObject *object)
2784 {
2785   GtkWindow *window;
2786   
2787   g_return_if_fail (GTK_IS_WINDOW (object));
2788
2789   window = GTK_WINDOW (object);
2790   
2791   if (window->transient_parent)
2792     gtk_window_set_transient_for (window, NULL);
2793
2794   /* frees the icons */
2795   gtk_window_set_icon_list (window, NULL);
2796   
2797   if (window->has_user_ref_count)
2798     {
2799       window->has_user_ref_count = FALSE;
2800       gtk_widget_unref (GTK_WIDGET (window));
2801     }
2802
2803   if (window->group)
2804     gtk_window_group_remove_window (window->group, window);
2805
2806   GTK_OBJECT_CLASS (parent_class)->destroy (object);
2807 }
2808
2809 static gboolean
2810 gtk_window_mnemonic_hash_remove (gpointer       key,
2811                                  gpointer       value,
2812                                  gpointer       user)
2813 {
2814   GtkWindowMnemonic *mnemonic = key;
2815   GtkWindow *window = user;
2816
2817   if (mnemonic->window == window)
2818     {
2819       if (mnemonic->targets)
2820         {
2821           gchar *name = gtk_accelerator_name (mnemonic->keyval, 0);
2822
2823           g_warning ("mnemonic \"%s\" wasn't removed for widget (%p)",
2824                      name, mnemonic->targets->data);
2825           g_free (name);
2826         }
2827       g_slist_free (mnemonic->targets);
2828       g_free (mnemonic);
2829       
2830       return TRUE;
2831     }
2832   return FALSE;
2833 }
2834
2835 static void
2836 gtk_window_finalize (GObject *object)
2837 {
2838   GtkWindow *window;
2839
2840   g_return_if_fail (GTK_IS_WINDOW (object));
2841
2842   window = GTK_WINDOW (object);
2843
2844   toplevel_list = g_slist_remove (toplevel_list, window);
2845
2846   g_free (window->title);
2847   g_free (window->wmclass_name);
2848   g_free (window->wmclass_class);
2849   g_free (window->wm_role);
2850
2851   g_hash_table_foreach_remove (mnemonic_hash_table,
2852                                gtk_window_mnemonic_hash_remove,
2853                                window);
2854   if (window->geometry_info)
2855     {
2856       if (window->geometry_info->widget)
2857         gtk_signal_disconnect_by_func (GTK_OBJECT (window->geometry_info->widget),
2858                                        GTK_SIGNAL_FUNC (gtk_widget_destroyed),
2859                                        &window->geometry_info->widget);
2860       g_free (window->geometry_info);
2861     }
2862   
2863   G_OBJECT_CLASS (parent_class)->finalize (object);
2864 }
2865
2866 static void
2867 gtk_window_show (GtkWidget *widget)
2868 {
2869   GtkWindow *window = GTK_WINDOW (widget);
2870   GtkContainer *container = GTK_CONTAINER (window);
2871   gboolean need_resize;
2872   
2873   GTK_WIDGET_SET_FLAGS (widget, GTK_VISIBLE);
2874   
2875   need_resize = container->need_resize || !GTK_WIDGET_REALIZED (widget);
2876   container->need_resize = FALSE;
2877   
2878   if (need_resize)
2879     {
2880       GtkWindowGeometryInfo *info = gtk_window_get_geometry_info (window, TRUE);
2881       GtkAllocation allocation = { 0, 0 };
2882       GdkRectangle configure_request;
2883       GdkGeometry new_geometry;
2884       guint new_flags;
2885       gboolean was_realized;
2886
2887       /* We are going to go ahead and perform this configure request
2888        * and then emulate a configure notify by going ahead and
2889        * doing a size allocate. Sort of a synchronous
2890        * mini-copy of gtk_window_move_resize() here.
2891        */
2892       gtk_window_compute_configure_request (window,
2893                                             &configure_request,
2894                                             &new_geometry,
2895                                             &new_flags);
2896       
2897       /* We update this because we are going to go ahead
2898        * and gdk_window_resize() below, rather than
2899        * queuing it.
2900        */
2901       info->last.configure_request.width = configure_request.width;
2902       info->last.configure_request.height = configure_request.height;
2903       
2904       /* and allocate the window - this is normally done
2905        * in move_resize in response to configure notify
2906        */
2907       allocation.width  = configure_request.width;
2908       allocation.height = configure_request.height;
2909       gtk_widget_size_allocate (widget, &allocation);
2910
2911       /* Then we guarantee we have a realize */
2912       was_realized = FALSE;
2913       if (!GTK_WIDGET_REALIZED (widget))
2914         {
2915           gtk_widget_realize (widget);
2916           was_realized = TRUE;
2917         }
2918
2919       /* Must be done after the windows are realized,
2920        * so that the decorations can be read
2921        */
2922       gtk_decorated_window_calculate_frame_size (window);
2923
2924       /* We only send configure request if we didn't just finish
2925        * creating the window; if we just created the window
2926        * then we created it with widget->allocation anyhow.
2927        */
2928       if (!was_realized)
2929         gdk_window_resize (widget->window,
2930                            configure_request.width,
2931                            configure_request.height);
2932     }
2933   
2934   gtk_container_check_resize (container);
2935
2936   gtk_widget_map (widget);
2937
2938   if (window->modal)
2939     gtk_grab_add (widget);
2940 }
2941
2942 static void
2943 gtk_window_hide (GtkWidget *widget)
2944 {
2945   GtkWindow *window;
2946
2947   g_return_if_fail (GTK_IS_WINDOW (widget));
2948
2949   window = GTK_WINDOW (widget);
2950
2951   GTK_WIDGET_UNSET_FLAGS (widget, GTK_VISIBLE);
2952   gtk_widget_unmap (widget);
2953
2954   if (window->modal)
2955     gtk_grab_remove (widget);
2956 }
2957
2958 static void
2959 gtk_window_map (GtkWidget *widget)
2960 {
2961   GtkWindow *window;
2962   GdkWindow *toplevel;
2963   
2964   g_return_if_fail (GTK_IS_WINDOW (widget));
2965
2966   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
2967
2968   window = GTK_WINDOW (widget);
2969
2970   if (window->bin.child &&
2971       GTK_WIDGET_VISIBLE (window->bin.child) &&
2972       !GTK_WIDGET_MAPPED (window->bin.child))
2973     gtk_widget_map (window->bin.child);
2974
2975   if (window->frame)
2976     toplevel = window->frame;
2977   else
2978     toplevel = widget->window;
2979   
2980   if (window->maximize_initially)
2981     gdk_window_maximize (toplevel);
2982   else
2983     gdk_window_unmaximize (toplevel);
2984   
2985   if (window->stick_initially)
2986     gdk_window_stick (toplevel);
2987   else
2988     gdk_window_unstick (toplevel);
2989   
2990   if (window->iconify_initially)
2991     gdk_window_iconify (toplevel);
2992   else
2993     gdk_window_deiconify (toplevel);
2994
2995   /* No longer use the default settings */
2996   window->need_default_size = FALSE;
2997   window->need_default_position = FALSE;
2998   
2999   gdk_window_show (widget->window);
3000
3001   if (window->frame)
3002     gdk_window_show (window->frame);
3003 }
3004
3005 static void
3006 gtk_window_unmap (GtkWidget *widget)
3007 {
3008   GtkWindow *window;
3009   GtkWindowGeometryInfo *info;    
3010
3011   window = GTK_WINDOW (widget);
3012   
3013   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
3014   if (window->frame)
3015     gdk_window_withdraw (window->frame);
3016   else 
3017     gdk_window_withdraw (widget->window);
3018   
3019   window->configure_request_count = 0;
3020   window->configure_notify_received = FALSE;
3021
3022   /* on unmap, we reset the default positioning of the window,
3023    * so it's placed again, but we don't reset the default
3024    * size of the window, so it's remembered.
3025    */
3026   window->need_default_position = TRUE;
3027
3028   info = gtk_window_get_geometry_info (window, FALSE);
3029   if (info)
3030     {
3031       info->initial_pos_set = FALSE;
3032       info->position_constraints_changed = FALSE;
3033     }
3034 }
3035
3036 static void
3037 gtk_window_realize (GtkWidget *widget)
3038 {
3039   GtkWindow *window;
3040   GdkWindow *parent_window;
3041   GdkWindowAttr attributes;
3042   gint attributes_mask;
3043   
3044   g_return_if_fail (GTK_IS_WINDOW (widget));
3045
3046   window = GTK_WINDOW (widget);
3047
3048   /* ensure widget tree is properly size allocated */
3049   if (widget->allocation.x == -1 &&
3050       widget->allocation.y == -1 &&
3051       widget->allocation.width == 1 &&
3052       widget->allocation.height == 1)
3053     {
3054       GtkRequisition requisition;
3055       GtkAllocation allocation = { 0, 0, 200, 200 };
3056
3057       gtk_widget_size_request (widget, &requisition);
3058       if (requisition.width || requisition.height)
3059         {
3060           /* non-empty window */
3061           allocation.width = requisition.width;
3062           allocation.height = requisition.height;
3063         }
3064       gtk_widget_size_allocate (widget, &allocation);
3065       
3066       gtk_container_queue_resize (GTK_CONTAINER (widget));
3067
3068       g_return_if_fail (!GTK_WIDGET_REALIZED (widget));
3069     }
3070   
3071   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
3072   
3073   switch (window->type)
3074     {
3075     case GTK_WINDOW_TOPLEVEL:
3076       attributes.window_type = GDK_WINDOW_TOPLEVEL;
3077       break;
3078     case GTK_WINDOW_POPUP:
3079       attributes.window_type = GDK_WINDOW_TEMP;
3080       break;
3081     default:
3082       g_warning (G_STRLOC": Unknown window type %d!", window->type);
3083       break;
3084     }
3085    
3086   attributes.title = window->title;
3087   attributes.wmclass_name = window->wmclass_name;
3088   attributes.wmclass_class = window->wmclass_class;
3089   attributes.wclass = GDK_INPUT_OUTPUT;
3090   attributes.visual = gtk_widget_get_visual (widget);
3091   attributes.colormap = gtk_widget_get_colormap (widget);
3092
3093   if (window->has_frame)
3094     {
3095       attributes.width = widget->allocation.width + window->frame_left + window->frame_right;
3096       attributes.height = widget->allocation.height + window->frame_top + window->frame_bottom;
3097       attributes.event_mask = (GDK_EXPOSURE_MASK |
3098                                GDK_KEY_PRESS_MASK |
3099                                GDK_ENTER_NOTIFY_MASK |
3100                                GDK_LEAVE_NOTIFY_MASK |
3101                                GDK_FOCUS_CHANGE_MASK |
3102                                GDK_STRUCTURE_MASK |
3103                                GDK_BUTTON_MOTION_MASK |
3104                                GDK_POINTER_MOTION_HINT_MASK |
3105                                GDK_BUTTON_PRESS_MASK |
3106                                GDK_BUTTON_RELEASE_MASK);
3107       
3108       attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP;
3109       
3110       window->frame = gdk_window_new (NULL, &attributes, attributes_mask);
3111       gdk_window_set_user_data (window->frame, widget);
3112       
3113       attributes.window_type = GDK_WINDOW_CHILD;
3114       attributes.x = window->frame_left;
3115       attributes.y = window->frame_right;
3116     
3117       attributes_mask = GDK_WA_X | GDK_WA_Y;
3118
3119       parent_window = window->frame;
3120     }
3121   else
3122     {
3123       attributes_mask = 0;
3124       parent_window = NULL;
3125     }
3126   
3127   attributes.width = widget->allocation.width;
3128   attributes.height = widget->allocation.height;
3129   attributes.event_mask = gtk_widget_get_events (widget);
3130   attributes.event_mask |= (GDK_EXPOSURE_MASK |
3131                             GDK_KEY_PRESS_MASK |
3132                             GDK_ENTER_NOTIFY_MASK |
3133                             GDK_LEAVE_NOTIFY_MASK |
3134                             GDK_FOCUS_CHANGE_MASK |
3135                             GDK_STRUCTURE_MASK);
3136
3137   attributes_mask |= GDK_WA_VISUAL | GDK_WA_COLORMAP;
3138   attributes_mask |= (window->title ? GDK_WA_TITLE : 0);
3139   attributes_mask |= (window->wmclass_name ? GDK_WA_WMCLASS : 0);
3140   widget->window = gdk_window_new (parent_window, &attributes, attributes_mask);
3141   gdk_window_set_user_data (widget->window, window);
3142       
3143   widget->style = gtk_style_attach (widget->style, widget->window);
3144   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
3145   if (window->frame)
3146     gtk_style_set_background (widget->style, window->frame, GTK_STATE_NORMAL);
3147
3148   /* This is a bad hack to set the window background. */
3149   gtk_window_paint (widget, NULL);
3150   
3151   if (window->transient_parent &&
3152       GTK_WIDGET_REALIZED (window->transient_parent))
3153     gdk_window_set_transient_for (widget->window,
3154                                   GTK_WIDGET (window->transient_parent)->window);
3155
3156   if (window->wm_role)
3157     gdk_window_set_role (widget->window, window->wm_role);
3158   
3159   if (!window->decorated)
3160     gdk_window_set_decorations (widget->window, 0);
3161
3162   gdk_window_set_type_hint (widget->window, window->type_hint);
3163
3164   /* transient_for must be set to allow the modal hint */
3165   if (window->transient_parent && window->modal)
3166     gdk_window_set_modal_hint (widget->window, TRUE);
3167   else
3168     gdk_window_set_modal_hint (widget->window, FALSE);
3169
3170   /* Icons */
3171   gtk_window_realize_icon (window);
3172 }
3173
3174 static void
3175 gtk_window_unrealize (GtkWidget *widget)
3176 {
3177   GtkWindow *window;
3178   GtkWindowGeometryInfo *info;
3179
3180   window = GTK_WINDOW (widget);
3181
3182   /* On unrealize, we reset the size of the window such
3183    * that we will re-apply the default sizing stuff
3184    * next time we show the window.
3185    *
3186    * Default positioning is reset on unmap, instead of unrealize.
3187    */
3188   window->need_default_size = TRUE;
3189   info = gtk_window_get_geometry_info (window, FALSE);
3190   if (info)
3191     {
3192       info->resize_width = -1;
3193       info->resize_height = -1;
3194       info->last.configure_request.x = 0;
3195       info->last.configure_request.y = 0;
3196       info->last.configure_request.width = -1;
3197       info->last.configure_request.height = -1;
3198       /* be sure we reset geom hints on re-realize */
3199       info->last.flags = 0;
3200     }
3201   
3202   if (window->frame)
3203     {
3204       gdk_window_set_user_data (window->frame, NULL);
3205       gdk_window_destroy (window->frame);
3206       window->frame = NULL;
3207     }
3208
3209   /* Icons */
3210   gtk_window_unrealize_icon (window);
3211   
3212   (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
3213 }
3214
3215 static void
3216 gtk_window_size_request (GtkWidget      *widget,
3217                          GtkRequisition *requisition)
3218 {
3219   GtkWindow *window;
3220   GtkBin *bin;
3221
3222   g_return_if_fail (GTK_IS_WINDOW (widget));
3223   g_return_if_fail (requisition != NULL);
3224
3225   window = GTK_WINDOW (widget);
3226   bin = GTK_BIN (window);
3227   
3228   requisition->width = GTK_CONTAINER (window)->border_width * 2;
3229   requisition->height = GTK_CONTAINER (window)->border_width * 2;
3230
3231   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
3232     {
3233       GtkRequisition child_requisition;
3234       
3235       gtk_widget_size_request (bin->child, &child_requisition);
3236
3237       requisition->width += child_requisition.width;
3238       requisition->height += child_requisition.height;
3239     }
3240 }
3241
3242 static void
3243 gtk_window_size_allocate (GtkWidget     *widget,
3244                           GtkAllocation *allocation)
3245 {
3246   GtkWindow *window;
3247   GtkAllocation child_allocation;
3248
3249   g_return_if_fail (GTK_IS_WINDOW (widget));
3250   g_return_if_fail (allocation != NULL);
3251
3252   window = GTK_WINDOW (widget);
3253   widget->allocation = *allocation;
3254
3255   if (window->bin.child && GTK_WIDGET_VISIBLE (window->bin.child))
3256     {
3257       child_allocation.x = GTK_CONTAINER (window)->border_width;
3258       child_allocation.y = GTK_CONTAINER (window)->border_width;
3259       child_allocation.width =
3260         MAX (1, (gint)allocation->width - child_allocation.x * 2);
3261       child_allocation.height =
3262         MAX (1, (gint)allocation->height - child_allocation.y * 2);
3263
3264       gtk_widget_size_allocate (window->bin.child, &child_allocation);
3265     }
3266
3267   if (GTK_WIDGET_REALIZED (widget) && window->frame)
3268     {
3269       gdk_window_resize (window->frame,
3270                          allocation->width + window->frame_left + window->frame_right,
3271                          allocation->height + window->frame_top + window->frame_bottom);
3272     }
3273 }
3274
3275 static gint
3276 gtk_window_event (GtkWidget *widget, GdkEvent *event)
3277 {
3278   GtkWindow *window;
3279   gboolean return_val;
3280
3281   
3282   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
3283   g_return_val_if_fail (event != NULL, FALSE);
3284   
3285   window = GTK_WINDOW (widget);
3286
3287   if (window->frame && (event->any.window == window->frame))
3288     {
3289       if ((event->type != GDK_KEY_PRESS) &&
3290           (event->type != GDK_KEY_RELEASE) &&
3291           (event->type != GDK_FOCUS_CHANGE))
3292         {
3293           gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "event");
3294           return_val = FALSE;
3295           gtk_signal_emit (GTK_OBJECT (widget), window_signals[FRAME_EVENT], event, &return_val);
3296           return TRUE;
3297         }
3298       else
3299         {
3300           g_object_unref (event->any.window);
3301           event->any.window = g_object_ref (widget->window);
3302         }
3303     }
3304
3305   return FALSE;
3306 }
3307
3308 static gboolean
3309 gtk_window_frame_event (GtkWidget *widget, GdkEvent *event)
3310 {
3311   GdkEventConfigure *configure_event;
3312   GtkWindow *window = GTK_WINDOW (widget);
3313   GdkRectangle rect;
3314
3315   switch (event->type)
3316     {
3317     case GDK_CONFIGURE:
3318       configure_event = (GdkEventConfigure *)event;
3319       
3320       /* Invalidate the decorations */
3321       rect.x = 0;
3322       rect.y = 0;
3323       rect.width = configure_event->width;
3324       rect.height = configure_event->height;
3325       
3326       gdk_window_invalidate_rect (window->frame, &rect, FALSE);
3327
3328       /* Pass on the (modified) configure event */
3329       configure_event->width -= window->frame_left + window->frame_right;
3330       configure_event->height -= window->frame_top + window->frame_bottom;
3331       return gtk_window_configure_event (widget, configure_event);
3332       break;
3333     default:
3334       break;
3335     }
3336   return FALSE;
3337 }
3338
3339 static gint
3340 gtk_window_configure_event (GtkWidget         *widget,
3341                             GdkEventConfigure *event)
3342 {
3343   GtkWindow *window;
3344   
3345   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
3346   g_return_val_if_fail (event != NULL, FALSE);
3347   
3348   window = GTK_WINDOW (widget);
3349
3350   /* window->configure_request_count incremented for each 
3351    * configure request, and decremented to a min of 0 for
3352    * each configure notify.
3353    *
3354    * All it means is that we know we will get at least
3355    * window->configure_request_count more configure notifies.
3356    * We could get more configure notifies than that; some
3357    * of the configure notifies we get may be unrelated to
3358    * the configure requests. But we will get at least
3359    * window->configure_request_count notifies.
3360    */
3361
3362   if (window->configure_request_count > 0)
3363     window->configure_request_count -= 1;
3364   
3365   /* As an optimization, we avoid a resize when possible.
3366    *
3367    * The only times we can avoid a resize are:
3368    *   - we know only the position changed, not the size
3369    *   - we know we have made more requests and so will get more
3370    *     notifies and can wait to resize when we get them
3371    */
3372   
3373   if (window->configure_request_count > 0 ||
3374       (widget->allocation.width == event->width &&
3375        widget->allocation.height == event->height))
3376     return TRUE;
3377
3378   /*
3379    * If we do need to resize, we do that by:
3380    *   - filling in widget->allocation with the new size
3381    *   - setting configure_notify_received to TRUE
3382    *     for use in gtk_window_move_resize()
3383    *   - queueing a resize, leading to invocation of
3384    *     gtk_window_move_resize() in an idle handler
3385    *
3386    */
3387   
3388   window->configure_notify_received = TRUE;
3389   
3390   widget->allocation.width = event->width;
3391   widget->allocation.height = event->height;
3392   
3393   gtk_widget_queue_resize (widget);
3394   
3395   return TRUE;
3396 }
3397
3398 static gint
3399 gtk_window_key_press_event (GtkWidget   *widget,
3400                             GdkEventKey *event)
3401 {
3402   GtkWindow *window;
3403   gboolean handled;
3404
3405   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
3406   g_return_val_if_fail (event != NULL, FALSE);
3407
3408   window = GTK_WINDOW (widget);
3409
3410   handled = FALSE;
3411   
3412   if (window->focus_widget && window->focus_widget != widget &&
3413       GTK_WIDGET_IS_SENSITIVE (window->focus_widget))
3414     handled = gtk_widget_event (window->focus_widget, (GdkEvent*) event);
3415
3416   if (!handled)
3417     handled = gtk_window_mnemonic_activate (window,
3418                                             event->keyval,
3419                                             event->state);
3420
3421   if (!handled)
3422     handled = gtk_accel_groups_activate (G_OBJECT (window), event->keyval, event->state);
3423
3424   /* Chain up, invokes binding set */
3425   if (!handled && GTK_WIDGET_CLASS (parent_class)->key_press_event)
3426     handled = GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
3427
3428   return handled;
3429 }
3430
3431
3432 static void
3433 gtk_window_real_activate_default (GtkWindow *window)
3434 {
3435   gtk_window_activate_default (window);
3436 }
3437
3438 static void
3439 gtk_window_real_activate_focus (GtkWindow *window)
3440 {
3441   gtk_window_activate_focus (window);
3442 }
3443
3444 static void
3445 gtk_window_move_focus (GtkWindow       *window,
3446                        GtkDirectionType dir)
3447 {
3448   gtk_widget_child_focus (GTK_WIDGET (window), dir);
3449   
3450   if (!GTK_CONTAINER (window)->focus_child)
3451     gtk_window_set_focus (window, NULL);
3452 }
3453
3454 static gint
3455 gtk_window_key_release_event (GtkWidget   *widget,
3456                               GdkEventKey *event)
3457 {
3458   GtkWindow *window;
3459   gint handled;
3460   
3461   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
3462   g_return_val_if_fail (event != NULL, FALSE);
3463   
3464   window = GTK_WINDOW (widget);
3465   handled = FALSE;
3466   if (window->focus_widget &&
3467       window->focus_widget != widget &&
3468       GTK_WIDGET_SENSITIVE (window->focus_widget))
3469     {
3470       handled = gtk_widget_event (window->focus_widget, (GdkEvent*) event);
3471     }
3472
3473   if (!handled && GTK_WIDGET_CLASS (parent_class)->key_release_event)
3474     handled = GTK_WIDGET_CLASS (parent_class)->key_release_event (widget, event);
3475
3476   return handled;
3477 }
3478
3479 static gint
3480 gtk_window_enter_notify_event (GtkWidget        *widget,
3481                                GdkEventCrossing *event)
3482 {
3483   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
3484   g_return_val_if_fail (event != NULL, FALSE);
3485
3486   return FALSE;
3487 }
3488
3489 static gint
3490 gtk_window_leave_notify_event (GtkWidget        *widget,
3491                                GdkEventCrossing *event)
3492 {
3493   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
3494   g_return_val_if_fail (event != NULL, FALSE);
3495
3496   return FALSE;
3497 }
3498
3499 static gint
3500 gtk_window_focus_in_event (GtkWidget     *widget,
3501                            GdkEventFocus *event)
3502 {
3503   GtkWindow *window = GTK_WINDOW (widget);
3504   GdkEventFocus fevent;
3505
3506   /* It appears spurious focus in events can occur when
3507    *  the window is hidden. So we'll just check to see if
3508    *  the window is visible before actually handling the
3509    *  event
3510    */
3511   if (GTK_WIDGET_VISIBLE (widget))
3512     {
3513       window->has_focus = TRUE;
3514       
3515       if (window->focus_widget &&
3516           window->focus_widget != widget &&
3517           !GTK_WIDGET_HAS_FOCUS (window->focus_widget))
3518         {
3519           fevent.type = GDK_FOCUS_CHANGE;
3520           fevent.window = window->focus_widget->window;
3521           fevent.in = TRUE;
3522
3523           gtk_widget_event (window->focus_widget, (GdkEvent*) &fevent);
3524         }
3525     }
3526
3527   return FALSE;
3528 }
3529
3530 static gint
3531 gtk_window_focus_out_event (GtkWidget     *widget,
3532                             GdkEventFocus *event)
3533 {
3534   GtkWindow *window = GTK_WINDOW (widget);
3535   GdkEventFocus fevent;
3536
3537   window->has_focus = FALSE;
3538   
3539   if (window->focus_widget &&
3540       window->focus_widget != widget &&
3541       GTK_WIDGET_HAS_FOCUS (window->focus_widget))
3542     {
3543       fevent.type = GDK_FOCUS_CHANGE;
3544       fevent.window = window->focus_widget->window;
3545       fevent.in = FALSE;
3546
3547       gtk_widget_event (window->focus_widget, (GdkEvent*) &fevent);
3548     }
3549
3550   return FALSE;
3551 }
3552
3553 static GdkAtom atom_rcfiles = GDK_NONE;
3554
3555 static void
3556 gtk_window_read_rcfiles (GtkWidget *widget,
3557                          GdkEventClient *event)
3558 {
3559   GList *embedded_windows;
3560
3561   embedded_windows = gtk_object_get_data (GTK_OBJECT (widget), "gtk-embedded");
3562   if (embedded_windows)
3563     {
3564       GdkEventClient sev;
3565       int i;
3566       
3567       for (i = 0; i < 5; i++)
3568         sev.data.l[i] = 0;
3569       sev.data_format = 32;
3570       sev.message_type = atom_rcfiles;
3571       
3572       while (embedded_windows)
3573         {
3574           guint xid = GPOINTER_TO_UINT (embedded_windows->data);
3575           gdk_event_send_client_message ((GdkEvent *) &sev, xid);
3576           embedded_windows = embedded_windows->next;
3577         }
3578     }
3579
3580   gtk_rc_reparse_all ();
3581 }
3582
3583 static gint
3584 gtk_window_client_event (GtkWidget      *widget,
3585                          GdkEventClient *event)
3586 {
3587   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
3588   g_return_val_if_fail (event != NULL, FALSE);
3589
3590   if (!atom_rcfiles)
3591     atom_rcfiles = gdk_atom_intern ("_GTK_READ_RCFILES", FALSE);
3592
3593   if (event->message_type == atom_rcfiles) 
3594     gtk_window_read_rcfiles (widget, event);    
3595
3596   return FALSE;
3597 }
3598
3599 static void
3600 gtk_window_check_resize (GtkContainer *container)
3601 {
3602   GtkWindow *window;
3603
3604   g_return_if_fail (GTK_IS_WINDOW (container));
3605
3606   window = GTK_WINDOW (container);
3607
3608   if (GTK_WIDGET_VISIBLE (container))
3609     gtk_window_move_resize (window);
3610 }
3611
3612 static gboolean
3613 gtk_window_focus (GtkWidget        *widget,
3614                   GtkDirectionType  direction)
3615 {
3616   GtkBin *bin;
3617   GtkWindow *window;
3618   GtkContainer *container;
3619   GtkWidget *old_focus_child;
3620   GtkWidget *parent;
3621
3622   container = GTK_CONTAINER (widget);
3623   window = GTK_WINDOW (widget);
3624   bin = GTK_BIN (widget);
3625
3626   old_focus_child = container->focus_child;
3627   
3628   /* We need a special implementation here to deal properly with wrapping
3629    * around in the tab chain without the danger of going into an
3630    * infinite loop.
3631    */
3632   if (old_focus_child)
3633     {
3634       if (gtk_widget_child_focus (old_focus_child, direction))
3635         return TRUE;
3636     }
3637
3638   if (window->focus_widget)
3639     {
3640       /* Wrapped off the end, clear the focus setting for the toplpevel */
3641       parent = window->focus_widget->parent;
3642       while (parent)
3643         {
3644           gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
3645           parent = GTK_WIDGET (parent)->parent;
3646         }
3647       
3648       gtk_window_set_focus (GTK_WINDOW (container), NULL);
3649     }
3650
3651   /* Now try to focus the first widget in the window */
3652   if (bin->child)
3653     {
3654       if (gtk_widget_child_focus (bin->child, direction))
3655         return TRUE;
3656     }
3657
3658   return FALSE;
3659 }
3660
3661 static void
3662 gtk_window_real_set_focus (GtkWindow *window,
3663                            GtkWidget *focus)
3664 {
3665   GdkEventFocus event;
3666   gboolean def_flags = 0;
3667
3668   g_return_if_fail (GTK_IS_WINDOW (window));
3669   
3670   if (window->default_widget)
3671     def_flags = GTK_WIDGET_HAS_DEFAULT (window->default_widget);
3672   
3673   if (window->focus_widget)
3674     {
3675       if (GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget) &&
3676           (window->focus_widget != window->default_widget))
3677         {
3678           GTK_WIDGET_UNSET_FLAGS (window->focus_widget, GTK_HAS_DEFAULT);
3679
3680           if (window->default_widget)
3681             GTK_WIDGET_SET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
3682         }
3683
3684       if (window->has_focus)
3685         {
3686           event.type = GDK_FOCUS_CHANGE;
3687           event.window = window->focus_widget->window;
3688           event.in = FALSE;
3689           
3690           gtk_widget_event (window->focus_widget, (GdkEvent*) &event);
3691         }
3692     }
3693   
3694   window->focus_widget = focus;
3695   
3696   if (window->focus_widget)
3697     {
3698       if (GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget) &&
3699           (window->focus_widget != window->default_widget))
3700         {
3701           if (GTK_WIDGET_CAN_DEFAULT (window->focus_widget))
3702             GTK_WIDGET_SET_FLAGS (window->focus_widget, GTK_HAS_DEFAULT);
3703
3704           if (window->default_widget)
3705             GTK_WIDGET_UNSET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
3706         }
3707
3708       if (window->has_focus)
3709         {
3710           event.type = GDK_FOCUS_CHANGE;
3711           event.window = window->focus_widget->window;
3712           event.in = TRUE;
3713           
3714           gtk_widget_event (window->focus_widget, (GdkEvent*) &event);
3715         }
3716     }
3717   
3718   if (window->default_widget &&
3719       (def_flags != GTK_WIDGET_FLAGS (window->default_widget)))
3720     gtk_widget_queue_draw (window->default_widget);
3721 }
3722
3723 /*********************************
3724  * Functions related to resizing *
3725  *********************************/
3726
3727 /* This function doesn't constrain to geometry hints */
3728 static void 
3729 gtk_window_compute_configure_request_size (GtkWindow *window,
3730                                            guint     *width,
3731                                            guint     *height)
3732 {
3733   GtkRequisition requisition;
3734   GtkWindowGeometryInfo *info;
3735   GtkWidget *widget;
3736
3737   /* Preconditions:
3738    *  - we've done a size request
3739    */
3740   
3741   widget = GTK_WIDGET (window);
3742
3743   info = gtk_window_get_geometry_info (window, FALSE);
3744   
3745   if (window->need_default_size)
3746     {
3747       gtk_widget_get_child_requisition (widget, &requisition);
3748
3749       /* Default to requisition */
3750       *width = requisition.width;
3751       *height = requisition.height;
3752
3753       /* If window is empty so requests 0, default to random nonzero size */
3754        if (*width == 0 && *height == 0)
3755          {
3756            *width = 200;
3757            *height = 200;
3758          }
3759
3760        /* Override requisition with default size */
3761
3762        if (info)
3763          {
3764            if (info->default_width > 0)
3765              *width = info->default_width;
3766            
3767            if (info->default_height > 0)
3768              *height = info->default_height;
3769          }
3770     }
3771   else
3772     {
3773       /* Default to keeping current size */
3774       *width = widget->allocation.width;
3775       *height = widget->allocation.height;
3776     }
3777
3778   /* Override any size with gtk_window_resize() values */
3779   if (info)
3780     {
3781       if (info->resize_width > 0)
3782         *width = info->resize_width;
3783
3784       if (info->resize_height > 0)
3785         *height = info->resize_height;
3786     }
3787 }
3788
3789 static void
3790 gtk_window_compute_configure_request (GtkWindow    *window,
3791                                       GdkRectangle *request,
3792                                       GdkGeometry  *geometry,
3793                                       guint        *flags)
3794 {
3795   GdkGeometry new_geometry;
3796   guint new_flags;
3797   int w, h;
3798   GtkWidget *widget;
3799   GtkWindowPosition pos;
3800   GtkWidget *parent_widget;
3801   GtkWindowGeometryInfo *info;
3802   int x, y;
3803   
3804   widget = GTK_WIDGET (window);
3805   
3806   gtk_widget_size_request (widget, NULL);
3807   gtk_window_compute_configure_request_size (window, &w, &h);
3808   
3809   gtk_window_compute_hints (window, &new_geometry, &new_flags);
3810   gtk_window_constrain_size (window,
3811                              &new_geometry, new_flags,
3812                              w, h,
3813                              &w, &h);
3814
3815   parent_widget = (GtkWidget*) window->transient_parent;
3816   
3817   pos = window->position;
3818   if (pos == GTK_WIN_POS_CENTER_ON_PARENT &&
3819       (parent_widget == NULL ||
3820        !GTK_WIDGET_MAPPED (parent_widget)))
3821     pos = GTK_WIN_POS_NONE;
3822
3823   info = gtk_window_get_geometry_info (window, TRUE);
3824
3825   /* by default, don't change position requested */
3826   x = info->last.configure_request.x;
3827   y = info->last.configure_request.y;
3828   
3829   if (window->need_default_position)
3830     {
3831
3832       /* FIXME this all interrelates with window gravity.
3833        * For most of them I think we want to set GRAVITY_CENTER.
3834        *
3835        * Not sure how to go about that.
3836        */
3837       
3838       switch (pos)
3839         {
3840           /* here we are only handling CENTER_ALWAYS
3841            * as it relates to default positioning,
3842            * where it's equivalent to simply CENTER
3843            */
3844         case GTK_WIN_POS_CENTER_ALWAYS:
3845         case GTK_WIN_POS_CENTER:
3846           {
3847             gint screen_width = gdk_screen_width ();
3848             gint screen_height = gdk_screen_height ();
3849             
3850             x = (screen_width - w) / 2;
3851             y = (screen_height - h) / 2;
3852           }
3853           break;
3854       
3855         case GTK_WIN_POS_CENTER_ON_PARENT:
3856           {
3857             gint ox, oy;
3858             
3859             g_assert (GTK_WIDGET_MAPPED (parent_widget)); /* established earlier */
3860             
3861             gdk_window_get_origin (parent_widget->window,
3862                                    &ox, &oy);
3863             
3864             x = ox + (parent_widget->allocation.width - w) / 2;
3865             y = oy + (parent_widget->allocation.height - h) / 2;
3866           }
3867           break;
3868
3869         case GTK_WIN_POS_MOUSE:
3870           {
3871             gint screen_width = gdk_screen_width ();
3872             gint screen_height = gdk_screen_height ();
3873             int px, py;
3874             
3875             gdk_window_get_pointer (NULL, &px, &py, NULL);
3876             x = px - w / 2;
3877             y = py - h / 2;
3878             x = CLAMP (x, 0, screen_width - w);
3879             y = CLAMP (y, 0, screen_height - h);
3880           }
3881           break;
3882
3883         default:
3884           break;
3885         }
3886     } /* if (window->need_default_position) */
3887
3888   if (window->need_default_position &&
3889       info->initial_pos_set)
3890     {
3891       x = info->initial_x;
3892       y = info->initial_y;
3893       gtk_window_constrain_position (window, w, h, &x, &y);
3894     }
3895   
3896   request->x = x;
3897   request->y = y;
3898   request->width = w;
3899   request->height = h;
3900
3901   if (geometry)
3902     *geometry = new_geometry;
3903   if (flags)
3904     *flags = new_flags;
3905 }
3906
3907 static void
3908 gtk_window_constrain_position (GtkWindow    *window,
3909                                gint          new_width,
3910                                gint          new_height,
3911                                gint         *x,
3912                                gint         *y)
3913 {
3914   /* See long comments in gtk_window_move_resize()
3915    * on when it's safe to call this function.
3916    */
3917   if (window->position == GTK_WIN_POS_CENTER_ALWAYS)
3918     {
3919       gint center_x, center_y;
3920       gint screen_width = gdk_screen_width ();
3921       gint screen_height = gdk_screen_height ();
3922       
3923       center_x = (screen_width - new_width) / 2;
3924       center_y = (screen_height - new_height) / 2;
3925       
3926       *x = center_x;
3927       *y = center_y;
3928     }
3929 }
3930
3931 static void
3932 gtk_window_move_resize (GtkWindow *window)
3933 {
3934   /* Overview:
3935    *
3936    * First we determine whether any information has changed that would
3937    * cause us to revise our last configure request.  If we would send
3938    * a different configure request from last time, then
3939    * configure_request_size_changed = TRUE or
3940    * configure_request_pos_changed = TRUE. configure_request_size_changed
3941    * may be true due to new hints, a gtk_window_resize(), or whatever.
3942    * configure_request_pos_changed may be true due to gtk_window_set_position()
3943    * or gtk_window_move().
3944    *
3945    * If the configure request has changed, we send off a new one.  To
3946    * ensure GTK invariants are maintained (resize queue does what it
3947    * should), we go ahead and size_allocate the requested size in this
3948    * function.
3949    *
3950    * If the configure request has not changed, we don't ever resend
3951    * it, because it could mean fighting the user or window manager.
3952    *
3953    * 
3954    *   To prepare the configure request, we come up with a base size/pos:
3955    *      - the one from gtk_window_move()/gtk_window_resize()
3956    *      - else default_width, default_height if we haven't ever
3957    *        been mapped
3958    *      - else the size request if we haven't ever been mapped,
3959    *        as a substitute default size
3960    *      - else the current size of the window, as received from
3961    *        configure notifies (i.e. the current allocation)
3962    *
3963    *   If GTK_WIN_POS_CENTER_ALWAYS is active, we constrain
3964    *   the position request to be centered.
3965    */
3966   GtkWidget *widget;
3967   GtkContainer *container;
3968   GtkWindowGeometryInfo *info;
3969   GdkGeometry new_geometry;
3970   guint new_flags;
3971   GdkRectangle new_request;
3972   gboolean configure_request_size_changed;
3973   gboolean configure_request_pos_changed;
3974   gboolean hints_changed; /* do we need to send these again */
3975   GtkWindowLastGeometryInfo saved_last_info;
3976   
3977   widget = GTK_WIDGET (window);
3978   container = GTK_CONTAINER (widget);
3979   info = gtk_window_get_geometry_info (window, TRUE);
3980   
3981   configure_request_size_changed = FALSE;
3982   configure_request_pos_changed = FALSE;
3983   
3984   gtk_window_compute_configure_request (window, &new_request,
3985                                         &new_geometry, &new_flags);  
3986   
3987   /* This check implies the invariant that we never set info->last
3988    * without setting the hints and sending off a configure request.
3989    *
3990    * If we change info->last without sending the request, we may
3991    * miss a request.
3992    */
3993   if (info->last.configure_request.x != new_request.x ||
3994       info->last.configure_request.y != new_request.y)
3995     configure_request_pos_changed = TRUE;
3996
3997   /* To change, we must be different from BOTH the last request, and
3998    * also our current size as received from the most recent configure
3999    * notify.
4000    *
4001    * If different from last request, it means some sizing
4002    * parameters have changed; but one possible such sizing
4003    * parameter could be the current size.
4004    *
4005    * We never want to re-request our current size, because that could
4006    * lead to some strange infinite loops if a window manager did
4007    * something insane but ICCCM-compliant such as add 2 to all
4008    * requested sizes. (i.e. if the WM always assigned a size that
4009    * was a function of the requested size, rather than a constraint
4010    * applied to requested size - so that requesting current size
4011    * did not result in getting that size back)
4012    *
4013    * So here we detect and prevent any attempt to set size
4014    * to current size.
4015    *
4016    * (FIXME I think some race may be possible here, but
4017    *  perhaps avoided by configure_request_count?)
4018    */
4019   if ((info->last.configure_request.width != new_request.width ||
4020        info->last.configure_request.height != new_request.height) &&
4021       (widget->allocation.width != new_request.width ||
4022        widget->allocation.height != new_request.height))
4023     configure_request_size_changed = TRUE;
4024
4025   
4026   hints_changed = FALSE;
4027   
4028   if (!gtk_window_compare_hints (&info->last.geometry, info->last.flags,
4029                                  &new_geometry, new_flags))
4030     {
4031       hints_changed = TRUE;
4032     }
4033   
4034   /* Position Constraints
4035    * ====================
4036    * 
4037    * POS_CENTER_ALWAYS is conceptually a constraint rather than
4038    * a default. The other POS_ values are used only when the
4039    * window is shown, not after that.
4040    * 
4041    * However, we can't implement a position constraint as
4042    * "anytime the window size changes, center the window"
4043    * because this may well end up fighting the WM or user.  In
4044    * fact it gets in an infinite loop with at least one WM.
4045    *
4046    * Basically, applications are in no way in a position to
4047    * constrain the position of a window, with one exception:
4048    * override redirect windows. (Really the intended purpose
4049    * of CENTER_ALWAYS anyhow, I would think.)
4050    *
4051    * So the way we implement this "constraint" is to say that when WE
4052    * cause a move or resize, i.e. we make a configure request changing
4053    * window size, we recompute the CENTER_ALWAYS position to reflect
4054    * the new window size, and include it in our request.  Also, if we
4055    * just turned on CENTER_ALWAYS we snap to center with a new
4056    * request.  Otherwise, if we are just NOTIFIED of a move or resize
4057    * done by someone else e.g. the window manager, we do NOT send a
4058    * new configure request.
4059    *
4060    * For override redirect windows, this works fine; all window
4061    * sizes are from our configure requests. For managed windows,
4062    * it is at least semi-sane, though who knows what the
4063    * app author is thinking.
4064    */
4065
4066   /* This condition should be kept in sync with the condition later on
4067    * that determines whether we send a configure request.  i.e. we
4068    * should do this position constraining anytime we were going to
4069    * send a configure request anyhow, plus when constraints have
4070    * changed.
4071    */
4072   if (configure_request_pos_changed ||
4073       configure_request_size_changed ||
4074       hints_changed ||
4075       info->position_constraints_changed)
4076     {
4077       /* We request the constrained position if:
4078        *  - we were changing position, and need to clamp
4079        *    the change to the constraint
4080        *  - we're changing the size anyway
4081        *  - set_position() was called to toggle CENTER_ALWAYS on
4082        */
4083
4084       gtk_window_constrain_position (window,
4085                                      new_request.width,
4086                                      new_request.height,
4087                                      &new_request.x,
4088                                      &new_request.y);
4089       
4090       /* Update whether we need to request a move */
4091       if (info->last.configure_request.x != new_request.x ||
4092           info->last.configure_request.y != new_request.y)
4093         configure_request_pos_changed = TRUE;
4094       else
4095         configure_request_pos_changed = FALSE;
4096     }
4097
4098 #if 0
4099   {
4100     int notify_x, notify_y;
4101
4102     /* this is the position from the last configure notify */
4103     gdk_window_get_position (widget->window, &notify_x, &notify_y);
4104     
4105     g_print ("--- %s ---\n"
4106              "last : %d,%d\t%d x %d\n"
4107              "this : %d,%d\t%d x %d\n"
4108              "alloc: %d,%d\t%d x %d\n"
4109              "req  :      \t%d x %d\n"
4110              "size_changed: %d pos_changed: %d hints_changed: %d\n"
4111              "configure_notify_received: %d\n"
4112              "configure_request_count: %d\n"
4113              "position_constraints_changed: %d\n",
4114              window->title ? window->title : "(no title)",
4115              info->last.configure_request.x,
4116              info->last.configure_request.y,
4117              info->last.configure_request.width,
4118              info->last.configure_request.height,
4119              new_request.x,
4120              new_request.y,
4121              new_request.width,
4122              new_request.height,
4123              notify_x, notify_y,
4124              widget->allocation.width,
4125              widget->allocation.height,
4126              widget->requisition.width,
4127              widget->requisition.height,
4128              configure_request_pos_changed,
4129              configure_request_size_changed,
4130              hints_changed,
4131              window->configure_notify_received,
4132              window->configure_request_count,
4133              info->position_constraints_changed);
4134   }
4135 #endif
4136   
4137   saved_last_info = info->last;
4138   info->last.geometry = new_geometry;
4139   info->last.flags = new_flags;
4140   info->last.configure_request = new_request;
4141   
4142   /* need to set PPosition so the WM will look at our position,
4143    * but we don't want to count PPosition coming and going as a hints
4144    * change for future iterations. So we saved info->last prior to
4145    * this.
4146    */
4147   
4148   /* Also, if the initial position was explicitly set, then we always
4149    * toggle on PPosition. This makes gtk_window_move(window, 0, 0)
4150    * work.
4151    */
4152
4153   /* Also, we toggle on PPosition if GTK_WIN_POS_ is in use and
4154    * this is an initial map
4155    */
4156   
4157   if ((configure_request_pos_changed ||
4158        info->initial_pos_set ||
4159        (window->need_default_position &&
4160         window->position != GTK_WIN_POS_NONE)) &&
4161       (new_flags & GDK_HINT_POS) == 0)
4162     {
4163       new_flags |= GDK_HINT_POS;
4164       hints_changed = TRUE;
4165     }
4166   
4167   /* Set hints if necessary
4168    */
4169   if (hints_changed)
4170     gdk_window_set_geometry_hints (widget->window,
4171                                    &new_geometry,
4172                                    new_flags);
4173
4174   /* handle resizing/moving and widget tree allocation
4175    */
4176   if (window->configure_notify_received)
4177     { 
4178       GtkAllocation allocation;
4179
4180       /* If we have received a configure event since
4181        * the last time in this function, we need to
4182        * accept our new size and size_allocate child widgets.
4183        * (see gtk_window_configure_event() for more details).
4184        *
4185        * 1 or more configure notifies may have been received.
4186        * Also, configure_notify_received will only be TRUE
4187        * if all expected configure notifies have been received
4188        * (one per configure request), as an optimization.
4189        *
4190        */
4191       window->configure_notify_received = FALSE;
4192
4193       /* gtk_window_configure_event() filled in widget->allocation */
4194       allocation = widget->allocation;
4195       gtk_widget_size_allocate (widget, &allocation);
4196       gtk_widget_queue_draw (widget);
4197
4198       /* If the configure request changed, it means that
4199        * we either:
4200        *   1) coincidentally changed hints or widget properties
4201        *      impacting the configure request before getting
4202        *      a configure notify, or
4203        *   2) some broken widget is changing its size request
4204        *      during size allocation, resulting in
4205        *      a false appearance of changed configure request.
4206        *
4207        * For 1), we could just go ahead and ask for the
4208        * new size right now, but doing that for 2)
4209        * might well be fighting the user (and can even
4210        * trigger a loop). Since we really don't want to
4211        * do that, we requeue a resize in hopes that
4212        * by the time it gets handled, the child has seen
4213        * the light and is willing to go along with the
4214        * new size. (this happens for the zvt widget, since
4215        * the size_allocate() above will have stored the
4216        * requisition corresponding to the new size in the
4217        * zvt widget)
4218        *
4219        * This doesn't buy us anything for 1), but it shouldn't
4220        * hurt us too badly, since it is what would have
4221        * happened if we had gotten the configure event before
4222        * the new size had been set.
4223        */
4224
4225       if (configure_request_size_changed ||
4226           configure_request_pos_changed)
4227         {
4228           /* Don't change the recorded last info after all, because we
4229            * haven't actually updated to the new info yet - we decided
4230            * to postpone our configure request until later.
4231            */
4232           info->last = saved_last_info;
4233           
4234           gtk_widget_queue_resize (widget); /* migth recurse for GTK_RESIZE_IMMEDIATE */
4235         }
4236     }
4237   else if (configure_request_pos_changed ||
4238            configure_request_size_changed ||
4239            hints_changed)
4240     {
4241       /* We are in one of the following situations:
4242        * A. configure_request_size_changed
4243        *    our requisition has changed and we need a different window size,
4244        *    so we request it from the window manager.
4245        * B. !configure_request_size_changed
4246        *    the window manager wouldn't assign us the size we requested, in this
4247        *    case we don't try to request a new size with every resize.
4248        * C. !configure_request_size_changed && hints_changed
4249        *    the window manager rejects our size, but we have just changed the
4250        *    window manager hints, so there's a certain chance our request will
4251        *    be honoured this time, so we try again.
4252        * D. configure_request_pos_changed
4253        *    we need to move to a new position, in which case we can also request
4254        *    a new size since any of A-C might also apply.
4255        */
4256
4257       /* Now send the configure request */
4258       if (configure_request_pos_changed)
4259         {
4260           if (window->frame)
4261             {
4262               gdk_window_move_resize (window->frame,
4263                                       new_request.x - window->frame_left,
4264                                       new_request.y - window->frame_top,
4265                                       new_request.width + window->frame_left + window->frame_right,
4266                                       new_request.height + window->frame_top + window->frame_bottom);
4267               gdk_window_resize (GTK_WIDGET (window)->window,
4268                                  new_request.width, new_request.height);
4269             }
4270           else
4271             gdk_window_move_resize (widget->window,
4272                                     new_request.x, new_request.y,
4273                                     new_request.width, new_request.height);
4274         }
4275       else  /* only size changed */
4276         {
4277           if (window->frame)
4278             gdk_window_resize (window->frame,
4279                                new_request.width + window->frame_left + window->frame_right,
4280                                new_request.height + window->frame_top + window->frame_bottom);
4281           gdk_window_resize (widget->window,
4282                              new_request.width, new_request.height);
4283         }
4284       
4285       /* Increment the number of have-not-yet-received-notify requests */
4286       window->configure_request_count += 1;
4287
4288       /* We have now sent a request since the last position constraint
4289        * change and definitely don't need a an initial size again (not
4290        * resetting this here can lead to infinite loops for
4291        * GTK_RESIZE_IMMEDIATE containers)
4292        */
4293       info->position_constraints_changed = FALSE;
4294       window->need_default_position = FALSE;
4295
4296       /* for GTK_RESIZE_QUEUE toplevels, we are now awaiting a new
4297        * configure event in response to our resizing request.
4298        * the configure event will cause a new resize with
4299        * ->configure_notify_received=TRUE.
4300        * until then, we want to
4301        * - discard expose events
4302        * - coalesce resizes for our children
4303        * - defer any window resizes until the configure event arrived
4304        * to achieve this, we queue a resize for the window, but remove its
4305        * resizing handler, so resizing will not be handled from the next
4306        * idle handler but when the configure event arrives.
4307        *
4308        * FIXME: we should also dequeue the pending redraws here, since
4309        * we handle those ourselves upon ->configure_notify_received==TRUE.
4310        */
4311       if (container->resize_mode == GTK_RESIZE_QUEUE)
4312         {
4313           gtk_widget_queue_resize (widget);
4314           _gtk_container_dequeue_resize_handler (container);
4315         }
4316     }
4317   else
4318     {
4319       /* Not requesting anything new from WM, just had a queue resize
4320        * for some reason, so handle the resize queue
4321        */
4322       if (container->resize_widgets)
4323         gtk_container_resize_children (container);
4324     }
4325 }
4326
4327 /* Compare two sets of Geometry hints for equality.
4328  */
4329 static gboolean
4330 gtk_window_compare_hints (GdkGeometry *geometry_a,
4331                           guint        flags_a,
4332                           GdkGeometry *geometry_b,
4333                           guint        flags_b)
4334 {
4335   if (flags_a != flags_b)
4336     return FALSE;
4337   
4338   if ((flags_a & GDK_HINT_MIN_SIZE) &&
4339       (geometry_a->min_width != geometry_b->min_width ||
4340        geometry_a->min_height != geometry_b->min_height))
4341     return FALSE;
4342
4343   if ((flags_a & GDK_HINT_MAX_SIZE) &&
4344       (geometry_a->max_width != geometry_b->max_width ||
4345        geometry_a->max_height != geometry_b->max_height))
4346     return FALSE;
4347
4348   if ((flags_a & GDK_HINT_BASE_SIZE) &&
4349       (geometry_a->base_width != geometry_b->base_width ||
4350        geometry_a->base_height != geometry_b->base_height))
4351     return FALSE;
4352
4353   if ((flags_a & GDK_HINT_ASPECT) &&
4354       (geometry_a->min_aspect != geometry_b->min_aspect ||
4355        geometry_a->max_aspect != geometry_b->max_aspect))
4356     return FALSE;
4357
4358   if ((flags_a & GDK_HINT_RESIZE_INC) &&
4359       (geometry_a->width_inc != geometry_b->width_inc ||
4360        geometry_a->height_inc != geometry_b->height_inc))
4361     return FALSE;
4362
4363   if ((flags_a & GDK_HINT_WIN_GRAVITY) &&
4364       geometry_a->win_gravity != geometry_b->win_gravity)
4365     return FALSE;
4366
4367   return TRUE;
4368 }
4369
4370 void
4371 _gtk_window_constrain_size (GtkWindow   *window,
4372                             gint         width,
4373                             gint         height,
4374                             gint        *new_width,
4375                             gint        *new_height)
4376 {
4377   GtkWindowGeometryInfo *info;
4378
4379   g_return_if_fail (GTK_IS_WINDOW (window));
4380
4381   info = window->geometry_info;
4382   if (info)
4383     {
4384       GdkWindowHints flags = info->last.flags;
4385       GdkGeometry *geometry = &info->last.geometry;
4386       
4387       gtk_window_constrain_size (window,
4388                                  geometry,
4389                                  flags,
4390                                  width,
4391                                  height,
4392                                  new_width,
4393                                  new_height);
4394     }
4395 }
4396
4397 static void 
4398 gtk_window_constrain_size (GtkWindow   *window,
4399                            GdkGeometry *geometry,
4400                            guint        flags,
4401                            gint         width,
4402                            gint         height,
4403                            gint        *new_width,
4404                            gint        *new_height)
4405 {
4406   gdk_window_constrain_size (geometry, flags, width, height,
4407                              new_width, new_height);
4408 }
4409
4410 /* Compute the set of geometry hints and flags for a window
4411  * based on the application set geometry, and requisiition
4412  * of the window. gtk_widget_size_request() must have been
4413  * called first.
4414  */
4415 static void
4416 gtk_window_compute_hints (GtkWindow   *window,
4417                           GdkGeometry *new_geometry,
4418                           guint       *new_flags)
4419 {
4420   GtkWidget *widget;
4421   gint extra_width = 0;
4422   gint extra_height = 0;
4423   GtkWindowGeometryInfo *geometry_info;
4424   GtkRequisition requisition;
4425
4426   g_return_if_fail (GTK_IS_WINDOW (window));
4427
4428   widget = GTK_WIDGET (window);
4429   
4430   gtk_widget_get_child_requisition (widget, &requisition);
4431   geometry_info = gtk_window_get_geometry_info (GTK_WINDOW (widget), FALSE);
4432
4433   if (geometry_info)
4434     {
4435       *new_flags = geometry_info->mask;
4436       *new_geometry = geometry_info->geometry;
4437     }
4438   else
4439     {
4440       *new_flags = 0;
4441     }
4442   
4443   if (geometry_info && geometry_info->widget)
4444     {
4445       extra_width = widget->requisition.width - geometry_info->widget->requisition.width;
4446       extra_height = widget->requisition.height - geometry_info->widget->requisition.height;
4447     }
4448
4449   /* We don't want to set GDK_HINT_POS in here, we just set it
4450    * in gtk_window_move_resize() when we want the position
4451    * honored.
4452    */
4453   
4454   if (*new_flags & GDK_HINT_BASE_SIZE)
4455     {
4456       new_geometry->base_width += extra_width;
4457       new_geometry->base_height += extra_height;
4458     }
4459   else if (!(*new_flags & GDK_HINT_MIN_SIZE) &&
4460            (*new_flags & GDK_HINT_RESIZE_INC) &&
4461            ((extra_width != 0) || (extra_height != 0)))
4462     {
4463       *new_flags |= GDK_HINT_BASE_SIZE;
4464       
4465       new_geometry->base_width = extra_width;
4466       new_geometry->base_height = extra_height;
4467     }
4468   
4469   if (*new_flags & GDK_HINT_MIN_SIZE)
4470     {
4471       if (new_geometry->min_width < 0)
4472         new_geometry->min_width = requisition.width;
4473       else
4474         new_geometry->min_width += extra_width;
4475
4476       if (new_geometry->min_height < 0)
4477         new_geometry->min_height = requisition.height;
4478       else
4479         new_geometry->min_height += extra_height;
4480     }
4481   else if (!window->allow_shrink)
4482     {
4483       *new_flags |= GDK_HINT_MIN_SIZE;
4484       
4485       new_geometry->min_width = requisition.width;
4486       new_geometry->min_height = requisition.height;
4487     }
4488   
4489   if (*new_flags & GDK_HINT_MAX_SIZE)
4490     {
4491       if (new_geometry->max_width < 0)
4492         new_geometry->max_width = requisition.width;
4493       else
4494         new_geometry->max_width += extra_width;
4495
4496       if (new_geometry->max_height < 0)
4497         new_geometry->max_width = requisition.height;
4498       else
4499         new_geometry->max_height += extra_height;
4500     }
4501   else if (!window->allow_grow)
4502     {
4503       *new_flags |= GDK_HINT_MAX_SIZE;
4504       
4505       new_geometry->max_width = requisition.width;
4506       new_geometry->max_height = requisition.height;
4507     }
4508
4509   *new_flags |= GDK_HINT_WIN_GRAVITY;
4510   new_geometry->win_gravity = window->gravity;
4511 }
4512
4513 /***********************
4514  * Redrawing functions *
4515  ***********************/
4516
4517 static void
4518 gtk_window_paint (GtkWidget     *widget,
4519                   GdkRectangle *area)
4520 {
4521   gtk_paint_flat_box (widget->style, widget->window, GTK_STATE_NORMAL, 
4522                       GTK_SHADOW_NONE, area, widget, "base", 0, 0, -1, -1);
4523 }
4524
4525 static gint
4526 gtk_window_expose (GtkWidget      *widget,
4527                    GdkEventExpose *event)
4528 {
4529   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
4530   g_return_val_if_fail (event != NULL, FALSE);
4531
4532   if (!GTK_WIDGET_APP_PAINTABLE (widget))
4533     gtk_window_paint (widget, &event->area);
4534   
4535   if (GTK_WIDGET_CLASS (parent_class)->expose_event)
4536     return GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
4537
4538   return TRUE;
4539 }
4540
4541 /**
4542  * gtk_window_set_has_frame:
4543  * @window: a #GtkWindow
4544  * @setting: a boolean
4545  * 
4546  * If this function is called on a window with setting of TRUE, before
4547  * it is realized or showed, it will have a "frame" window around
4548  * widget->window, accessible in window->frame. Using the signal 
4549  * frame_event you can recieve all events targeted at the frame.
4550  * 
4551  * This function is used by the linux-fb port to implement managed
4552  * windows, but it could concievably be used by X-programs that
4553  * want to do their own window decorations.
4554  **/
4555 void
4556 gtk_window_set_has_frame (GtkWindow *window, 
4557                           gboolean   setting)
4558 {
4559   g_return_if_fail (GTK_IS_WINDOW (window));
4560   g_return_if_fail (!GTK_WIDGET_REALIZED (window));
4561
4562   window->has_frame = setting != FALSE;
4563 }
4564
4565 /**
4566  * gtk_window_get_has_frame:
4567  * @window: a #GtkWindow
4568  * 
4569  * Returns whether the window has a frame window exterior to
4570  * widget->window. See gtk_window_set_has_frame ().
4571  *
4572  * Return value: %TRUE if a frame has been added to the window
4573  *   via gtk_widow_has_frame
4574  **/
4575 gboolean
4576 gtk_window_get_has_frame (GtkWindow *window)
4577 {
4578   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
4579
4580   return window->has_frame;
4581 }
4582
4583 /**
4584  * gtk_window_set_frame_dimensions:
4585  * @window: a #GtkWindow that has a frame
4586  * @left: The width of the left border
4587  * @top: The height of the top border
4588  * @right: The width of the right border
4589  * @bottom: The height of the bottom border
4590  *
4591  * For windows with frames (see #gtk_window_set_has_frame) this function
4592  * can be used to change the size of the frame border.
4593  **/
4594 void
4595 gtk_window_set_frame_dimensions (GtkWindow *window, 
4596                                  gint       left,
4597                                  gint       top,
4598                                  gint       right,
4599                                  gint       bottom)
4600 {
4601   GtkWidget *widget = GTK_WIDGET (window);
4602
4603   g_return_if_fail (GTK_IS_WINDOW (window));
4604
4605   if (window->frame_left == left &&
4606       window->frame_top == top &&
4607       window->frame_right == right && 
4608       window->frame_bottom == bottom)
4609     return;
4610
4611   window->frame_left = left;
4612   window->frame_top = top;
4613   window->frame_right = right;
4614   window->frame_bottom = bottom;
4615
4616   if (GTK_WIDGET_REALIZED (widget) && window->frame)
4617     {
4618       gint width = widget->allocation.width + left + right;
4619       gint height = widget->allocation.height + top + bottom;
4620       gdk_window_resize (window->frame, width, height);
4621       gtk_decorated_window_move_resize_window (window,
4622                                                left, top,
4623                                                widget->allocation.width,
4624                                                widget->allocation.height);
4625     }
4626 }
4627
4628 /**
4629  * gtk_window_present:
4630  * @window: a #GtkWindow
4631  *
4632  * Presents a window to the user. This may mean raising the window
4633  * in the stacking order, deiconifying it, moving it to the current
4634  * desktop, and/or giving it the keyboard focus, possibly dependent
4635  * on the user's platform, window manager, and preferences.
4636  *
4637  * If @window is hidden, this function calls gtk_widget_show()
4638  * as well.
4639  * 
4640  * This function should be used when the user tries to open a window
4641  * that's already open. Say for example the preferences dialog is
4642  * currently open, and the user chooses Preferences from the menu
4643  * a second time; use gtk_window_present() to move the already-open dialog
4644  * where the user can see it.
4645  * 
4646  **/
4647 void
4648 gtk_window_present (GtkWindow *window)
4649 {
4650   GtkWidget *widget;
4651
4652   g_return_if_fail (GTK_IS_WINDOW (window));
4653
4654   widget = GTK_WIDGET (window);
4655
4656   if (GTK_WIDGET_VISIBLE (window))
4657     {
4658       g_assert (widget->window != NULL);
4659       
4660       gdk_window_show (widget->window);
4661
4662       /* note that gdk_window_focus() will also move the window to
4663        * the current desktop, for WM spec compliant window managers.
4664        */
4665       gdk_window_focus (widget->window,
4666                         gtk_get_current_event_time ());
4667     }
4668   else
4669     {
4670       gtk_widget_show (widget);
4671     }
4672 }
4673
4674 /**
4675  * gtk_window_iconify:
4676  * @window: a #GtkWindow
4677  *
4678  * Asks to iconify (i.e. minimize) the specified @window. Note that you
4679  * shouldn't assume the window is definitely iconified afterward,
4680  * because other entities (e.g. the user or window manager) could
4681  * deiconify it again, or there may not be a window manager in which
4682  * case iconification isn't possible, etc. But normally the window
4683  * will end up iconified. Just don't write code that crashes if not.
4684  *
4685  * It's permitted to call this function before showing a window,
4686  * in which case the window will be iconified before it ever appears
4687  * onscreen.
4688  *
4689  * You can track iconification via the "window_state_event" signal
4690  * on #GtkWidget.
4691  * 
4692  **/
4693 void
4694 gtk_window_iconify (GtkWindow *window)
4695 {
4696   GtkWidget *widget;
4697   GdkWindow *toplevel;
4698   
4699   g_return_if_fail (GTK_IS_WINDOW (window));
4700
4701   widget = GTK_WIDGET (window);
4702
4703   window->iconify_initially = TRUE;
4704
4705   if (window->frame)
4706     toplevel = window->frame;
4707   else
4708     toplevel = widget->window;
4709   
4710   if (toplevel != NULL)
4711     gdk_window_iconify (toplevel);
4712 }
4713
4714 /**
4715  * gtk_window_deiconify:
4716  * @window: a #GtkWindow
4717  *
4718  * Asks to deiconify (i.e. unminimize) the specified @window. Note
4719  * that you shouldn't assume the window is definitely deiconified
4720  * afterward, because other entities (e.g. the user or window manager)
4721  * could iconify it again before your code which assumes
4722  * deiconification gets to run.
4723  *
4724  * You can track iconification via the "window_state_event" signal
4725  * on #GtkWidget.
4726  **/
4727 void
4728 gtk_window_deiconify (GtkWindow *window)
4729 {
4730   GtkWidget *widget;
4731   GdkWindow *toplevel;
4732   
4733   g_return_if_fail (GTK_IS_WINDOW (window));
4734
4735   widget = GTK_WIDGET (window);
4736
4737   window->iconify_initially = FALSE;
4738
4739   if (window->frame)
4740     toplevel = window->frame;
4741   else
4742     toplevel = widget->window;
4743   
4744   if (toplevel != NULL)
4745     gdk_window_deiconify (toplevel);
4746 }
4747
4748 /**
4749  * gtk_window_stick:
4750  * @window: a #GtkWindow
4751  *
4752  * Asks to stick @window, which means that it will appear on all user
4753  * desktops. Note that you shouldn't assume the window is definitely
4754  * stuck afterward, because other entities (e.g. the user or window
4755  * manager) could unstick it again, and some window managers do not
4756  * support sticking windows. But normally the window will end up
4757  * stuck. Just don't write code that crashes if not.
4758  *
4759  * It's permitted to call this function before showing a window.
4760  *
4761  * You can track stickiness via the "window_state_event" signal
4762  * on #GtkWidget.
4763  * 
4764  **/
4765 void
4766 gtk_window_stick (GtkWindow *window)
4767 {
4768   GtkWidget *widget;
4769   GdkWindow *toplevel;
4770   
4771   g_return_if_fail (GTK_IS_WINDOW (window));
4772
4773   widget = GTK_WIDGET (window);
4774
4775   window->stick_initially = TRUE;
4776
4777   if (window->frame)
4778     toplevel = window->frame;
4779   else
4780     toplevel = widget->window;
4781   
4782   if (toplevel != NULL)
4783     gdk_window_stick (toplevel);
4784 }
4785
4786 /**
4787  * gtk_window_unstick:
4788  * @window: a #GtkWindow
4789  *
4790  * Asks to unstick @window, which means that it will appear on only
4791  * one of the user's desktops. Note that you shouldn't assume the
4792  * window is definitely unstuck afterward, because other entities
4793  * (e.g. the user or window manager) could stick it again. But
4794  * normally the window will end up stuck. Just don't write code that
4795  * crashes if not.
4796  *
4797  * You can track stickiness via the "window_state_event" signal
4798  * on #GtkWidget.
4799  * 
4800  **/
4801 void
4802 gtk_window_unstick (GtkWindow *window)
4803 {
4804   GtkWidget *widget;
4805   GdkWindow *toplevel;
4806   
4807   g_return_if_fail (GTK_IS_WINDOW (window));
4808
4809   widget = GTK_WIDGET (window);
4810
4811   window->stick_initially = FALSE;
4812
4813   if (window->frame)
4814     toplevel = window->frame;
4815   else
4816     toplevel = widget->window;
4817   
4818   if (toplevel != NULL)
4819     gdk_window_unstick (toplevel);
4820 }
4821
4822 /**
4823  * gtk_window_maximize:
4824  * @window: a #GtkWindow
4825  *
4826  * Asks to maximize @window, so that it becomes full-screen. Note that
4827  * you shouldn't assume the window is definitely maximized afterward,
4828  * because other entities (e.g. the user or window manager) could
4829  * unmaximize it again, and not all window managers support
4830  * maximization. But normally the window will end up maximized. Just
4831  * don't write code that crashes if not.
4832  *
4833  * It's permitted to call this function before showing a window,
4834  * in which case the window will be maximized when it appears onscreen
4835  * initially.
4836  *
4837  * You can track maximization via the "window_state_event" signal
4838  * on #GtkWidget.
4839  * 
4840  **/
4841 void
4842 gtk_window_maximize (GtkWindow *window)
4843 {
4844   GtkWidget *widget;
4845   GdkWindow *toplevel;
4846   
4847   g_return_if_fail (GTK_IS_WINDOW (window));
4848
4849   widget = GTK_WIDGET (window);
4850
4851   window->maximize_initially = TRUE;
4852
4853   if (window->frame)
4854     toplevel = window->frame;
4855   else
4856     toplevel = widget->window;
4857   
4858   if (toplevel != NULL)
4859     gdk_window_maximize (toplevel);
4860 }
4861
4862 /**
4863  * gtk_window_unmaximize:
4864  * @window: a #GtkWindow
4865  *
4866  * Asks to unmaximize @window. Note that you shouldn't assume the
4867  * window is definitely unmaximized afterward, because other entities
4868  * (e.g. the user or window manager) could maximize it again, and not
4869  * all window managers honor requests to unmaximize. But normally the
4870  * window will end up unmaximized. Just don't write code that crashes
4871  * if not.
4872  *
4873  * You can track maximization via the "window_state_event" signal
4874  * on #GtkWidget.
4875  * 
4876  **/
4877 void
4878 gtk_window_unmaximize (GtkWindow *window)
4879 {
4880   GtkWidget *widget;
4881   GdkWindow *toplevel;
4882   
4883   g_return_if_fail (GTK_IS_WINDOW (window));
4884
4885   widget = GTK_WIDGET (window);
4886
4887   window->maximize_initially = FALSE;
4888
4889   if (window->frame)
4890     toplevel = window->frame;
4891   else
4892     toplevel = widget->window;
4893   
4894   if (toplevel != NULL)
4895     gdk_window_unmaximize (toplevel);
4896 }
4897
4898 /**
4899  * gtk_window_set_resizable:
4900  * @window: a #GtkWindow
4901  * @resizable: %TRUE if the user can resize this window
4902  *
4903  * Sets whether the user can resize a window. Windows are user resizable
4904  * by default.
4905  **/
4906 void
4907 gtk_window_set_resizable (GtkWindow *window,
4908                           gboolean   resizable)
4909 {
4910   g_return_if_fail (GTK_IS_WINDOW (window));
4911
4912   gtk_window_set_policy (window, FALSE, resizable, FALSE);
4913 }
4914
4915 /**
4916  * gtk_window_get_resizable:
4917  * @window: a #GtkWindow
4918  *
4919  * Gets the value set by gtk_window_set_resizable().
4920  *
4921  * Return value: %TRUE if the user can resize the window
4922  **/
4923 gboolean
4924 gtk_window_get_resizable (GtkWindow *window)
4925 {
4926   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
4927
4928   /* allow_grow is most likely to indicate the semantic concept we
4929    * mean by "resizable" (and will be a reliable indicator if
4930    * set_policy() hasn't been called)
4931    */
4932   return window->allow_grow;
4933 }
4934
4935 /**
4936  * gtk_window_set_gravity:
4937  * @window: a #GtkWindow
4938  * @gravity: window gravity
4939  *
4940  * Window gravity defines the meaning of coordinates passed to
4941  * gtk_window_move(). See gtk_window_move() and #GdkGravity for
4942  * more details.
4943  *
4944  * The default window gravity is #GDK_GRAVITY_NORTH_WEST which will
4945  * typically "do what you mean."
4946  *
4947  **/
4948 void
4949 gtk_window_set_gravity (GtkWindow *window,
4950                         GdkGravity gravity)
4951 {
4952   g_return_if_fail (GTK_IS_WINDOW (window));
4953
4954   if (gravity != window->gravity)
4955     {
4956       window->gravity = gravity;
4957
4958       /* gtk_window_move_resize() will adapt gravity
4959        */
4960       gtk_widget_queue_resize (GTK_WIDGET (window));
4961     }
4962 }
4963
4964 /**
4965  * gtk_window_get_gravity:
4966  * @window: a #GtkWindow
4967  *
4968  * Gets the value set by gtk_window_set_gravity().
4969  *
4970  * Return value: window gravity
4971  **/
4972 GdkGravity
4973 gtk_window_get_gravity (GtkWindow *window)
4974 {
4975   g_return_val_if_fail (GTK_IS_WINDOW (window), 0);
4976
4977   return window->gravity;
4978 }
4979
4980 /**
4981  * gtk_window_begin_resize_drag:
4982  * @window: a #GtkWindow
4983  * @button: mouse button that initiated the drag
4984  * @edge: position of the resize control
4985  * @root_x: X position where the user clicked to initiate the drag, in root window coordinates
4986  * @root_y: Y position where the user clicked to initiate the drag
4987  * @timestamp: timestamp from the click event that initiated the drag
4988  *
4989  * Starts resizing a window. This function is used if an application
4990  * has window resizing controls. When GDK can support it, the resize
4991  * will be done using the standard mechanism for the window manager or
4992  * windowing system. Otherwise, GDK will try to emulate window
4993  * resizing, potentially not all that well, depending on the windowing system.
4994  * 
4995  **/
4996 void
4997 gtk_window_begin_resize_drag  (GtkWindow    *window,
4998                                GdkWindowEdge edge,
4999                                gint          button,
5000                                gint          root_x,
5001                                gint          root_y,
5002                                guint32       timestamp)
5003 {
5004   GtkWidget *widget;
5005   GdkWindow *toplevel;
5006   
5007   g_return_if_fail (GTK_IS_WINDOW (window));
5008   g_return_if_fail (GTK_WIDGET_VISIBLE (window));
5009   
5010   widget = GTK_WIDGET (window);
5011   
5012   if (window->frame)
5013     toplevel = window->frame;
5014   else
5015     toplevel = widget->window;
5016   
5017   gdk_window_begin_resize_drag (toplevel,
5018                                 edge, button,
5019                                 root_x, root_y,
5020                                 timestamp);
5021 }
5022
5023 /**
5024  * gtk_window_get_frame_dimensions:
5025  * @window: a #GtkWindow
5026  * @left: location to store the width of the frame at the left, or %NULL
5027  * @top: location to store the height of the frame at the top, or %NULL
5028  * @right: location to store the width of the frame at the returns, or %NULL
5029  * @bottom: location to store the height of the frame at the bottom, or %NULL
5030  *
5031  * Retrieves the dimensions of the frame window for this toplevel.
5032  * See gtk_window_set_has_frame(), gtk_window_set_frame_dimensions().
5033  **/
5034 void
5035 gtk_window_get_frame_dimensions (GtkWindow *window,
5036                                  gint      *left,
5037                                  gint      *top,
5038                                  gint      *right,
5039                                  gint      *bottom)
5040 {
5041   g_return_if_fail (GTK_IS_WINDOW (window));
5042
5043   if (left)
5044     *left = window->frame_left;
5045   if (top)
5046     *top = window->frame_top;
5047   if (right)
5048     *top = window->frame_right;
5049   if (bottom)
5050     *top = window->frame_bottom;
5051 }
5052
5053 /**
5054  * gtk_window_begin_move_drag:
5055  * @window: a #GtkWindow
5056  * @button: mouse button that initiated the drag
5057  * @root_x: X position where the user clicked to initiate the drag, in root window coordinates
5058  * @root_y: Y position where the user clicked to initiate the drag
5059  * @timestamp: timestamp from the click event that initiated the drag
5060  *
5061  * Starts moving a window. This function is used if an application
5062  * has window movement grips. When GDK can support it, the window movement
5063  * will be done using the standard mechanism for the window manager or
5064  * windowing system. Otherwise, GDK will try to emulate window
5065  * movement, potentially not all that well, depending on the windowing system.
5066  * 
5067  **/
5068 void
5069 gtk_window_begin_move_drag  (GtkWindow *window,
5070                              gint       button,
5071                              gint       root_x,
5072                              gint       root_y,
5073                              guint32    timestamp)
5074 {
5075   GtkWidget *widget;
5076   GdkWindow *toplevel;
5077   
5078   g_return_if_fail (GTK_IS_WINDOW (window));
5079   g_return_if_fail (GTK_WIDGET_VISIBLE (window));
5080   
5081   widget = GTK_WIDGET (window);
5082   
5083   if (window->frame)
5084     toplevel = window->frame;
5085   else
5086     toplevel = widget->window;
5087   
5088   gdk_window_begin_move_drag (toplevel,
5089                               button,
5090                               root_x, root_y,
5091                               timestamp);
5092 }
5093
5094
5095 static void
5096 gtk_window_group_class_init (GtkWindowGroupClass *klass)
5097 {
5098 }
5099
5100 GtkType
5101 gtk_window_group_get_type (void)
5102 {
5103   static GtkType window_group_type = 0;
5104
5105   if (!window_group_type)
5106     {
5107       static const GTypeInfo window_group_info =
5108       {
5109         sizeof (GtkWindowGroupClass),
5110         NULL,           /* base_init */
5111         NULL,           /* base_finalize */
5112         (GClassInitFunc) gtk_window_group_class_init,
5113         NULL,           /* class_finalize */
5114         NULL,           /* class_data */
5115         sizeof (GtkWindowGroup),
5116         16,             /* n_preallocs */
5117         (GInstanceInitFunc) NULL,
5118       };
5119
5120       window_group_type = g_type_register_static (G_TYPE_OBJECT, "GtkWindowGroup", &window_group_info, 0);
5121     }
5122
5123   return window_group_type;
5124 }
5125
5126 /**
5127  * gtk_window_group_new:
5128  * 
5129  * Create a new #GtkWindowGroup object. Grabs added with
5130  * gtk_window_grab_add() only affect windows within the
5131  * same #GtkWindowGroup
5132  * 
5133  * Return value: 
5134  **/
5135 GtkWindowGroup *
5136 gtk_window_group_new (void)
5137 {
5138   return g_object_new (GTK_TYPE_WINDOW_GROUP, NULL);
5139 }
5140
5141 static void
5142 window_group_cleanup_grabs (GtkWindowGroup *group,
5143                             GtkWindow      *window)
5144 {
5145   GSList *tmp_list;
5146   GSList *to_remove = NULL;
5147
5148   tmp_list = group->grabs;
5149   while (tmp_list)
5150     {
5151       if (gtk_widget_get_toplevel (tmp_list->data) == (GtkWidget*) window)
5152         to_remove = g_slist_prepend (to_remove, g_object_ref (tmp_list->data));
5153       tmp_list = tmp_list->next;
5154     }
5155
5156   while (to_remove)
5157     {
5158       gtk_grab_remove (to_remove->data);
5159       g_object_unref (to_remove->data);
5160       to_remove = g_slist_delete_link (to_remove, to_remove);
5161     }
5162 }
5163
5164 /**
5165  * gtk_window_group_add_widget:
5166  * @window_group: a #GtkWindowGroup
5167  * @window: the #GtkWindow to add
5168  * 
5169  * Add a window to a #GtkWindowGroup. 
5170  **/
5171 void
5172 gtk_window_group_add_window (GtkWindowGroup *window_group,
5173                              GtkWindow      *window)
5174 {
5175   g_return_if_fail (GTK_IS_WINDOW_GROUP (window_group));
5176   g_return_if_fail (GTK_IS_WINDOW (window));
5177
5178   if (window->group != window_group)
5179     {
5180       g_object_ref (window);
5181       g_object_ref (window_group);
5182       
5183       if (window->group)
5184         gtk_window_group_remove_window (window->group, window);
5185       else
5186         window_group_cleanup_grabs (_gtk_window_get_group (NULL), window);
5187
5188       window->group = window_group;
5189
5190       g_object_unref (window);
5191     }
5192 }
5193
5194 /**
5195  * gtk_window_group_remove_window:
5196  * @window_group: a #GtkWindowGroup
5197  * @window: the #GtkWindow to remove
5198  * 
5199  * Removes a window from a #GtkWindowGroup.
5200  **/
5201 void
5202 gtk_window_group_remove_window (GtkWindowGroup *window_group,
5203                                 GtkWindow      *window)
5204 {
5205   g_return_if_fail (GTK_IS_WINDOW_GROUP (window_group));
5206   g_return_if_fail (GTK_IS_WIDGET (window));
5207   g_return_if_fail (window->group == window_group);
5208
5209   g_object_ref (window);
5210
5211   window_group_cleanup_grabs (window_group, window);
5212   window->group = NULL;
5213   
5214   g_object_unref (G_OBJECT (window_group));
5215   g_object_unref (window);
5216 }
5217
5218 /* Return the group for the window or the default group
5219  */
5220 GtkWindowGroup *
5221 _gtk_window_get_group (GtkWindow *window)
5222 {
5223   if (window && window->group)
5224     return window->group;
5225   else
5226     {
5227       static GtkWindowGroup *default_group = NULL;
5228
5229       if (!default_group)
5230         default_group = gtk_window_group_new ();
5231
5232       return default_group;
5233     }
5234 }
5235
5236
5237 /*
5238   Derived from XParseGeometry() in XFree86  
5239
5240   Copyright 1985, 1986, 1987,1998  The Open Group
5241
5242   All Rights Reserved.
5243
5244   The above copyright notice and this permission notice shall be included
5245   in all copies or substantial portions of the Software.
5246
5247   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
5248   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
5249   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
5250   IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
5251   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
5252   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
5253   OTHER DEALINGS IN THE SOFTWARE.
5254
5255   Except as contained in this notice, the name of The Open Group shall
5256   not be used in advertising or otherwise to promote the sale, use or
5257   other dealings in this Software without prior written authorization
5258   from The Open Group.
5259 */
5260
5261
5262 /*
5263  *    XParseGeometry parses strings of the form
5264  *   "=<width>x<height>{+-}<xoffset>{+-}<yoffset>", where
5265  *   width, height, xoffset, and yoffset are unsigned integers.
5266  *   Example:  "=80x24+300-49"
5267  *   The equal sign is optional.
5268  *   It returns a bitmask that indicates which of the four values
5269  *   were actually found in the string.  For each value found,
5270  *   the corresponding argument is updated;  for each value
5271  *   not found, the corresponding argument is left unchanged. 
5272  */
5273
5274 /* The following code is from Xlib, and is minimally modified, so we
5275  * can track any upstream changes if required.  Don't change this
5276  * code. Or if you do, put in a huge comment marking which thing
5277  * changed.
5278  */
5279
5280 static int
5281 read_int (gchar   *string,
5282           gchar  **next)
5283 {
5284   int result = 0;
5285   int sign = 1;
5286   
5287   if (*string == '+')
5288     string++;
5289   else if (*string == '-')
5290     {
5291       string++;
5292       sign = -1;
5293     }
5294
5295   for (; (*string >= '0') && (*string <= '9'); string++)
5296     {
5297       result = (result * 10) + (*string - '0');
5298     }
5299
5300   *next = string;
5301
5302   if (sign >= 0)
5303     return (result);
5304   else
5305     return (-result);
5306 }
5307
5308 /* 
5309  * Bitmask returned by XParseGeometry().  Each bit tells if the corresponding
5310  * value (x, y, width, height) was found in the parsed string.
5311  */
5312 #define NoValue         0x0000
5313 #define XValue          0x0001
5314 #define YValue          0x0002
5315 #define WidthValue      0x0004
5316 #define HeightValue     0x0008
5317 #define AllValues       0x000F
5318 #define XNegative       0x0010
5319 #define YNegative       0x0020
5320
5321 /* Try not to reformat/modify, so we can compare/sync with X sources */
5322 static int
5323 gtk_XParseGeometry (const char   *string,
5324                     int          *x,
5325                     int          *y,
5326                     unsigned int *width,   
5327                     unsigned int *height)  
5328 {
5329   int mask = NoValue;
5330   char *strind;
5331   unsigned int tempWidth, tempHeight;
5332   int tempX, tempY;
5333   char *nextCharacter;
5334
5335   /* These initializations are just to silence gcc */
5336   tempWidth = 0;
5337   tempHeight = 0;
5338   tempX = 0;
5339   tempY = 0;
5340   
5341   if ( (string == NULL) || (*string == '\0')) return(mask);
5342   if (*string == '=')
5343     string++;  /* ignore possible '=' at beg of geometry spec */
5344
5345   strind = (char *)string;
5346   if (*strind != '+' && *strind != '-' && *strind != 'x') {
5347     tempWidth = read_int(strind, &nextCharacter);
5348     if (strind == nextCharacter) 
5349       return (0);
5350     strind = nextCharacter;
5351     mask |= WidthValue;
5352   }
5353
5354   if (*strind == 'x' || *strind == 'X') {       
5355     strind++;
5356     tempHeight = read_int(strind, &nextCharacter);
5357     if (strind == nextCharacter)
5358       return (0);
5359     strind = nextCharacter;
5360     mask |= HeightValue;
5361   }
5362
5363   if ((*strind == '+') || (*strind == '-')) {
5364     if (*strind == '-') {
5365       strind++;
5366       tempX = -read_int(strind, &nextCharacter);
5367       if (strind == nextCharacter)
5368         return (0);
5369       strind = nextCharacter;
5370       mask |= XNegative;
5371
5372     }
5373     else
5374       { strind++;
5375       tempX = read_int(strind, &nextCharacter);
5376       if (strind == nextCharacter)
5377         return(0);
5378       strind = nextCharacter;
5379       }
5380     mask |= XValue;
5381     if ((*strind == '+') || (*strind == '-')) {
5382       if (*strind == '-') {
5383         strind++;
5384         tempY = -read_int(strind, &nextCharacter);
5385         if (strind == nextCharacter)
5386           return(0);
5387         strind = nextCharacter;
5388         mask |= YNegative;
5389
5390       }
5391       else
5392         {
5393           strind++;
5394           tempY = read_int(strind, &nextCharacter);
5395           if (strind == nextCharacter)
5396             return(0);
5397           strind = nextCharacter;
5398         }
5399       mask |= YValue;
5400     }
5401   }
5402         
5403   /* If strind isn't at the end of the string the it's an invalid
5404                 geometry specification. */
5405
5406   if (*strind != '\0') return (0);
5407
5408   if (mask & XValue)
5409     *x = tempX;
5410   if (mask & YValue)
5411     *y = tempY;
5412   if (mask & WidthValue)
5413     *width = tempWidth;
5414   if (mask & HeightValue)
5415     *height = tempHeight;
5416   return (mask);
5417 }
5418
5419 /**
5420  * gtk_window_parse_geometry:
5421  * @window: a #GtkWindow
5422  * @geometry: geometry string
5423  * 
5424  * Parses a standard X Window System geometry string - see the
5425  * manual page for X (type 'man X') for details on this.
5426  * gtk_window_parse_geometry() does work on all GTK+ ports
5427  * including Win32 but is primarily intended for an X environment.
5428  *
5429  * If either a size or a position can be extracted from the
5430  * geometry string, gtk_window_parse_geometry() returns %TRUE
5431  * and calls gtk_window_set_default_size() and/or gtk_window_move()
5432  * to resize/move the window.
5433  *
5434  * If gtk_window_parse_geometry() returns %TRUE, it will also
5435  * set the #GDK_HINT_USER_POS and/or #GDK_HINT_USER_SIZE hints
5436  * indicating to the window manager that the size/position of
5437  * the window was user-specified. This causes most window
5438  * managers to honor the geometry.
5439  * 
5440  * Return value: %TRUE if string was parsed successfully
5441  **/
5442 gboolean
5443 gtk_window_parse_geometry (GtkWindow   *window,
5444                            const gchar *geometry)
5445 {
5446   gint result, x, y;
5447   guint w, h;
5448   GdkGravity grav;
5449   gboolean size_set, pos_set;
5450   
5451   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
5452   g_return_val_if_fail (geometry != NULL, FALSE);
5453   
5454   result = gtk_XParseGeometry (geometry, &x, &y, &w, &h);
5455
5456   if ((result & WidthValue) == 0 ||
5457       w < 0)
5458     w = -1;
5459   if ((result & HeightValue) == 0 ||
5460       h < 0)
5461     h = -1;
5462
5463   size_set = FALSE;
5464   if ((result & WidthValue) || (result & HeightValue))
5465     {
5466       gtk_window_set_default_size (window, w, h);
5467       size_set = TRUE;
5468     }
5469
5470   gtk_window_get_size (window, &w, &h);
5471   
5472   grav = GDK_GRAVITY_NORTH_WEST;
5473
5474   if ((result & XNegative) && (result & YNegative))
5475     grav = GDK_GRAVITY_SOUTH_EAST;
5476   else if (result & XNegative)
5477     grav = GDK_GRAVITY_NORTH_EAST;
5478   else if (result & YNegative)
5479     grav = GDK_GRAVITY_SOUTH_WEST;
5480
5481   if ((result & XValue) == 0)
5482     x = 0;
5483
5484   if ((result & YValue) == 0)
5485     y = 0;
5486   
5487   if (grav == GDK_GRAVITY_SOUTH_WEST ||
5488       grav == GDK_GRAVITY_SOUTH_EAST)
5489     y = gdk_screen_height () - h;
5490
5491   if (grav == GDK_GRAVITY_SOUTH_EAST ||
5492       grav == GDK_GRAVITY_NORTH_EAST)
5493     x = gdk_screen_width () - w;
5494
5495   if (y < 0)
5496     y = 0;
5497
5498   if (x < 0)
5499     x = 0;
5500
5501   pos_set = FALSE;
5502   if ((result & XValue) || (result & YValue))
5503     {
5504       gtk_window_set_gravity (window, grav);
5505       gtk_window_move (window, x, y);
5506       pos_set = TRUE;
5507     }
5508
5509   if (size_set || pos_set)
5510     {
5511       /* Set USSize, USPosition hints */
5512       GtkWindowGeometryInfo *info;
5513
5514       info = gtk_window_get_geometry_info (window, TRUE);
5515
5516       if (pos_set)
5517         info->mask |= GDK_HINT_USER_POS;
5518       if (size_set)
5519         info->mask |= GDK_HINT_USER_SIZE;
5520     }
5521   
5522   return result != 0;
5523 }