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