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