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