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