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