]> Pileus Git - ~andy/gtk/blob - gtk/gtkwindow.c
fixed an assertment.
[~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 Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library 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 #include <string.h>
20 #include <limits.h>
21 #include "gdk/gdk.h"
22 #include "gdk/gdkkeysyms.h"
23 #include "gdk/gdkx.h"
24 #include "gtkprivate.h"
25 #include "gtkrc.h"
26 #include "gtksignal.h"
27 #include "gtkwindow.h"
28 #include "gtkbindings.h"
29
30 enum {
31   MOVE_RESIZE,
32   SET_FOCUS,
33   LAST_SIGNAL
34 };
35 enum {
36   ARG_0,
37   ARG_TYPE,
38   ARG_TITLE,
39   ARG_AUTO_SHRINK,
40   ARG_ALLOW_SHRINK,
41   ARG_ALLOW_GROW,
42   ARG_WIN_POS
43 };
44
45 typedef gint (*GtkWindowSignal1) (GtkObject *object,
46                                   gpointer   arg1,
47                                   gpointer   arg2,
48                                   gint       arg3,
49                                   gint       arg4,
50                                   gpointer   data);
51 typedef void (*GtkWindowSignal2) (GtkObject *object,
52                                   gpointer   arg1,
53                                   gpointer   data);
54
55 static void gtk_window_marshal_signal_1 (GtkObject      *object,
56                                          GtkSignalFunc   func,
57                                          gpointer        func_data,
58                                          GtkArg         *args);
59 static void gtk_window_marshal_signal_2 (GtkObject      *object,
60                                          GtkSignalFunc   func,
61                                          gpointer        func_data,
62                                          GtkArg         *args);
63 static void gtk_window_class_init         (GtkWindowClass    *klass);
64 static void gtk_window_init               (GtkWindow         *window);
65 static void gtk_window_set_arg            (GtkWindow         *window,
66                                            GtkArg            *arg,
67                                            guint              arg_id);
68 static void gtk_window_get_arg            (GtkWindow         *window,
69                                            GtkArg            *arg,
70                                            guint              arg_id);
71 static void gtk_window_destroy            (GtkObject         *object);
72 static void gtk_window_finalize           (GtkObject         *object);
73 static void gtk_window_show               (GtkWidget         *widget);
74 static void gtk_window_hide               (GtkWidget         *widget);
75 static void gtk_window_map                (GtkWidget         *widget);
76 static void gtk_window_unmap              (GtkWidget         *widget);
77 static void gtk_window_realize            (GtkWidget         *widget);
78 static void gtk_window_size_request       (GtkWidget         *widget,
79                                            GtkRequisition    *requisition);
80 static void gtk_window_size_allocate      (GtkWidget         *widget,
81                                            GtkAllocation     *allocation);
82 static gint gtk_window_expose_event       (GtkWidget         *widget,
83                                            GdkEventExpose    *event);
84 static gint gtk_window_configure_event    (GtkWidget         *widget,
85                                            GdkEventConfigure *event);
86 static gint gtk_window_key_press_event    (GtkWidget         *widget,
87                                            GdkEventKey       *event);
88 static gint gtk_window_key_release_event  (GtkWidget         *widget,
89                                            GdkEventKey       *event);
90 static gint gtk_window_enter_notify_event (GtkWidget         *widget,
91                                            GdkEventCrossing  *event);
92 static gint gtk_window_leave_notify_event (GtkWidget         *widget,
93                                            GdkEventCrossing  *event);
94 static gint gtk_window_focus_in_event     (GtkWidget         *widget,
95                                            GdkEventFocus     *event);
96 static gint gtk_window_focus_out_event    (GtkWidget         *widget,
97                                            GdkEventFocus     *event);
98 static gint gtk_window_client_event       (GtkWidget         *widget,
99                                            GdkEventClient    *event);
100 static gint gtk_window_need_resize        (GtkContainer      *container);
101 static gint gtk_real_window_move_resize   (GtkWindow         *window,
102                                            gint              *x,
103                                            gint              *y,
104                                            gint               width,
105                                            gint               height);
106 static void gtk_real_window_set_focus     (GtkWindow         *window,
107                                            GtkWidget         *focus);
108 static gint gtk_window_move_resize        (GtkWidget         *widget);
109 static void gtk_window_set_hints          (GtkWidget         *widget,
110                                            GtkRequisition    *requisition);
111
112 static void gtk_window_read_rcfiles       (GtkWidget         *widget,
113                                            GdkEventClient    *event);
114
115
116 static GtkBinClass *parent_class = NULL;
117 static guint window_signals[LAST_SIGNAL] = { 0 };
118
119
120 GtkType
121 gtk_window_get_type (void)
122 {
123   static GtkType window_type = 0;
124
125   if (!window_type)
126     {
127       GtkTypeInfo window_info =
128       {
129         "GtkWindow",
130         sizeof (GtkWindow),
131         sizeof (GtkWindowClass),
132         (GtkClassInitFunc) gtk_window_class_init,
133         (GtkObjectInitFunc) gtk_window_init,
134         (GtkArgSetFunc) gtk_window_set_arg,
135         (GtkArgGetFunc) gtk_window_get_arg,
136       };
137
138       window_type = gtk_type_unique (gtk_bin_get_type (), &window_info);
139     }
140
141   return window_type;
142 }
143
144 static void
145 gtk_window_class_init (GtkWindowClass *klass)
146 {
147   GtkObjectClass *object_class;
148   GtkWidgetClass *widget_class;
149   GtkContainerClass *container_class;
150
151   object_class = (GtkObjectClass*) klass;
152   widget_class = (GtkWidgetClass*) klass;
153   container_class = (GtkContainerClass*) klass;
154
155   parent_class = gtk_type_class (gtk_bin_get_type ());
156
157   gtk_object_add_arg_type ("GtkWindow::type", GTK_TYPE_WINDOW_TYPE, GTK_ARG_READWRITE, ARG_TYPE);
158   gtk_object_add_arg_type ("GtkWindow::title", GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_TITLE);
159   gtk_object_add_arg_type ("GtkWindow::auto_shrink", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_AUTO_SHRINK);
160   gtk_object_add_arg_type ("GtkWindow::allow_shrink", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_ALLOW_SHRINK);
161   gtk_object_add_arg_type ("GtkWindow::allow_grow", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_ALLOW_GROW);
162   gtk_object_add_arg_type ("GtkWindow::window_position", GTK_TYPE_ENUM, GTK_ARG_READWRITE, ARG_WIN_POS);
163
164   window_signals[MOVE_RESIZE] =
165     gtk_signal_new ("move_resize",
166                     GTK_RUN_LAST,
167                     object_class->type,
168                     GTK_SIGNAL_OFFSET (GtkWindowClass, move_resize),
169                     gtk_window_marshal_signal_1,
170                     GTK_TYPE_BOOL, 4,
171                     GTK_TYPE_POINTER, GTK_TYPE_POINTER,
172                     GTK_TYPE_INT, GTK_TYPE_INT);
173
174   window_signals[SET_FOCUS] =
175     gtk_signal_new ("set_focus",
176                     GTK_RUN_LAST,
177                     object_class->type,
178                     GTK_SIGNAL_OFFSET (GtkWindowClass, set_focus),
179                     gtk_window_marshal_signal_2,
180                     GTK_TYPE_NONE, 1,
181                     GTK_TYPE_POINTER);
182
183   gtk_object_class_add_signals (object_class, window_signals, LAST_SIGNAL);
184
185   object_class->destroy = gtk_window_destroy;
186   object_class->finalize = gtk_window_finalize;
187
188   widget_class->show = gtk_window_show;
189   widget_class->hide = gtk_window_hide;
190   widget_class->map = gtk_window_map;
191   widget_class->unmap = gtk_window_unmap;
192   widget_class->realize = gtk_window_realize;
193   widget_class->size_request = gtk_window_size_request;
194   widget_class->size_allocate = gtk_window_size_allocate;
195   widget_class->expose_event = gtk_window_expose_event;
196   widget_class->configure_event = gtk_window_configure_event;
197   widget_class->key_press_event = gtk_window_key_press_event;
198   widget_class->key_release_event = gtk_window_key_release_event;
199   widget_class->enter_notify_event = gtk_window_enter_notify_event;
200   widget_class->leave_notify_event = gtk_window_leave_notify_event;
201   widget_class->focus_in_event = gtk_window_focus_in_event;
202   widget_class->focus_out_event = gtk_window_focus_out_event;
203   widget_class->client_event = gtk_window_client_event;
204
205   container_class->need_resize = gtk_window_need_resize;
206
207   klass->move_resize = gtk_real_window_move_resize;
208   klass->set_focus = gtk_real_window_set_focus;
209 }
210
211 static void
212 gtk_window_init (GtkWindow *window)
213 {
214   GTK_WIDGET_UNSET_FLAGS (window, GTK_NO_WINDOW);
215   GTK_WIDGET_SET_FLAGS (window, GTK_TOPLEVEL);
216
217   window->title = NULL;
218   window->wmclass_name = g_strdup (gdk_progname);
219   window->wmclass_class = g_strdup (gdk_progclass);
220   window->type = GTK_WINDOW_TOPLEVEL;
221   window->focus_widget = NULL;
222   window->default_widget = NULL;
223   window->resize_count = 0;
224   window->need_resize = FALSE;
225   window->allow_shrink = FALSE;
226   window->allow_grow = TRUE;
227   window->auto_shrink = FALSE;
228   window->handling_resize = FALSE;
229   window->position = GTK_WIN_POS_NONE;
230   window->use_uposition = TRUE;
231   
232   gtk_container_register_toplevel (GTK_CONTAINER (window));
233 }
234
235 static void
236 gtk_window_set_arg (GtkWindow  *window,
237                     GtkArg     *arg,
238                     guint       arg_id)
239 {
240   switch (arg_id)
241     {
242     case ARG_TYPE:
243       window->type = GTK_VALUE_ENUM (*arg);
244       break;
245     case ARG_TITLE:
246       gtk_window_set_title (window, GTK_VALUE_STRING (*arg));
247       break;
248     case ARG_AUTO_SHRINK:
249       window->auto_shrink = (GTK_VALUE_BOOL (*arg) != FALSE);
250       gtk_window_set_hints (GTK_WIDGET (window), &GTK_WIDGET (window)->requisition);
251       break;
252     case ARG_ALLOW_SHRINK:
253       window->allow_shrink = (GTK_VALUE_BOOL (*arg) != FALSE);
254       gtk_window_set_hints (GTK_WIDGET (window), &GTK_WIDGET (window)->requisition);
255       break;
256     case ARG_ALLOW_GROW:
257       window->allow_grow = (GTK_VALUE_BOOL (*arg) != FALSE);
258       gtk_window_set_hints (GTK_WIDGET (window), &GTK_WIDGET (window)->requisition);
259       break;
260     case ARG_WIN_POS:
261       gtk_window_position (window, GTK_VALUE_ENUM (*arg));
262       break;
263     default:
264       arg->type = GTK_TYPE_INVALID;
265       break;
266     }
267 }
268
269 static void
270 gtk_window_get_arg (GtkWindow  *window,
271                     GtkArg     *arg,
272                     guint       arg_id)
273 {
274   switch (arg_id)
275     {
276     case ARG_TYPE:
277       GTK_VALUE_ENUM (*arg) = window->type;
278       break;
279     case ARG_TITLE:
280       GTK_VALUE_STRING (*arg) = g_strdup (window->title);
281       break;
282     case ARG_AUTO_SHRINK:
283       GTK_VALUE_BOOL (*arg) = window->auto_shrink;
284       break;
285     case ARG_ALLOW_SHRINK:
286       GTK_VALUE_BOOL (*arg) = window->allow_shrink;
287       break;
288     case ARG_ALLOW_GROW:
289       GTK_VALUE_BOOL (*arg) = window->allow_grow;
290       break;
291     case ARG_WIN_POS:
292       GTK_VALUE_ENUM (*arg) = window->position;
293       break;
294     default:
295       arg->type = GTK_TYPE_INVALID;
296       break;
297     }
298 }
299
300 GtkWidget*
301 gtk_window_new (GtkWindowType type)
302 {
303   GtkWindow *window;
304
305   window = gtk_type_new (gtk_window_get_type ());
306
307   window->type = type;
308
309   return GTK_WIDGET (window);
310 }
311
312 void
313 gtk_window_set_title (GtkWindow   *window,
314                       const gchar *title)
315 {
316   g_return_if_fail (window != NULL);
317   g_return_if_fail (GTK_IS_WINDOW (window));
318
319   if (window->title)
320     g_free (window->title);
321   window->title = g_strdup (title);
322
323   if (GTK_WIDGET_REALIZED (window))
324     gdk_window_set_title (GTK_WIDGET (window)->window, window->title);
325 }
326
327 void
328 gtk_window_set_wmclass (GtkWindow *window,
329                         const gchar *wmclass_name,
330                         const gchar *wmclass_class)
331 {
332   g_return_if_fail (window != NULL);
333   g_return_if_fail (GTK_IS_WINDOW (window));
334
335   g_free (window->wmclass_name);
336   window->wmclass_name = g_strdup (wmclass_name);
337
338   g_free (window->wmclass_class);
339   window->wmclass_class = g_strdup (wmclass_class);
340
341   if (GTK_WIDGET_REALIZED (window))
342     g_warning ("shouldn't set wmclass after window is realized!\n");
343 }
344
345 void
346 gtk_window_set_focus (GtkWindow *window,
347                       GtkWidget *focus)
348 {
349   gtk_signal_emit (GTK_OBJECT (window), window_signals[SET_FOCUS], focus);
350 }
351
352 void
353 gtk_window_set_default (GtkWindow *window,
354                         GtkWidget *default_widget)
355 {
356   g_return_if_fail (window != NULL);
357   g_return_if_fail (GTK_IS_WINDOW (window));
358
359   if (default_widget)
360     g_return_if_fail (GTK_WIDGET_CAN_DEFAULT (default_widget));
361
362   if (window->default_widget != default_widget)
363     {
364       if (window->default_widget)
365         {
366           GTK_WIDGET_UNSET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
367           gtk_widget_draw_default (window->default_widget);
368         }
369
370       window->default_widget = default_widget;
371
372       if (window->default_widget)
373         {
374           GTK_WIDGET_SET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
375           gtk_widget_draw_default (window->default_widget);
376         }
377     }
378 }
379
380 void
381 gtk_window_set_policy (GtkWindow *window,
382                        gint       allow_shrink,
383                        gint       allow_grow,
384                        gint       auto_shrink)
385 {
386   g_return_if_fail (window != NULL);
387   g_return_if_fail (GTK_IS_WINDOW (window));
388
389   window->allow_shrink = (allow_shrink != FALSE);
390   window->allow_grow = (allow_grow != FALSE);
391   window->auto_shrink = (auto_shrink != FALSE);
392
393   gtk_window_set_hints (GTK_WIDGET (window), &GTK_WIDGET (window)->requisition);
394 }
395
396 void
397 gtk_window_add_accel_group (GtkWindow        *window,
398                             GtkAccelGroup    *accel_group)
399 {
400   g_return_if_fail (window != NULL);
401   g_return_if_fail (GTK_IS_WINDOW (window));
402   g_return_if_fail (accel_group != NULL);
403
404   gtk_accel_group_attach (accel_group, GTK_OBJECT (window));
405 }
406
407 void
408 gtk_window_remove_accel_group (GtkWindow       *window,
409                                GtkAccelGroup   *accel_group)
410 {
411   g_return_if_fail (window != NULL);
412   g_return_if_fail (GTK_IS_WINDOW (window));
413   g_return_if_fail (accel_group != NULL);
414
415   gtk_accel_group_detach (accel_group, GTK_OBJECT (window));
416 }
417
418 void
419 gtk_window_position (GtkWindow         *window,
420                      GtkWindowPosition  position)
421 {
422   g_return_if_fail (window != NULL);
423   g_return_if_fail (GTK_IS_WINDOW (window));
424
425   window->position = position;
426 }
427
428 gint
429 gtk_window_activate_focus (GtkWindow      *window)
430 {
431   g_return_val_if_fail (window != NULL, FALSE);
432   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
433
434   if (window->focus_widget)
435     {
436       gtk_widget_activate (window->focus_widget);
437       return TRUE;
438     }
439
440   return FALSE;
441 }
442
443 gint
444 gtk_window_activate_default (GtkWindow      *window)
445 {
446   g_return_val_if_fail (window != NULL, FALSE);
447   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
448
449   if (window->default_widget)
450     {
451       gtk_widget_activate (window->default_widget);
452       return TRUE;
453     }
454
455   return FALSE;
456 }
457
458 static void
459 gtk_window_marshal_signal_1 (GtkObject      *object,
460                              GtkSignalFunc   func,
461                              gpointer        func_data,
462                              GtkArg         *args)
463 {
464   GtkWindowSignal1 rfunc;
465   gint *return_val;
466
467   rfunc = (GtkWindowSignal1) func;
468   return_val = GTK_RETLOC_BOOL (args[4]);
469
470   *return_val = (* rfunc) (object,
471                            GTK_VALUE_POINTER (args[0]),
472                            GTK_VALUE_POINTER (args[1]),
473                            GTK_VALUE_INT (args[2]),
474                            GTK_VALUE_INT (args[3]),
475                            func_data);
476 }
477
478 static void
479 gtk_window_marshal_signal_2 (GtkObject      *object,
480                              GtkSignalFunc   func,
481                              gpointer        func_data,
482                              GtkArg         *args)
483 {
484   GtkWindowSignal2 rfunc;
485
486   rfunc = (GtkWindowSignal2) func;
487
488   (* rfunc) (object, GTK_VALUE_POINTER (args[0]), func_data);
489 }
490
491 static void
492 gtk_window_destroy (GtkObject *object)
493 {
494   g_return_if_fail (object != NULL);
495   g_return_if_fail (GTK_IS_WINDOW (object));
496
497   gtk_container_unregister_toplevel (GTK_CONTAINER (object));
498
499   if (GTK_OBJECT_CLASS (parent_class)->destroy)
500     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
501 }
502
503 static void
504 gtk_window_finalize (GtkObject *object)
505 {
506   GtkWindow *window;
507
508   g_return_if_fail (object != NULL);
509   g_return_if_fail (GTK_IS_WINDOW (object));
510
511   window = GTK_WINDOW (object);
512   g_free (window->title);
513   g_free (window->wmclass_name);
514   g_free (window->wmclass_class);
515
516   GTK_OBJECT_CLASS(parent_class)->finalize (object);
517 }
518
519 static void
520 gtk_window_show (GtkWidget *widget)
521 {
522   g_return_if_fail (widget != NULL);
523   g_return_if_fail (GTK_IS_WINDOW (widget));
524
525   GTK_WIDGET_SET_FLAGS (widget, GTK_VISIBLE);
526   gtk_container_need_resize (GTK_CONTAINER (widget));
527   gtk_widget_map (widget);
528 }
529
530 static void
531 gtk_window_hide (GtkWidget *widget)
532 {
533   g_return_if_fail (widget != NULL);
534   g_return_if_fail (GTK_IS_WINDOW (widget));
535
536   GTK_WIDGET_UNSET_FLAGS (widget, GTK_VISIBLE);
537   gtk_widget_unmap (widget);
538 }
539
540 static void
541 gtk_window_map (GtkWidget *widget)
542 {
543   GtkWindow *window;
544
545   g_return_if_fail (widget != NULL);
546   g_return_if_fail (GTK_IS_WINDOW (widget));
547
548   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
549
550   window = GTK_WINDOW (widget);
551
552   if (window->bin.child &&
553       GTK_WIDGET_VISIBLE (window->bin.child) &&
554       !GTK_WIDGET_MAPPED (window->bin.child))
555     gtk_widget_map (window->bin.child);
556
557   gtk_window_set_hints (widget, &widget->requisition);
558   gdk_window_show (widget->window);
559 }
560
561 static void
562 gtk_window_unmap (GtkWidget *widget)
563 {
564   GtkWindow *window;
565
566   g_return_if_fail (widget != NULL);
567   g_return_if_fail (GTK_IS_WINDOW (widget));
568
569   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
570   gdk_window_hide (widget->window);
571
572   window = GTK_WINDOW (widget);
573   window->use_uposition = TRUE;
574 }
575
576 static void
577 gtk_window_realize (GtkWidget *widget)
578 {
579   GtkWindow *window;
580   GdkWindowAttr attributes;
581   gint attributes_mask;
582
583   g_return_if_fail (widget != NULL);
584   g_return_if_fail (GTK_IS_WINDOW (widget));
585
586   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
587   window = GTK_WINDOW (widget);
588
589   switch (window->type)
590     {
591     case GTK_WINDOW_TOPLEVEL:
592       attributes.window_type = GDK_WINDOW_TOPLEVEL;
593       break;
594     case GTK_WINDOW_DIALOG:
595       attributes.window_type = GDK_WINDOW_DIALOG;
596       break;
597     case GTK_WINDOW_POPUP:
598       attributes.window_type = GDK_WINDOW_TEMP;
599       break;
600     }
601
602   attributes.title = window->title;
603   attributes.wmclass_name = window->wmclass_name;
604   attributes.wmclass_class = window->wmclass_class;
605   attributes.width = widget->allocation.width;
606   attributes.height = widget->allocation.height;
607   attributes.wclass = GDK_INPUT_OUTPUT;
608   attributes.visual = gtk_widget_get_visual (widget);
609   attributes.colormap = gtk_widget_get_colormap (widget);
610   attributes.event_mask = gtk_widget_get_events (widget);
611   attributes.event_mask |= (GDK_EXPOSURE_MASK |
612                             GDK_KEY_PRESS_MASK |
613                             GDK_ENTER_NOTIFY_MASK |
614                             GDK_LEAVE_NOTIFY_MASK |
615                             GDK_FOCUS_CHANGE_MASK |
616                             GDK_STRUCTURE_MASK);
617
618   attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP;
619   attributes_mask |= (window->title ? GDK_WA_TITLE : 0);
620   attributes_mask |= (window->wmclass_name ? GDK_WA_WMCLASS : 0);
621
622   widget->window = gdk_window_new (NULL, &attributes, attributes_mask);
623   gdk_window_set_user_data (widget->window, window);
624
625   widget->style = gtk_style_attach (widget->style, widget->window);
626   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
627 }
628
629 static void
630 gtk_window_size_request (GtkWidget      *widget,
631                          GtkRequisition *requisition)
632 {
633   GtkWindow *window;
634
635   g_return_if_fail (widget != NULL);
636   g_return_if_fail (GTK_IS_WINDOW (widget));
637   g_return_if_fail (requisition != NULL);
638
639   window = GTK_WINDOW (widget);
640
641   if (window->bin.child)
642     {
643       requisition->width = GTK_CONTAINER (window)->border_width * 2;
644       requisition->height = GTK_CONTAINER (window)->border_width * 2;
645
646       gtk_widget_size_request (window->bin.child, &window->bin.child->requisition);
647
648       requisition->width += window->bin.child->requisition.width;
649       requisition->height += window->bin.child->requisition.height;
650     }
651   else
652     {
653       if (!GTK_WIDGET_VISIBLE (window))
654         window->need_resize = TRUE;
655     }
656 }
657
658 static void
659 gtk_window_size_allocate (GtkWidget     *widget,
660                           GtkAllocation *allocation)
661 {
662   GtkWindow *window;
663   GtkAllocation child_allocation;
664
665   g_return_if_fail (widget != NULL);
666   g_return_if_fail (GTK_IS_WINDOW (widget));
667   g_return_if_fail (allocation != NULL);
668
669   window = GTK_WINDOW (widget);
670   widget->allocation = *allocation;
671
672   if (window->bin.child && GTK_WIDGET_VISIBLE (window->bin.child))
673     {
674       child_allocation.x = GTK_CONTAINER (window)->border_width;
675       child_allocation.y = GTK_CONTAINER (window)->border_width;
676       child_allocation.width = allocation->width - child_allocation.x * 2;
677       child_allocation.height = allocation->height - child_allocation.y * 2;
678
679       gtk_widget_size_allocate (window->bin.child, &child_allocation);
680     }
681 }
682
683 static gint
684 gtk_window_expose_event (GtkWidget      *widget,
685                          GdkEventExpose *event)
686 {
687   g_return_val_if_fail (widget != NULL, FALSE);
688   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
689   g_return_val_if_fail (event != NULL, FALSE);
690
691   if (GTK_WIDGET_DRAWABLE (widget))
692     if (GTK_WIDGET_CLASS (parent_class)->expose_event)
693       return (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
694   
695   return FALSE;
696 }
697
698 static gint
699 gtk_window_configure_event (GtkWidget         *widget,
700                             GdkEventConfigure *event)
701 {
702   GtkWindow *window;
703   GtkAllocation allocation;
704   
705   g_return_val_if_fail (widget != NULL, FALSE);
706   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
707   g_return_val_if_fail (event != NULL, FALSE);
708   
709   window = GTK_WINDOW (widget);
710
711   /* If the window was merely moved, do nothing */
712   if ((widget->allocation.width == event->width) &&
713       (widget->allocation.height == event->height) &&
714       (window->resize_count == 0))
715     return FALSE;
716   
717   window->handling_resize = TRUE;
718   
719   allocation.x = 0;
720   allocation.y = 0;
721   allocation.width = event->width;
722   allocation.height = event->height;
723   
724   gtk_widget_size_allocate (widget, &allocation);
725   
726   if (window->bin.child &&
727       GTK_WIDGET_VISIBLE (window->bin.child) &&
728       !GTK_WIDGET_MAPPED (window->bin.child))
729     gtk_widget_map (window->bin.child);
730   
731   if (window->resize_count > 0)
732       window->resize_count -= 1;
733   
734   window->handling_resize = FALSE;
735   
736   return FALSE;
737 }
738
739 static gint
740 gtk_window_key_press_event (GtkWidget   *widget,
741                             GdkEventKey *event)
742 {
743   GtkWindow *window;
744   GtkDirectionType direction = 0;
745   gboolean handled;
746
747   g_return_val_if_fail (widget != NULL, FALSE);
748   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
749   g_return_val_if_fail (event != NULL, FALSE);
750
751   window = GTK_WINDOW (widget);
752
753   handled = FALSE;
754   
755   if (window->focus_widget)
756     {
757       handled = gtk_widget_event (window->focus_widget, (GdkEvent*) event);
758
759       if (!handled)
760         handled = gtk_bindings_activate (GTK_OBJECT (window->focus_widget),
761                                          event->keyval, event->state);
762     }
763     
764   if (!handled)
765     handled = gtk_accel_groups_activate (GTK_OBJECT (window), event->keyval, event->state);
766
767   if (!handled)
768     {
769       switch (event->keyval)
770         {
771         case GDK_space:
772           if (window->focus_widget)
773             {
774               gtk_widget_activate (window->focus_widget);
775               handled = TRUE;
776             }
777           break;
778         case GDK_Return:
779         case GDK_KP_Enter:
780           if (window->default_widget)
781             {
782               gtk_widget_activate (window->default_widget);
783               handled = TRUE;
784             }
785           else if (window->focus_widget)
786             {
787               gtk_widget_activate (window->focus_widget);
788               handled = TRUE;
789             }
790           break;
791         case GDK_Up:
792         case GDK_Down:
793         case GDK_Left:
794         case GDK_Right:
795         case GDK_Tab:
796         case GDK_ISO_Left_Tab:
797           switch (event->keyval)
798             {
799             case GDK_Up:
800               direction = GTK_DIR_UP;
801               break;
802             case GDK_Down:
803               direction = GTK_DIR_DOWN;
804               break;
805             case GDK_Left:
806               direction = GTK_DIR_LEFT;
807               break;
808             case GDK_Right:
809               direction = GTK_DIR_RIGHT;
810               break;
811             case GDK_Tab:
812             case GDK_ISO_Left_Tab:
813               if (event->state & GDK_SHIFT_MASK)
814                 direction = GTK_DIR_TAB_BACKWARD;
815               else
816                 direction = GTK_DIR_TAB_FORWARD;
817               break;
818             default :
819               direction = GTK_DIR_UP; /* never reached, but makes compiler happy */
820             }
821
822           gtk_container_focus (GTK_CONTAINER (widget), direction);
823
824           if (!GTK_CONTAINER (window)->focus_child)
825             gtk_window_set_focus (GTK_WINDOW (widget), NULL);
826           else
827             handled = TRUE;
828           break;
829         }
830     }
831
832   return handled;
833 }
834
835 static gint
836 gtk_window_key_release_event (GtkWidget   *widget,
837                               GdkEventKey *event)
838 {
839   GtkWindow *window;
840   gint handled;
841   
842   g_return_val_if_fail (widget != NULL, FALSE);
843   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
844   g_return_val_if_fail (event != NULL, FALSE);
845   
846   window = GTK_WINDOW (widget);
847   handled = FALSE;
848   if (window->focus_widget)
849     {
850       handled = gtk_widget_event (window->focus_widget, (GdkEvent*) event);
851       
852       if (!handled)
853         handled = gtk_bindings_activate (GTK_OBJECT (window->focus_widget),
854                                          event->keyval, event->state | GDK_AFTER_MASK);
855     }
856   
857   return handled;
858 }
859
860 static gint
861 gtk_window_enter_notify_event (GtkWidget        *widget,
862                                GdkEventCrossing *event)
863 {
864   g_return_val_if_fail (widget != NULL, FALSE);
865   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
866   g_return_val_if_fail (event != NULL, FALSE);
867
868   return FALSE;
869 }
870
871 static gint
872 gtk_window_leave_notify_event (GtkWidget        *widget,
873                                GdkEventCrossing *event)
874 {
875   g_return_val_if_fail (widget != NULL, FALSE);
876   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
877   g_return_val_if_fail (event != NULL, FALSE);
878
879   return FALSE;
880 }
881
882 static gint
883 gtk_window_focus_in_event (GtkWidget     *widget,
884                            GdkEventFocus *event)
885 {
886   GtkWindow *window;
887   GdkEventFocus fevent;
888
889   g_return_val_if_fail (widget != NULL, FALSE);
890   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
891   g_return_val_if_fail (event != NULL, FALSE);
892
893   /* It appears spurious focus in events can occur when
894    *  the window is hidden. So we'll just check to see if
895    *  the window is visible before actually handling the
896    *  event
897    */
898   if (GTK_WIDGET_VISIBLE (widget))
899     {
900       window = GTK_WINDOW (widget);
901       if (window->focus_widget && !GTK_WIDGET_HAS_FOCUS (window->focus_widget))
902         {
903           fevent.type = GDK_FOCUS_CHANGE;
904           fevent.window = window->focus_widget->window;
905           fevent.in = TRUE;
906
907           gtk_widget_event (window->focus_widget, (GdkEvent*) &fevent);
908         }
909     }
910
911   return FALSE;
912 }
913
914 static gint
915 gtk_window_focus_out_event (GtkWidget     *widget,
916                             GdkEventFocus *event)
917 {
918   GtkWindow *window;
919   GdkEventFocus fevent;
920
921   g_return_val_if_fail (widget != NULL, FALSE);
922   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
923   g_return_val_if_fail (event != NULL, FALSE);
924
925   window = GTK_WINDOW (widget);
926   if (window->focus_widget && GTK_WIDGET_HAS_FOCUS (window->focus_widget))
927     {
928       fevent.type = GDK_FOCUS_CHANGE;
929       fevent.window = window->focus_widget->window;
930       fevent.in = FALSE;
931
932       gtk_widget_event (window->focus_widget, (GdkEvent*) &fevent);
933     }
934
935   return FALSE;
936 }
937
938 static void
939 gtk_window_read_rcfiles (GtkWidget *widget,
940                          GdkEventClient *event)
941 {
942   GList *toplevels;
943   
944   if (gtk_rc_reparse_all ())
945     {
946       toplevels = gdk_window_get_toplevels();
947       while (toplevels)
948         {
949           GtkWidget *widget;
950           gdk_window_get_user_data (toplevels->data, (gpointer *)&widget);
951           
952           if (widget)
953             gtk_widget_reset_rc_styles (widget);
954           
955           toplevels = toplevels->next;
956         }
957       g_list_free (toplevels);
958     }
959 }
960
961 static gint
962 gtk_window_client_event (GtkWidget      *widget,
963                          GdkEventClient *event)
964 {
965   static GdkAtom atom_rcfiles = GDK_NONE;
966   g_return_val_if_fail (widget != NULL, FALSE);
967   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
968   g_return_val_if_fail (event != NULL, FALSE);
969
970   if (!atom_rcfiles)
971     atom_rcfiles = gdk_atom_intern("_GTK_READ_RCFILES", FALSE);
972
973   if(event->message_type == atom_rcfiles) 
974     gtk_window_read_rcfiles (widget, event);    
975
976   return FALSE;
977 }
978
979 static gint
980 gtk_window_need_resize (GtkContainer *container)
981 {
982   GtkWindow *window;
983   gint return_val;
984
985   g_return_val_if_fail (container != NULL, FALSE);
986   g_return_val_if_fail (GTK_IS_WINDOW (container), FALSE);
987
988   return_val = FALSE;
989
990   window = GTK_WINDOW (container);
991   if (window->handling_resize)
992     return return_val;
993
994   if (GTK_WIDGET_VISIBLE (container))
995     return_val = gtk_window_move_resize (GTK_WIDGET (window));
996   else
997     window->need_resize = TRUE;
998   
999   return return_val;
1000 }
1001
1002 static gint
1003 gtk_real_window_move_resize (GtkWindow *window,
1004                              gint      *x,
1005                              gint      *y,
1006                              gint       width,
1007                              gint       height)
1008 {
1009   GtkWidget *widget;
1010   gboolean needed_resize;
1011   
1012   g_return_val_if_fail (window != NULL, FALSE);
1013   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
1014   g_return_val_if_fail ((x != NULL) || (y != NULL), FALSE);
1015
1016   widget = GTK_WIDGET (window);
1017
1018   needed_resize = window->need_resize;
1019   window->need_resize = FALSE;
1020
1021   if ((widget->requisition.width == 0) ||
1022       (widget->requisition.height == 0))
1023     {
1024       widget->requisition.width = 200;
1025       widget->requisition.height = 200;
1026     }
1027   
1028   if (!GTK_WIDGET_REALIZED (window))
1029     {
1030       GtkAllocation allocation;
1031
1032       allocation.x = 0;
1033       allocation.y = 0;
1034       allocation.width = widget->requisition.width;
1035       allocation.height = widget->requisition.height;
1036       
1037       gtk_widget_size_allocate (widget, &allocation);
1038
1039       return FALSE;
1040     }
1041   
1042   gdk_window_get_geometry (widget->window, NULL, NULL, &width, &height, NULL);
1043   
1044   if ((window->auto_shrink &&
1045        ((width != widget->requisition.width) ||
1046         (height != widget->requisition.height))) ||
1047       (width < widget->requisition.width) ||
1048       (height < widget->requisition.height))
1049     {
1050       window->resize_count += 1;
1051       if ((*x != -1) && (*y != -1))
1052         gdk_window_move_resize (widget->window, *x, *y,
1053                                 widget->requisition.width,
1054                                 widget->requisition.height);
1055       else
1056         gdk_window_resize (widget->window,
1057                            widget->requisition.width,
1058                            widget->requisition.height);
1059     }
1060   else if (needed_resize)
1061     {
1062       /* The windows contents changed size while it was not
1063        * visible, so reallocate everything, since we didn't
1064        * keep track of what changed
1065        */
1066       GtkAllocation allocation;
1067
1068       allocation.x = 0;
1069       allocation.y = 0;
1070       allocation.width = widget->requisition.width;
1071       allocation.height = widget->requisition.height;
1072       
1073       gtk_widget_size_allocate (widget, &allocation);
1074     }
1075   else
1076     {
1077       /* The window hasn't changed size but one of its children
1078        *  queued a resize request. Which means that the allocation
1079        *  is not sufficient for the requisition of some child.
1080        *  We've already performed a size request at this point,
1081        *  so we simply need to run through the list of resize
1082        *  widgets and reallocate their sizes appropriately. We
1083        *  make the optimization of not performing reallocation
1084        *  for a widget who also has a parent in the resize widgets
1085        *  list. GTK_RESIZE_NEEDED is used for flagging those
1086        *  parents inside this function.
1087        */
1088       GSList *resize_widgets;
1089       GSList *resize_containers;
1090       GSList *node;
1091       
1092       if ((*x != -1) && (*y != -1))
1093         gdk_window_move (widget->window, *x, *y);
1094
1095       resize_widgets = GTK_CONTAINER (window)->resize_widgets;
1096       GTK_CONTAINER (window)->resize_widgets = NULL;
1097       
1098       for (node = resize_widgets; node; node = node->next)
1099         {
1100           widget = node->data;
1101           
1102           GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_NEEDED);
1103           
1104           while (widget && widget->parent &&
1105                  ((widget->allocation.width < widget->requisition.width) ||
1106                   (widget->allocation.height < widget->requisition.height)))
1107             widget = widget->parent;
1108           
1109           GTK_PRIVATE_SET_FLAG (widget, GTK_RESIZE_NEEDED);
1110           node->data = widget;
1111         }
1112       
1113       resize_containers = NULL;
1114       
1115       for (node = resize_widgets; node; node = node->next)
1116         {
1117           GtkWidget *resize_container;
1118           
1119           widget = node->data;
1120           
1121           if (!GTK_WIDGET_RESIZE_NEEDED (widget))
1122             continue;
1123           
1124           resize_container = widget->parent;
1125           
1126           if (resize_container)
1127             {
1128               GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_NEEDED);
1129               widget = resize_container->parent;
1130               
1131               while (widget)
1132                 {
1133                   if (GTK_WIDGET_RESIZE_NEEDED (widget))
1134                     {
1135                       GTK_PRIVATE_UNSET_FLAG (resize_container, GTK_RESIZE_NEEDED);
1136                       resize_container = widget;
1137                     }
1138                   widget = widget->parent;
1139                 }
1140             }
1141           else
1142             resize_container = widget;
1143           
1144           if (!g_slist_find (resize_containers, resize_container))
1145             resize_containers = g_slist_prepend (resize_containers,
1146                                                  resize_container);
1147         }
1148       g_slist_free (resize_widgets);
1149       
1150       for (node = resize_containers; node; node = node->next)
1151         {
1152           widget = node->data;
1153           
1154           GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_NEEDED);
1155           gtk_widget_size_allocate (widget, &widget->allocation);
1156           gtk_widget_queue_draw (widget);
1157         }
1158       g_slist_free (resize_containers);
1159     }
1160
1161   return FALSE;
1162 }
1163
1164 static gint
1165 gtk_window_move_resize (GtkWidget *widget)
1166 {
1167   GtkWindow *window;
1168   gint x, y;
1169   gint width, height;
1170   gint screen_width;
1171   gint screen_height;
1172   gint return_val;
1173
1174   g_return_val_if_fail (widget != NULL, FALSE);
1175   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
1176
1177   window = GTK_WINDOW (widget);
1178   return_val = FALSE;
1179
1180   /* Remember old size, to know if we have to reset hints */
1181   width = widget->requisition.width;
1182   height = widget->requisition.height;
1183   gtk_widget_size_request (widget, &widget->requisition);
1184   
1185   if ((width != widget->requisition.width ||
1186        height != widget->requisition.height))
1187     gtk_window_set_hints (widget, &widget->requisition);
1188   
1189   x = -1;
1190   y = -1;
1191   width = widget->requisition.width;
1192   height = widget->requisition.height;
1193   
1194   if (window->use_uposition)
1195     switch (window->position)
1196       {
1197       case GTK_WIN_POS_CENTER:
1198         x = (gdk_screen_width () - width) / 2;
1199         y = (gdk_screen_height () - height) / 2;
1200         gtk_widget_set_uposition (widget, x, y);
1201         break;
1202       case GTK_WIN_POS_MOUSE:
1203         gdk_window_get_pointer (NULL, &x, &y, NULL);
1204         
1205         x -= width / 2;
1206         y -= height / 2;
1207         
1208         screen_width = gdk_screen_width ();
1209         screen_height = gdk_screen_height ();
1210         
1211         if (x < 0)
1212           x = 0;
1213         else if (x > (screen_width - width))
1214           x = screen_width - width;
1215         
1216         if (y < 0)
1217           y = 0;
1218         else if (y > (screen_height - height))
1219           y = screen_height - height;
1220         
1221         gtk_widget_set_uposition (widget, x, y);
1222         break;
1223       }
1224   
1225   gtk_signal_emit (GTK_OBJECT (widget), window_signals[MOVE_RESIZE],
1226                    &x, &y, width, height, &return_val);
1227
1228   return return_val;
1229 }
1230
1231 static void
1232 gtk_real_window_set_focus (GtkWindow *window,
1233                            GtkWidget *focus)
1234 {
1235   GdkEventFocus event;
1236
1237   g_return_if_fail (window != NULL);
1238   g_return_if_fail (GTK_IS_WINDOW (window));
1239
1240   if (focus && !GTK_WIDGET_CAN_FOCUS (focus))
1241     return;
1242
1243   if (window->focus_widget != focus)
1244     {
1245       if (window->focus_widget)
1246         {
1247           event.type = GDK_FOCUS_CHANGE;
1248           event.window = window->focus_widget->window;
1249           event.in = FALSE;
1250
1251           gtk_widget_event (window->focus_widget, (GdkEvent*) &event);
1252         }
1253
1254       window->focus_widget = focus;
1255
1256       if (window->focus_widget)
1257         {
1258           event.type = GDK_FOCUS_CHANGE;
1259           event.window = window->focus_widget->window;
1260           event.in = TRUE;
1261
1262           gtk_widget_event (window->focus_widget, (GdkEvent*) &event);
1263         }
1264     }
1265 }
1266
1267 static void
1268 gtk_window_set_hints (GtkWidget      *widget,
1269                       GtkRequisition *requisition)
1270 {
1271   GtkWindow *window;
1272   GtkWidgetAuxInfo *aux_info;
1273   gint flags;
1274   gint ux, uy;
1275
1276   g_return_if_fail (widget != NULL);
1277   g_return_if_fail (GTK_IS_WINDOW (widget));
1278   g_return_if_fail (requisition != NULL);
1279
1280   if (GTK_WIDGET_REALIZED (widget))
1281     {
1282       window = GTK_WINDOW (widget);
1283
1284       flags = 0;
1285       ux = 0;
1286       uy = 0;
1287
1288       aux_info = gtk_object_get_data (GTK_OBJECT (widget), "gtk-aux-info");
1289       if (aux_info && (aux_info->x != -1) && (aux_info->y != -1))
1290         {
1291           ux = aux_info->x;
1292           uy = aux_info->y;
1293           flags |= GDK_HINT_POS;
1294         }
1295
1296       if (!window->allow_shrink)
1297         flags |= GDK_HINT_MIN_SIZE;
1298       if (!window->allow_grow)
1299         flags |= GDK_HINT_MAX_SIZE;
1300
1301       gdk_window_set_hints (widget->window, ux, uy,
1302                             requisition->width, requisition->height,
1303                             requisition->width, requisition->height,
1304                             flags);
1305
1306       if (window->use_uposition && (flags & GDK_HINT_POS))
1307         {
1308           window->use_uposition = FALSE;
1309           gdk_window_move (widget->window, ux, uy);
1310         }
1311     }
1312 }