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