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