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