]> Pileus Git - ~andy/gtk/blob - gtk/gtkwindow.c
s/gtk_notebook_nth_page/gtk_notebook_get_nth_page/.
[~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_real_window_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_real_window_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   gtk_signal_emit (GTK_OBJECT (window), window_signals[SET_FOCUS], focus);
338 }
339
340 void
341 gtk_window_set_default (GtkWindow *window,
342                         GtkWidget *default_widget)
343 {
344   g_return_if_fail (window != NULL);
345   g_return_if_fail (GTK_IS_WINDOW (window));
346
347   if (default_widget)
348     g_return_if_fail (GTK_WIDGET_CAN_DEFAULT (default_widget));
349
350   if (window->default_widget != default_widget)
351     {
352       if (window->default_widget)
353         {
354           GTK_WIDGET_UNSET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
355           gtk_widget_draw_default (window->default_widget);
356         }
357
358       window->default_widget = default_widget;
359
360       if (window->default_widget)
361         {
362           GTK_WIDGET_SET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
363           gtk_widget_draw_default (window->default_widget);
364         }
365     }
366 }
367
368 void
369 gtk_window_set_policy (GtkWindow *window,
370                        gint       allow_shrink,
371                        gint       allow_grow,
372                        gint       auto_shrink)
373 {
374   g_return_if_fail (window != NULL);
375   g_return_if_fail (GTK_IS_WINDOW (window));
376
377   window->allow_shrink = (allow_shrink != FALSE);
378   window->allow_grow = (allow_grow != FALSE);
379   window->auto_shrink = (auto_shrink != FALSE);
380
381   gtk_window_set_hints (GTK_WIDGET (window), &GTK_WIDGET (window)->requisition);
382 }
383
384 void
385 gtk_window_add_accel_group (GtkWindow        *window,
386                             GtkAccelGroup    *accel_group)
387 {
388   g_return_if_fail (window != NULL);
389   g_return_if_fail (GTK_IS_WINDOW (window));
390   g_return_if_fail (accel_group != NULL);
391
392   gtk_accel_group_attach (accel_group, GTK_OBJECT (window));
393 }
394
395 void
396 gtk_window_remove_accel_group (GtkWindow       *window,
397                                GtkAccelGroup   *accel_group)
398 {
399   g_return_if_fail (window != NULL);
400   g_return_if_fail (GTK_IS_WINDOW (window));
401   g_return_if_fail (accel_group != NULL);
402
403   gtk_accel_group_detach (accel_group, GTK_OBJECT (window));
404 }
405
406 void
407 gtk_window_set_position (GtkWindow         *window,
408                          GtkWindowPosition  position)
409 {
410   g_return_if_fail (window != NULL);
411   g_return_if_fail (GTK_IS_WINDOW (window));
412
413   window->position = position;
414 }
415
416 gint
417 gtk_window_activate_focus (GtkWindow      *window)
418 {
419   g_return_val_if_fail (window != NULL, FALSE);
420   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
421
422   if (window->focus_widget)
423     {
424       gtk_widget_activate (window->focus_widget);
425       return TRUE;
426     }
427
428   return FALSE;
429 }
430
431 gint
432 gtk_window_activate_default (GtkWindow      *window)
433 {
434   g_return_val_if_fail (window != NULL, FALSE);
435   g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
436
437   if (window->default_widget)
438     {
439       gtk_widget_activate (window->default_widget);
440       return TRUE;
441     }
442
443   return FALSE;
444 }
445
446 void
447 gtk_window_set_modal (GtkWindow *window, gboolean modal)
448 {
449   g_return_if_fail (window != NULL);
450   g_return_if_fail (GTK_IS_WINDOW (window));
451
452   /* If the widget was showed already, adjust it's grab state */
453   if (GTK_WIDGET_VISIBLE(GTK_WIDGET(window)))
454     {
455       if (window->modal && !modal)
456         gtk_grab_remove (GTK_WIDGET(window));
457       else if (!window->modal && modal)
458         gtk_grab_add (GTK_WIDGET(window));
459     }
460   
461   window->modal = modal;
462 }
463
464 void
465 gtk_window_add_embedded_xid (GtkWindow *window, guint xid)
466 {
467   GList *embedded_windows;
468
469   g_return_if_fail (window != NULL);
470   g_return_if_fail (GTK_IS_WINDOW (window));
471   
472   g_print ("add %#x\n", xid);
473
474   embedded_windows = gtk_object_get_data (GTK_OBJECT (window), "gtk-embedded");
475   if (embedded_windows)
476     gtk_object_remove_no_notify_by_id (GTK_OBJECT (window), 
477                                        g_quark_from_static_string ("gtk-embedded"));
478   embedded_windows = g_list_prepend (embedded_windows,
479                                      GUINT_TO_POINTER (xid));
480
481   gtk_object_set_data_full (GTK_OBJECT (window), "gtk-embedded", 
482                             embedded_windows,
483                             embedded_windows ?
484                               (GtkDestroyNotify) g_list_free : NULL);
485 }
486
487 void
488 gtk_window_remove_embedded_xid (GtkWindow *window, guint xid)
489 {
490   GList *embedded_windows;
491   GList *node;
492
493   g_return_if_fail (window != NULL);
494   g_return_if_fail (GTK_IS_WINDOW (window));
495   
496   g_print ("remove %#x\n", xid);
497
498   embedded_windows = gtk_object_get_data (GTK_OBJECT (window), "gtk-embedded");
499   if (embedded_windows)
500     gtk_object_remove_no_notify_by_id (GTK_OBJECT (window), 
501                                        g_quark_from_static_string ("gtk-embedded"));
502
503   node = g_list_find (embedded_windows, GUINT_TO_POINTER (xid));
504   if (node)
505     {
506       embedded_windows = g_list_remove_link (embedded_windows, node);
507       g_list_free_1 (node);
508     }
509   
510   gtk_object_set_data_full (GTK_OBJECT (window), 
511                             "gtk-embedded", embedded_windows,
512                             embedded_windows ?
513                               (GtkDestroyNotify) g_list_free : NULL);
514 }
515
516 static void
517 gtk_window_shutdown (GtkObject *object)
518 {
519   GtkWindow *window;
520
521   g_return_if_fail (object != NULL);
522   g_return_if_fail (GTK_IS_WINDOW (object));
523
524   window = GTK_WINDOW (object);
525
526   gtk_window_set_focus (window, NULL);
527   gtk_window_set_default (window, NULL);
528
529   GTK_OBJECT_CLASS (parent_class)->shutdown (object);
530 }
531
532 static void
533 gtk_window_destroy (GtkObject *object)
534 {
535   g_return_if_fail (object != NULL);
536   g_return_if_fail (GTK_IS_WINDOW (object));
537
538   gtk_container_unregister_toplevel (GTK_CONTAINER (object));
539
540   GTK_OBJECT_CLASS (parent_class)->destroy (object);
541 }
542
543 static void
544 gtk_window_finalize (GtkObject *object)
545 {
546   GtkWindow *window;
547
548   g_return_if_fail (object != NULL);
549   g_return_if_fail (GTK_IS_WINDOW (object));
550
551   window = GTK_WINDOW (object);
552   g_free (window->title);
553   g_free (window->wmclass_name);
554   g_free (window->wmclass_class);
555
556   GTK_OBJECT_CLASS(parent_class)->finalize (object);
557 }
558
559 static void
560 gtk_window_show (GtkWidget *widget)
561 {
562   g_return_if_fail (widget != NULL);
563   g_return_if_fail (GTK_IS_WINDOW (widget));
564
565   GTK_WIDGET_SET_FLAGS (widget, GTK_VISIBLE);
566   gtk_container_check_resize (GTK_CONTAINER (widget));
567   gtk_widget_map (widget);
568
569   if (GTK_WINDOW(widget)->modal)
570       gtk_grab_add(widget);
571       
572 }
573
574 static void
575 gtk_window_hide (GtkWidget *widget)
576 {
577   g_return_if_fail (widget != NULL);
578   g_return_if_fail (GTK_IS_WINDOW (widget));
579
580   GTK_WIDGET_UNSET_FLAGS (widget, GTK_VISIBLE);
581   gtk_widget_unmap (widget);
582
583   if (GTK_WINDOW(widget)->modal)
584       gtk_grab_remove(widget);
585
586 }
587
588 static void
589 gtk_window_map (GtkWidget *widget)
590 {
591   GtkWindow *window;
592
593   g_return_if_fail (widget != NULL);
594   g_return_if_fail (GTK_IS_WINDOW (widget));
595
596   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
597
598   window = GTK_WINDOW (widget);
599
600   if (window->bin.child &&
601       GTK_WIDGET_VISIBLE (window->bin.child) &&
602       !GTK_WIDGET_MAPPED (window->bin.child))
603     gtk_widget_map (window->bin.child);
604
605   gtk_window_set_hints (widget, &widget->requisition);
606   gdk_window_show (widget->window);
607 }
608
609 static void
610 gtk_window_unmap (GtkWidget *widget)
611 {
612   GtkWindow *window;
613
614   g_return_if_fail (widget != NULL);
615   g_return_if_fail (GTK_IS_WINDOW (widget));
616
617   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
618   gdk_window_hide (widget->window);
619
620   window = GTK_WINDOW (widget);
621   window->use_uposition = TRUE;
622 }
623
624 static void
625 gtk_window_realize (GtkWidget *widget)
626 {
627   GtkWindow *window;
628   GdkWindowAttr attributes;
629   gint attributes_mask;
630   
631   g_return_if_fail (widget != NULL);
632   g_return_if_fail (GTK_IS_WINDOW (widget));
633   
634   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
635   window = GTK_WINDOW (widget);
636   
637   switch (window->type)
638     {
639     case GTK_WINDOW_TOPLEVEL:
640       attributes.window_type = GDK_WINDOW_TOPLEVEL;
641       break;
642     case GTK_WINDOW_DIALOG:
643       attributes.window_type = GDK_WINDOW_DIALOG;
644       break;
645     case GTK_WINDOW_POPUP:
646       attributes.window_type = GDK_WINDOW_TEMP;
647       break;
648     }
649    
650   attributes.title = window->title;
651   attributes.wmclass_name = window->wmclass_name;
652   attributes.wmclass_class = window->wmclass_class;
653   attributes.width = widget->allocation.width;
654   attributes.height = widget->allocation.height;
655   attributes.wclass = GDK_INPUT_OUTPUT;
656   attributes.visual = gtk_widget_get_visual (widget);
657   attributes.colormap = gtk_widget_get_colormap (widget);
658   attributes.event_mask = gtk_widget_get_events (widget);
659   attributes.event_mask |= (GDK_EXPOSURE_MASK |
660                             GDK_KEY_PRESS_MASK |
661                             GDK_ENTER_NOTIFY_MASK |
662                             GDK_LEAVE_NOTIFY_MASK |
663                             GDK_FOCUS_CHANGE_MASK |
664                             GDK_STRUCTURE_MASK);
665    
666   attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP;
667   attributes_mask |= (window->title ? GDK_WA_TITLE : 0);
668   attributes_mask |= (window->wmclass_name ? GDK_WA_WMCLASS : 0);
669    
670   widget->window = gdk_window_new (NULL, &attributes, attributes_mask);
671   gdk_window_set_user_data (widget->window, window);
672
673   widget->style = gtk_style_attach (widget->style, widget->window);
674   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
675   gtk_window_paint (widget, NULL);
676 }
677
678 static void
679 gtk_window_size_request (GtkWidget      *widget,
680                          GtkRequisition *requisition)
681 {
682   GtkWindow *window;
683   GtkBin *bin;
684
685   g_return_if_fail (widget != NULL);
686   g_return_if_fail (GTK_IS_WINDOW (widget));
687   g_return_if_fail (requisition != NULL);
688
689   window = GTK_WINDOW (widget);
690   bin = GTK_BIN (window);
691   
692   requisition->width = GTK_CONTAINER (window)->border_width * 2;
693   requisition->height = GTK_CONTAINER (window)->border_width * 2;
694
695   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
696     {
697       gtk_widget_size_request (bin->child, &bin->child->requisition);
698
699       requisition->width += bin->child->requisition.width;
700       requisition->height += bin->child->requisition.height;
701     }
702   else
703     {
704       if (!GTK_WIDGET_VISIBLE (window))
705         GTK_CONTAINER (window)->need_resize = TRUE;
706     }
707 }
708
709 static void
710 gtk_window_size_allocate (GtkWidget     *widget,
711                           GtkAllocation *allocation)
712 {
713   GtkWindow *window;
714   GtkAllocation child_allocation;
715
716   g_return_if_fail (widget != NULL);
717   g_return_if_fail (GTK_IS_WINDOW (widget));
718   g_return_if_fail (allocation != NULL);
719
720   window = GTK_WINDOW (widget);
721   widget->allocation = *allocation;
722
723   if (window->bin.child && GTK_WIDGET_VISIBLE (window->bin.child))
724     {
725       child_allocation.x = GTK_CONTAINER (window)->border_width;
726       child_allocation.y = GTK_CONTAINER (window)->border_width;
727       child_allocation.width = allocation->width - child_allocation.x * 2;
728       child_allocation.height = allocation->height - child_allocation.y * 2;
729
730       gtk_widget_size_allocate (window->bin.child, &child_allocation);
731     }
732 }
733
734 static gint
735 gtk_window_configure_event (GtkWidget         *widget,
736                             GdkEventConfigure *event)
737 {
738   GtkWindow *window;
739   GtkAllocation allocation;
740   gboolean need_expose = FALSE;
741   
742   g_return_val_if_fail (widget != NULL, FALSE);
743   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
744   g_return_val_if_fail (event != NULL, FALSE);
745   
746   window = GTK_WINDOW (widget);
747
748   /* If the window was merely moved, do nothing */
749   if ((widget->allocation.width == event->width) &&
750       (widget->allocation.height == event->height))
751     {
752       if (window->resize_count == 0)      /* The window was merely moved */
753         return FALSE;
754       else
755         {
756           /* We asked for a new size, which was rejected, so the
757            * WM sent us a synthetic configure event. We won't
758            * get the expose event we would normally get (since
759            * we have ForgetGravity), so we need to fake it.
760            */
761           need_expose = TRUE;
762         }
763     }
764         
765   
766   window->handling_resize = TRUE;
767   
768   allocation.x = 0;
769   allocation.y = 0;
770   allocation.width = event->width;
771   allocation.height = event->height;
772   
773   gtk_widget_size_allocate (widget, &allocation);
774   
775   if (window->bin.child &&
776       GTK_WIDGET_VISIBLE (window->bin.child) &&
777       !GTK_WIDGET_MAPPED (window->bin.child))
778     gtk_widget_map (window->bin.child);
779   
780   if (window->resize_count > 0)
781       window->resize_count -= 1;
782   
783   if (need_expose)
784     {
785       GdkEvent temp_event;
786       temp_event.type = GDK_EXPOSE;
787       temp_event.expose.window = widget->window;
788       temp_event.expose.send_event = TRUE;
789       temp_event.expose.area.x = 0;
790       temp_event.expose.area.y = 0;
791       temp_event.expose.area.width = event->width;
792       temp_event.expose.area.height = event->height;
793       temp_event.expose.count = 0;
794       
795       gtk_widget_event (widget, &temp_event);
796     }
797
798   window->handling_resize = FALSE;
799   
800   return FALSE;
801 }
802
803 static gint
804 gtk_window_key_press_event (GtkWidget   *widget,
805                             GdkEventKey *event)
806 {
807   GtkWindow *window;
808   GtkDirectionType direction = 0;
809   gboolean handled;
810
811   g_return_val_if_fail (widget != NULL, FALSE);
812   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
813   g_return_val_if_fail (event != NULL, FALSE);
814
815   window = GTK_WINDOW (widget);
816
817   handled = FALSE;
818   
819   if (window->focus_widget)
820     {
821       handled = gtk_widget_event (window->focus_widget, (GdkEvent*) event);
822     }
823     
824   if (!handled)
825     handled = gtk_accel_groups_activate (GTK_OBJECT (window), event->keyval, event->state);
826
827   if (!handled)
828     {
829       switch (event->keyval)
830         {
831         case GDK_space:
832           if (window->focus_widget)
833             {
834               gtk_widget_activate (window->focus_widget);
835               handled = TRUE;
836             }
837           break;
838         case GDK_Return:
839         case GDK_KP_Enter:
840           if (window->default_widget)
841             {
842               gtk_widget_activate (window->default_widget);
843               handled = TRUE;
844             }
845           else if (window->focus_widget)
846             {
847               gtk_widget_activate (window->focus_widget);
848               handled = TRUE;
849             }
850           break;
851         case GDK_Up:
852         case GDK_Down:
853         case GDK_Left:
854         case GDK_Right:
855         case GDK_Tab:
856         case GDK_ISO_Left_Tab:
857           switch (event->keyval)
858             {
859             case GDK_Up:
860               direction = GTK_DIR_UP;
861               break;
862             case GDK_Down:
863               direction = GTK_DIR_DOWN;
864               break;
865             case GDK_Left:
866               direction = GTK_DIR_LEFT;
867               break;
868             case GDK_Right:
869               direction = GTK_DIR_RIGHT;
870               break;
871             case GDK_Tab:
872             case GDK_ISO_Left_Tab:
873               if (event->state & GDK_SHIFT_MASK)
874                 direction = GTK_DIR_TAB_BACKWARD;
875               else
876                 direction = GTK_DIR_TAB_FORWARD;
877               break;
878             default :
879               direction = GTK_DIR_UP; /* never reached, but makes compiler happy */
880             }
881
882           gtk_container_focus (GTK_CONTAINER (widget), direction);
883
884           if (!GTK_CONTAINER (window)->focus_child)
885             gtk_window_set_focus (GTK_WINDOW (widget), NULL);
886           else
887             handled = TRUE;
888           break;
889         }
890     }
891
892   if (!handled && GTK_WIDGET_CLASS (parent_class)->key_press_event)
893     handled = GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
894
895   return handled;
896 }
897
898 static gint
899 gtk_window_key_release_event (GtkWidget   *widget,
900                               GdkEventKey *event)
901 {
902   GtkWindow *window;
903   gint handled;
904   
905   g_return_val_if_fail (widget != NULL, FALSE);
906   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
907   g_return_val_if_fail (event != NULL, FALSE);
908   
909   window = GTK_WINDOW (widget);
910   handled = FALSE;
911   if (window->focus_widget)
912     {
913       handled = gtk_widget_event (window->focus_widget, (GdkEvent*) event);
914     }
915
916   if (!handled && GTK_WIDGET_CLASS (parent_class)->key_release_event)
917     handled = GTK_WIDGET_CLASS (parent_class)->key_release_event (widget, event);
918
919   return handled;
920 }
921
922 static gint
923 gtk_window_enter_notify_event (GtkWidget        *widget,
924                                GdkEventCrossing *event)
925 {
926   g_return_val_if_fail (widget != NULL, FALSE);
927   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
928   g_return_val_if_fail (event != NULL, FALSE);
929
930   return FALSE;
931 }
932
933 static gint
934 gtk_window_leave_notify_event (GtkWidget        *widget,
935                                GdkEventCrossing *event)
936 {
937   g_return_val_if_fail (widget != NULL, FALSE);
938   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
939   g_return_val_if_fail (event != NULL, FALSE);
940
941   return FALSE;
942 }
943
944 static gint
945 gtk_window_focus_in_event (GtkWidget     *widget,
946                            GdkEventFocus *event)
947 {
948   GtkWindow *window;
949   GdkEventFocus fevent;
950
951   g_return_val_if_fail (widget != NULL, FALSE);
952   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
953   g_return_val_if_fail (event != NULL, FALSE);
954
955   /* It appears spurious focus in events can occur when
956    *  the window is hidden. So we'll just check to see if
957    *  the window is visible before actually handling the
958    *  event
959    */
960   if (GTK_WIDGET_VISIBLE (widget))
961     {
962       window = GTK_WINDOW (widget);
963       if (window->focus_widget && !GTK_WIDGET_HAS_FOCUS (window->focus_widget))
964         {
965           fevent.type = GDK_FOCUS_CHANGE;
966           fevent.window = window->focus_widget->window;
967           fevent.in = TRUE;
968
969           gtk_widget_event (window->focus_widget, (GdkEvent*) &fevent);
970         }
971     }
972
973   return FALSE;
974 }
975
976 static gint
977 gtk_window_focus_out_event (GtkWidget     *widget,
978                             GdkEventFocus *event)
979 {
980   GtkWindow *window;
981   GdkEventFocus fevent;
982
983   g_return_val_if_fail (widget != NULL, FALSE);
984   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
985   g_return_val_if_fail (event != NULL, FALSE);
986
987   window = GTK_WINDOW (widget);
988   if (window->focus_widget && GTK_WIDGET_HAS_FOCUS (window->focus_widget))
989     {
990       fevent.type = GDK_FOCUS_CHANGE;
991       fevent.window = window->focus_widget->window;
992       fevent.in = FALSE;
993
994       gtk_widget_event (window->focus_widget, (GdkEvent*) &fevent);
995     }
996
997   return FALSE;
998 }
999
1000 static GdkAtom atom_rcfiles = GDK_NONE;
1001
1002 static void
1003 gtk_window_read_rcfiles (GtkWidget *widget,
1004                          GdkEventClient *event)
1005 {
1006   GList *embedded_windows;
1007
1008   embedded_windows = gtk_object_get_data (GTK_OBJECT (widget), "gtk-embedded");
1009   if (embedded_windows)
1010     {
1011       GdkEventClient sev;
1012       int i;
1013       
1014       for(i = 0; i < 5; i++)
1015         sev.data.l[i] = 0;
1016       sev.data_format = 32;
1017       sev.message_type = atom_rcfiles;
1018       
1019       while (embedded_windows)
1020         {
1021           guint xid = GPOINTER_TO_UINT (embedded_windows->data);
1022           gdk_event_send_client_message ((GdkEvent *) &sev, xid);
1023           embedded_windows = embedded_windows->next;
1024         }
1025     }
1026
1027   if (gtk_rc_reparse_all ())
1028     {
1029       /* If the above returned true, some of our RC files are out
1030        * of date, so we need to reset all our widgets. Our other
1031        * toplevel windows will also get the message, but by
1032        * then, the RC file will up to date, so we have to tell
1033        * them now.
1034        */
1035       GList *toplevels;
1036       
1037       toplevels = gtk_container_get_toplevels();
1038       while (toplevels)
1039         {
1040           gtk_widget_reset_rc_styles (toplevels->data);
1041           toplevels = toplevels->next;
1042         }
1043     }
1044 }
1045
1046 static gint
1047 gtk_window_client_event (GtkWidget      *widget,
1048                          GdkEventClient *event)
1049 {
1050   g_return_val_if_fail (widget != NULL, FALSE);
1051   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
1052   g_return_val_if_fail (event != NULL, FALSE);
1053
1054   if (!atom_rcfiles)
1055     atom_rcfiles = gdk_atom_intern("_GTK_READ_RCFILES", FALSE);
1056
1057   if(event->message_type == atom_rcfiles) 
1058     gtk_window_read_rcfiles (widget, event);    
1059
1060   return FALSE;
1061 }
1062
1063 static void
1064 gtk_window_check_resize (GtkContainer *container)
1065 {
1066   GtkWindow *window;
1067
1068   g_return_if_fail (container != NULL);
1069   g_return_if_fail (GTK_IS_WINDOW (container));
1070
1071   window = GTK_WINDOW (container);
1072   if (!window->handling_resize)
1073     {
1074       if (GTK_WIDGET_VISIBLE (container))
1075         gtk_window_move_resize (window);
1076       else
1077         GTK_CONTAINER (window)->need_resize = TRUE;
1078     }
1079 }
1080
1081 /* FIXME: we leave container->resize_widgets set under some
1082    circumstances ? */
1083 static void
1084 gtk_window_move_resize (GtkWindow *window)
1085 {
1086   GtkWidget    *widget;
1087   GtkContainer *container;
1088   gint x, y;
1089   gint width, height;
1090   gint screen_width;
1091   gint screen_height;
1092   gboolean needed_resize;
1093   gboolean size_changed;
1094
1095   g_return_if_fail (window != NULL);
1096   g_return_if_fail (GTK_IS_WINDOW (window));
1097
1098   widget = GTK_WIDGET (window);
1099   container = GTK_CONTAINER (widget);
1100
1101   /* Remember old size, to know if we have to reset hints */
1102   width = widget->requisition.width;
1103   height = widget->requisition.height;
1104   gtk_widget_size_request (widget, &widget->requisition);
1105
1106   size_changed = ((width != widget->requisition.width) ||
1107                   (height != widget->requisition.height));
1108   
1109   if (size_changed)
1110     {
1111       gboolean saved_use_upos;
1112
1113       saved_use_upos = window->use_uposition;
1114       gtk_window_set_hints (widget, &widget->requisition);
1115       window->use_uposition = saved_use_upos;
1116     }
1117   
1118   x = -1;
1119   y = -1;
1120   width = widget->requisition.width;
1121   height = widget->requisition.height;
1122   
1123   if (window->use_uposition)
1124     switch (window->position)
1125       {
1126       case GTK_WIN_POS_CENTER:
1127         x = (gdk_screen_width () - width) / 2;
1128         y = (gdk_screen_height () - height) / 2;
1129         gtk_widget_set_uposition (widget, x, y);
1130         break;
1131       case GTK_WIN_POS_MOUSE:
1132         gdk_window_get_pointer (NULL, &x, &y, NULL);
1133         
1134         x -= width / 2;
1135         y -= height / 2;
1136         
1137         screen_width = gdk_screen_width ();
1138         screen_height = gdk_screen_height ();
1139         
1140         if (x < 0)
1141           x = 0;
1142         else if (x > (screen_width - width))
1143           x = screen_width - width;
1144         
1145         if (y < 0)
1146           y = 0;
1147         else if (y > (screen_height - height))
1148           y = screen_height - height;
1149         
1150         gtk_widget_set_uposition (widget, x, y);
1151         break;
1152       }
1153
1154   /* Now, do the resizing */
1155
1156   needed_resize = container->need_resize;
1157   container->need_resize = FALSE;
1158
1159   if ((widget->requisition.width == 0) ||
1160       (widget->requisition.height == 0))
1161     {
1162       widget->requisition.width = 200;
1163       widget->requisition.height = 200;
1164     }
1165   
1166   if (!GTK_WIDGET_REALIZED (window))
1167     {
1168       GtkAllocation allocation;
1169
1170       allocation.x = 0;
1171       allocation.y = 0;
1172       allocation.width = widget->requisition.width;
1173       allocation.height = widget->requisition.height;
1174       
1175       gtk_widget_size_allocate (widget, &allocation);
1176
1177       return;
1178     }
1179   
1180   gdk_window_get_geometry (widget->window, NULL, NULL, &width, &height, NULL);
1181   
1182   /* As an optimization, we don't try to get a new size from the
1183    * window manager if we asked for the same size last time and
1184    * didn't get it */
1185
1186   if (size_changed && 
1187       (((window->auto_shrink &&
1188         ((width != widget->requisition.width) ||
1189          (height != widget->requisition.height)))) ||
1190        ((width < widget->requisition.width) ||
1191         (height < widget->requisition.height))))
1192     {
1193       window->resize_count += 1;
1194       if ((x != -1) && (y != -1))
1195         gdk_window_move_resize (widget->window, x, y,
1196                                 widget->requisition.width,
1197                                 widget->requisition.height);
1198       else
1199         gdk_window_resize (widget->window,
1200                            widget->requisition.width,
1201                            widget->requisition.height);
1202     }
1203   else if (needed_resize)
1204     {
1205       /* The windows contents changed size while it was not
1206        * visible, so reallocate everything, since we didn't
1207        * keep track of what changed
1208        */
1209       GtkAllocation allocation;
1210       
1211       allocation.x = 0;
1212       allocation.y = 0;
1213       allocation.width = widget->requisition.width;
1214       allocation.height = widget->requisition.height;
1215       
1216       gtk_widget_size_allocate (widget, &allocation);
1217     }
1218   else
1219     {
1220       if ((x != -1) && (y != -1))
1221         gdk_window_move (widget->window, x, y);
1222       
1223       gtk_container_resize_children (GTK_CONTAINER (window));
1224     }
1225 }
1226
1227 static void
1228 gtk_real_window_set_focus (GtkWindow *window,
1229                            GtkWidget *focus)
1230 {
1231   GdkEventFocus event;
1232
1233   g_return_if_fail (window != NULL);
1234   g_return_if_fail (GTK_IS_WINDOW (window));
1235
1236   if (focus && !GTK_WIDGET_CAN_FOCUS (focus))
1237     return;
1238
1239   if (window->focus_widget != focus)
1240     {
1241       if (window->focus_widget)
1242         {
1243           event.type = GDK_FOCUS_CHANGE;
1244           event.window = window->focus_widget->window;
1245           event.in = FALSE;
1246
1247           gtk_widget_event (window->focus_widget, (GdkEvent*) &event);
1248         }
1249
1250       window->focus_widget = focus;
1251
1252       if (window->focus_widget)
1253         {
1254           event.type = GDK_FOCUS_CHANGE;
1255           event.window = window->focus_widget->window;
1256           event.in = TRUE;
1257
1258           gtk_widget_event (window->focus_widget, (GdkEvent*) &event);
1259         }
1260     }
1261 }
1262
1263 static void
1264 gtk_window_set_hints (GtkWidget      *widget,
1265                       GtkRequisition *requisition)
1266 {
1267   GtkWindow *window;
1268   GtkWidgetAuxInfo *aux_info;
1269   gint flags;
1270   gint ux, uy;
1271
1272   g_return_if_fail (widget != NULL);
1273   g_return_if_fail (GTK_IS_WINDOW (widget));
1274   g_return_if_fail (requisition != NULL);
1275
1276   if (GTK_WIDGET_REALIZED (widget))
1277     {
1278       window = GTK_WINDOW (widget);
1279
1280       flags = 0;
1281       ux = 0;
1282       uy = 0;
1283
1284       aux_info = gtk_object_get_data (GTK_OBJECT (widget), "gtk-aux-info");
1285       if (aux_info && (aux_info->x != -1) && (aux_info->y != -1))
1286         {
1287           ux = aux_info->x;
1288           uy = aux_info->y;
1289           flags |= GDK_HINT_POS;
1290         }
1291
1292       if (!window->allow_shrink)
1293         flags |= GDK_HINT_MIN_SIZE;
1294       if (!window->allow_grow)
1295         flags |= GDK_HINT_MAX_SIZE;
1296
1297       gdk_window_set_hints (widget->window,
1298                             ux, uy,
1299                             requisition->width, requisition->height,
1300                             requisition->width, requisition->height,
1301                             flags);
1302
1303       if (window->use_uposition && (flags & GDK_HINT_POS))
1304         {
1305           window->use_uposition = FALSE;
1306           gdk_window_move (widget->window, ux, uy);
1307         }
1308     }
1309 }
1310
1311 static void
1312 gtk_window_paint (GtkWidget     *widget,
1313                   GdkRectangle *area)
1314 {
1315   gtk_paint_flat_box (widget->style, widget->window, GTK_STATE_NORMAL, 
1316                       GTK_SHADOW_NONE, area, widget, "base", 0, 0, -1, -1);
1317 }
1318
1319 static gint
1320 gtk_window_expose (GtkWidget      *widget,
1321                    GdkEventExpose *event)
1322 {
1323   g_return_val_if_fail (widget != NULL, FALSE);
1324   g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
1325   g_return_val_if_fail (event != NULL, FALSE);
1326
1327   gtk_window_paint (widget, &event->area);
1328   
1329   if (GTK_WIDGET_CLASS (parent_class)->expose_event)
1330     return (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
1331
1332   return FALSE;
1333 }
1334
1335 static void
1336 gtk_window_draw (GtkWidget    *widget,
1337                  GdkRectangle *area)
1338 {
1339   gtk_window_paint (widget, area);
1340   
1341   if (GTK_WIDGET_CLASS (parent_class)->draw)
1342     (* GTK_WIDGET_CLASS (parent_class)->draw) (widget, area);
1343 }
1344
1345 static void
1346 gtk_window_style_set (GtkWidget *widget,
1347                       GtkStyle  *previous_style)
1348 {
1349    GdkRectangle area;
1350    
1351    if (GTK_WIDGET_REALIZED (widget) &&
1352        !GTK_WIDGET_NO_WINDOW (widget))
1353      {
1354         gtk_style_set_background (widget->style, widget->window, widget->state);
1355
1356         area.x = 0;
1357         area.y = 0;
1358         area.width = widget->allocation.width;
1359         area.height = widget->allocation.height;
1360         gtk_window_draw(widget, &area);
1361
1362         if (GTK_WIDGET_DRAWABLE (widget))
1363           gdk_window_clear (widget->window);
1364      }
1365 }