]> Pileus Git - ~andy/gtk/blob - gtk/gtklayout.c
Try adding a #ifndef/#define for XkbKeySymEntry to make up for OSF broken
[~andy/gtk] / gtk / gtklayout.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 Lesser 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  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser 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  * GtkLayout: Widget for scrolling of arbitrary-sized areas.
20  *
21  * Copyright Owen Taylor, 1998
22  */
23
24 /*
25  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
26  * file for a list of people on the GTK+ Team.  See the ChangeLog
27  * files for a list of changes.  These files are distributed with
28  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
29  */
30
31 #include "gdkconfig.h"
32
33 #include "gtklayout.h"
34 #include "gtksignal.h"
35 #include "gtkprivate.h"
36 #include "gtkintl.h"
37 #include "gtkmarshalers.h"
38
39 typedef struct _GtkLayoutChild   GtkLayoutChild;
40
41 struct _GtkLayoutChild {
42   GtkWidget *widget;
43   gint x;
44   gint y;
45 };
46
47 enum {
48    PROP_0,
49    PROP_HADJUSTMENT,
50    PROP_VADJUSTMENT,
51    PROP_WIDTH,
52    PROP_HEIGHT
53 };
54
55 enum {
56   CHILD_PROP_0,
57   CHILD_PROP_X,
58   CHILD_PROP_Y
59 };
60
61 static void gtk_layout_class_init         (GtkLayoutClass *class);
62 static void gtk_layout_get_property       (GObject        *object,
63                                            guint           prop_id,
64                                            GValue         *value,
65                                            GParamSpec     *pspec);
66 static void gtk_layout_set_property       (GObject        *object,
67                                            guint           prop_id,
68                                            const GValue   *value,
69                                            GParamSpec     *pspec);
70 static GObject *gtk_layout_constructor    (GType                  type,
71                                            guint                  n_properties,
72                                            GObjectConstructParam *properties);
73 static void gtk_layout_init               (GtkLayout      *layout);
74 static void gtk_layout_finalize           (GObject        *object);
75 static void gtk_layout_realize            (GtkWidget      *widget);
76 static void gtk_layout_unrealize          (GtkWidget      *widget);
77 static void gtk_layout_map                (GtkWidget      *widget);
78 static void gtk_layout_size_request       (GtkWidget      *widget,
79                                            GtkRequisition *requisition);
80 static void gtk_layout_size_allocate      (GtkWidget      *widget,
81                                            GtkAllocation  *allocation);
82 static gint gtk_layout_expose             (GtkWidget      *widget,
83                                            GdkEventExpose *event);
84 static void gtk_layout_remove             (GtkContainer   *container,
85                                            GtkWidget      *widget);
86 static void gtk_layout_forall             (GtkContainer   *container,
87                                            gboolean        include_internals,
88                                            GtkCallback     callback,
89                                            gpointer        callback_data);
90 static void gtk_layout_set_adjustments    (GtkLayout      *layout,
91                                            GtkAdjustment  *hadj,
92                                            GtkAdjustment  *vadj);
93 static void gtk_layout_set_child_property (GtkContainer   *container,
94                                            GtkWidget      *child,
95                                            guint           property_id,
96                                            const GValue   *value,
97                                            GParamSpec     *pspec);
98 static void gtk_layout_get_child_property (GtkContainer   *container,
99                                            GtkWidget      *child,
100                                            guint           property_id,
101                                            GValue         *value,
102                                            GParamSpec     *pspec);
103 static void gtk_layout_allocate_child     (GtkLayout      *layout,
104                                            GtkLayoutChild *child);
105 static void gtk_layout_adjustment_changed (GtkAdjustment  *adjustment,
106                                            GtkLayout      *layout);
107 static void gtk_layout_style_set          (GtkWidget      *widget,
108                                            GtkStyle       *old_style);
109
110 static void gtk_layout_set_adjustment_upper (GtkAdjustment *adj,
111                                              gdouble        upper,
112                                              gboolean       always_emit_changed);
113
114 static GtkWidgetClass *parent_class = NULL;
115
116 /* Public interface
117  */
118 /**
119  * gtk_layout_new:
120  * @hadjustment: horizontal scroll adjustment, or %NULL
121  * @vadjustment: vertical scroll adjustment, or %NULL
122  * 
123  * Creates a new #GtkLayout. Unless you have a specific adjustment
124  * you'd like the layout to use for scrolling, pass %NULL for
125  * @hadjustment and @vadjustment.
126  * 
127  * Return value: a new #GtkLayout
128  **/
129   
130 GtkWidget*    
131 gtk_layout_new (GtkAdjustment *hadjustment,
132                 GtkAdjustment *vadjustment)
133 {
134   GtkLayout *layout;
135
136   layout = g_object_new (GTK_TYPE_LAYOUT,
137                          "hadjustment", hadjustment,
138                          "vadjustment", vadjustment,
139                          NULL);
140
141   return GTK_WIDGET (layout);
142 }
143
144 /**
145  * gtk_layout_get_hadjustment:
146  * @layout: a #GtkLayout
147  * 
148  * This function should only be called after the layout has been
149  * placed in a #GtkScrolledWindow or otherwise configured for
150  * scrolling. It returns the #GtkAdjustment used for communication
151  * between the horizontal scrollbar and @layout.
152  *
153  * See #GtkScrolledWindow, #GtkScrollbar, #GtkAdjustment for details.
154  * 
155  * Return value: horizontal scroll adjustment
156  **/
157 GtkAdjustment* 
158 gtk_layout_get_hadjustment (GtkLayout     *layout)
159 {
160   g_return_val_if_fail (GTK_IS_LAYOUT (layout), NULL);
161
162   return layout->hadjustment;
163 }
164 /**
165  * gtk_layout_get_vadjustment:
166  * @layout: a #GtkLayout
167  * 
168  * This function should only be called after the layout has been
169  * placed in a #GtkScrolledWindow or otherwise configured for
170  * scrolling. It returns the #GtkAdjustment used for communication
171  * between the vertical scrollbar and @layout.
172  *
173  * See #GtkScrolledWindow, #GtkScrollbar, #GtkAdjustment for details.
174  * 
175  * Return value: vertical scroll adjustment
176  **/
177 GtkAdjustment* 
178 gtk_layout_get_vadjustment (GtkLayout     *layout)
179 {
180   g_return_val_if_fail (GTK_IS_LAYOUT (layout), NULL);
181
182   return layout->vadjustment;
183 }
184
185 static GtkAdjustment *
186 new_default_adjustment (void)
187 {
188   return GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
189 }
190
191 static void           
192 gtk_layout_set_adjustments (GtkLayout     *layout,
193                             GtkAdjustment *hadj,
194                             GtkAdjustment *vadj)
195 {
196   gboolean need_adjust = FALSE;
197
198   g_return_if_fail (GTK_IS_LAYOUT (layout));
199
200   if (hadj)
201     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
202   else if (layout->hadjustment)
203     hadj = new_default_adjustment ();
204   if (vadj)
205     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
206   else if (layout->vadjustment)
207     vadj = new_default_adjustment ();
208   
209   if (layout->hadjustment && (layout->hadjustment != hadj))
210     {
211       gtk_signal_disconnect_by_data (GTK_OBJECT (layout->hadjustment), layout);
212       gtk_object_unref (GTK_OBJECT (layout->hadjustment));
213     }
214   
215   if (layout->vadjustment && (layout->vadjustment != vadj))
216     {
217       gtk_signal_disconnect_by_data (GTK_OBJECT (layout->vadjustment), layout);
218       gtk_object_unref (GTK_OBJECT (layout->vadjustment));
219     }
220   
221   if (layout->hadjustment != hadj)
222     {
223       layout->hadjustment = hadj;
224       gtk_object_ref (GTK_OBJECT (layout->hadjustment));
225       gtk_object_sink (GTK_OBJECT (layout->hadjustment));
226       gtk_layout_set_adjustment_upper (layout->hadjustment, layout->width, FALSE);
227       
228       gtk_signal_connect (GTK_OBJECT (layout->hadjustment), "value_changed",
229                           (GtkSignalFunc) gtk_layout_adjustment_changed,
230                           layout);
231       need_adjust = TRUE;
232     }
233   
234   if (layout->vadjustment != vadj)
235     {
236       layout->vadjustment = vadj;
237       gtk_object_ref (GTK_OBJECT (layout->vadjustment));
238       gtk_object_sink (GTK_OBJECT (layout->vadjustment));
239       gtk_layout_set_adjustment_upper (layout->vadjustment, layout->height, FALSE);
240       
241       gtk_signal_connect (GTK_OBJECT (layout->vadjustment), "value_changed",
242                           (GtkSignalFunc) gtk_layout_adjustment_changed,
243                           layout);
244       need_adjust = TRUE;
245     }
246
247   /* vadj or hadj can be NULL while constructing; don't emit a signal
248      then */
249   if (need_adjust && vadj && hadj)
250     gtk_layout_adjustment_changed (NULL, layout);
251 }
252
253 static void
254 gtk_layout_finalize (GObject *object)
255 {
256   GtkLayout *layout = GTK_LAYOUT (object);
257
258   gtk_object_unref (GTK_OBJECT (layout->hadjustment));
259   gtk_object_unref (GTK_OBJECT (layout->vadjustment));
260
261   G_OBJECT_CLASS (parent_class)->finalize (object);
262 }
263
264 /**
265  * gtk_layout_set_hadjustment:
266  * @layout: a #GtkLayout
267  * @adjustment: new scroll adjustment
268  *
269  * Sets the horizontal scroll adjustment for the layout.
270  *
271  * See #GtkScrolledWindow, #GtkScrollbar, #GtkAdjustment for details.
272  * 
273  **/
274 void           
275 gtk_layout_set_hadjustment (GtkLayout     *layout,
276                             GtkAdjustment *adjustment)
277 {
278   g_return_if_fail (GTK_IS_LAYOUT (layout));
279
280   gtk_layout_set_adjustments (layout, adjustment, layout->vadjustment);
281   g_object_notify (G_OBJECT (layout), "hadjustment");
282 }
283  
284 /**
285  * gtk_layout_set_vadjustment:
286  * @layout: a #GtkLayout
287  * @adjustment: new scroll adjustment
288  *
289  * Sets the vertical scroll adjustment for the layout.
290  *
291  * See #GtkScrolledWindow, #GtkScrollbar, #GtkAdjustment for details.
292  * 
293  **/
294 void           
295 gtk_layout_set_vadjustment (GtkLayout     *layout,
296                             GtkAdjustment *adjustment)
297 {
298   g_return_if_fail (GTK_IS_LAYOUT (layout));
299   
300   gtk_layout_set_adjustments (layout, layout->hadjustment, adjustment);
301   g_object_notify (G_OBJECT (layout), "vadjustment");
302 }
303
304 static GtkLayoutChild*
305 get_child (GtkLayout  *layout,
306            GtkWidget  *widget)
307 {
308   GList *children;
309   
310   children = layout->children;
311   while (children)
312     {
313       GtkLayoutChild *child;
314       
315       child = children->data;
316       children = children->next;
317
318       if (child->widget == widget)
319         return child;
320     }
321
322   return NULL;
323 }
324
325 /**
326  * gtk_layout_put:
327  * @layout: a #GtkLayout
328  * @child_widget: child widget
329  * @x: X position of child widget
330  * @y: Y position of child widget
331  *
332  * Adds @child_widget to @layout, at position (@x,@y).
333  * @layout becomes the new parent container of @child_widget.
334  * 
335  **/
336 void           
337 gtk_layout_put (GtkLayout     *layout, 
338                 GtkWidget     *child_widget, 
339                 gint           x, 
340                 gint           y)
341 {
342   GtkLayoutChild *child;
343
344   g_return_if_fail (GTK_IS_LAYOUT (layout));
345   g_return_if_fail (GTK_IS_WIDGET (child_widget));
346   
347   child = g_new (GtkLayoutChild, 1);
348
349   child->widget = child_widget;
350   child->x = x;
351   child->y = y;
352
353   layout->children = g_list_append (layout->children, child);
354   
355   if (GTK_WIDGET_REALIZED (layout))
356     gtk_widget_set_parent_window (child->widget, layout->bin_window);
357
358   gtk_widget_set_parent (child_widget, GTK_WIDGET (layout));
359 }
360
361 static void
362 gtk_layout_move_internal (GtkLayout       *layout,
363                           GtkWidget       *widget,
364                           gboolean         change_x,
365                           gint             x,
366                           gboolean         change_y,
367                           gint             y)
368 {
369   GtkLayoutChild *child;
370   
371   g_return_if_fail (GTK_IS_LAYOUT (layout));
372   g_return_if_fail (GTK_IS_WIDGET (widget));
373   g_return_if_fail (widget->parent == GTK_WIDGET (layout));  
374   
375   child = get_child (layout, widget);
376
377   g_assert (child);
378
379   gtk_widget_freeze_child_notify (widget);
380   
381   if (change_x)
382     {
383       child->x = x;
384       gtk_widget_child_notify (widget, "x");
385     }
386
387   if (change_y)
388     {
389       child->y = y;
390       gtk_widget_child_notify (widget, "y");
391     }
392
393   gtk_widget_thaw_child_notify (widget);
394   
395   if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (layout))
396     gtk_widget_queue_resize (GTK_WIDGET (widget));
397 }
398
399 /**
400  * gtk_layout_move:
401  * @layout: a #GtkLayout
402  * @child_widget: a current child of @layout
403  * @x: X position to move to
404  * @y: Y position to move to
405  *
406  * Moves a current child of @layout to a new position.
407  * 
408  **/
409 void           
410 gtk_layout_move (GtkLayout     *layout, 
411                  GtkWidget     *child_widget, 
412                  gint           x, 
413                  gint           y)
414 {
415   g_return_if_fail (GTK_IS_LAYOUT (layout));
416   g_return_if_fail (GTK_IS_WIDGET (child_widget));
417   g_return_if_fail (child_widget->parent == GTK_WIDGET (layout));  
418
419   gtk_layout_move_internal (layout, child_widget, TRUE, x, TRUE, y);
420 }
421
422 static void
423 gtk_layout_set_adjustment_upper (GtkAdjustment *adj,
424                                  gdouble        upper,
425                                  gboolean       always_emit_changed)
426 {
427   gboolean changed = FALSE;
428   gboolean value_changed = FALSE;
429   
430   gdouble min = MAX (0., upper - adj->page_size);
431
432   if (upper != adj->upper)
433     {
434       adj->upper = upper;
435       changed = TRUE;
436     }
437       
438   if (adj->value > min)
439     {
440       adj->value = min;
441       value_changed = TRUE;
442     }
443   
444   if (changed || always_emit_changed)
445     gtk_signal_emit_by_name (GTK_OBJECT (adj), "changed");
446   if (value_changed)
447     gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
448 }
449
450 /**
451  * gtk_layout_set_size:
452  * @layout: a #GtkLayout
453  * @width: width of entire scrollable area
454  * @height: height of entire scrollable area
455  *
456  * Sets the size of the scrollable area of the layout.
457  * 
458  **/
459 void
460 gtk_layout_set_size (GtkLayout     *layout, 
461                      guint          width,
462                      guint          height)
463 {
464   GtkWidget *widget;
465   
466   g_return_if_fail (GTK_IS_LAYOUT (layout));
467
468   widget = GTK_WIDGET (layout);
469   
470   g_object_freeze_notify (G_OBJECT (layout));
471   if (width != layout->width)
472      {
473         layout->width = width;
474         g_object_notify (G_OBJECT (layout), "width");
475      }
476   if (height != layout->height)
477      {
478         layout->height = height;
479         g_object_notify (G_OBJECT (layout), "height");
480      }
481   g_object_thaw_notify (G_OBJECT (layout));
482
483   if (layout->hadjustment)
484     gtk_layout_set_adjustment_upper (layout->hadjustment, layout->width, FALSE);
485   if (layout->vadjustment)
486     gtk_layout_set_adjustment_upper (layout->vadjustment, layout->height, FALSE);
487
488   if (GTK_WIDGET_REALIZED (layout))
489     {
490       width = MAX (width, widget->allocation.width);
491       height = MAX (height, widget->allocation.height);
492       gdk_window_resize (layout->bin_window, width, height);
493     }
494 }
495
496 /**
497  * gtk_layout_get_size:
498  * @layout: a #GtkLayout
499  * @width: location to store the width set on @layout, or %NULL
500  * @height: location to store the height set on @layout, or %NULL
501  *
502  * Gets the size that has been set on the layout, and that determines
503  * the total extents of the layout's scrollbar area. See
504  * gtk_layout_set_size ().
505  **/
506 void
507 gtk_layout_get_size (GtkLayout *layout,
508                      guint     *width,
509                      guint     *height)
510 {
511   g_return_if_fail (GTK_IS_LAYOUT (layout));
512
513   if (width)
514     *width = layout->width;
515   if (height)
516     *height = layout->height;
517 }
518
519 /**
520  * gtk_layout_freeze:
521  * @layout: a #GtkLayout
522  * 
523  * This is a deprecated function, it doesn't do anything useful.
524  **/
525 void
526 gtk_layout_freeze (GtkLayout *layout)
527 {
528   g_return_if_fail (GTK_IS_LAYOUT (layout));
529
530   layout->freeze_count++;
531 }
532
533 /**
534  * gtk_layout_thaw:
535  * @layout: a #GtkLayout
536  * 
537  * This is a deprecated function, it doesn't do anything useful.
538  **/
539 void
540 gtk_layout_thaw (GtkLayout *layout)
541 {
542   g_return_if_fail (GTK_IS_LAYOUT (layout));
543
544   if (layout->freeze_count)
545     if (!(--layout->freeze_count))
546       gtk_widget_draw (GTK_WIDGET (layout), NULL);
547 }
548
549 /* Basic Object handling procedures
550  */
551 GtkType
552 gtk_layout_get_type (void)
553 {
554   static GtkType layout_type = 0;
555
556   if (!layout_type)
557     {
558       static const GTypeInfo layout_info =
559       {
560         sizeof (GtkLayoutClass),
561         NULL,           /* base_init */
562         NULL,           /* base_finalize */
563         (GClassInitFunc) gtk_layout_class_init,
564         NULL,           /* class_finalize */
565         NULL,           /* class_data */
566         sizeof (GtkLayout),
567         16,             /* n_preallocs */
568         (GInstanceInitFunc) gtk_layout_init,
569       };
570
571       layout_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkLayout", &layout_info, 0);
572     }
573
574   return layout_type;
575 }
576
577 static void
578 gtk_layout_class_init (GtkLayoutClass *class)
579 {
580   GObjectClass *gobject_class;
581   GtkObjectClass *object_class;
582   GtkWidgetClass *widget_class;
583   GtkContainerClass *container_class;
584
585   gobject_class = (GObjectClass*) class;
586   object_class = (GtkObjectClass*) class;
587   widget_class = (GtkWidgetClass*) class;
588   container_class = (GtkContainerClass*) class;
589
590   parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
591
592   gobject_class->set_property = gtk_layout_set_property;
593   gobject_class->get_property = gtk_layout_get_property;
594   gobject_class->finalize = gtk_layout_finalize;
595   gobject_class->constructor = gtk_layout_constructor;
596
597   container_class->set_child_property = gtk_layout_set_child_property;
598   container_class->get_child_property = gtk_layout_get_child_property;
599
600   gtk_container_class_install_child_property (container_class,
601                                               CHILD_PROP_X,
602                                               g_param_spec_int ("x",
603                                                                 _("X position"),
604                                                                 _("X position of child widget"),
605                                                                 G_MININT,
606                                                                 G_MAXINT,
607                                                                 0,
608                                                                 G_PARAM_READWRITE));
609
610   gtk_container_class_install_child_property (container_class,
611                                               CHILD_PROP_Y,
612                                               g_param_spec_int ("y",
613                                                                 _("Y position"),
614                                                                 _("Y position of child widget"),
615                                                                 G_MININT,
616                                                                 G_MAXINT,
617                                                                 0,
618                                                                 G_PARAM_READWRITE));
619   
620   g_object_class_install_property (gobject_class,
621                                    PROP_HADJUSTMENT,
622                                    g_param_spec_object ("hadjustment",
623                                                         _("Horizontal adjustment"),
624                                                         _("The GtkAdjustment for the horizontal position."),
625                                                         GTK_TYPE_ADJUSTMENT,
626                                                         G_PARAM_READWRITE));
627   
628   g_object_class_install_property (gobject_class,
629                                    PROP_VADJUSTMENT,
630                                    g_param_spec_object ("vadjustment",
631                                                         _("Vertical adjustment"),
632                                                         _("The GtkAdjustment for the vertical position."),
633                                                         GTK_TYPE_ADJUSTMENT,
634                                                         G_PARAM_READWRITE));
635
636   g_object_class_install_property (gobject_class,
637                                    PROP_WIDTH,
638                                    g_param_spec_uint ("width",
639                                                      _("Width"),
640                                                      _("The width of the layout."),
641                                                      0,
642                                                      G_MAXINT,
643                                                      100,
644                                                      G_PARAM_READWRITE));
645   g_object_class_install_property (gobject_class,
646                                    PROP_HEIGHT,
647                                    g_param_spec_uint ("height",
648                                                      _("Height"),
649                                                      _("The height of the layout."),
650                                                      0,
651                                                      G_MAXINT,
652                                                      100,
653                                                      G_PARAM_READWRITE));
654   widget_class->realize = gtk_layout_realize;
655   widget_class->unrealize = gtk_layout_unrealize;
656   widget_class->map = gtk_layout_map;
657   widget_class->size_request = gtk_layout_size_request;
658   widget_class->size_allocate = gtk_layout_size_allocate;
659   widget_class->expose_event = gtk_layout_expose;
660   widget_class->style_set = gtk_layout_style_set;
661
662   container_class->remove = gtk_layout_remove;
663   container_class->forall = gtk_layout_forall;
664
665   class->set_scroll_adjustments = gtk_layout_set_adjustments;
666
667   widget_class->set_scroll_adjustments_signal =
668     gtk_signal_new ("set_scroll_adjustments",
669                     GTK_RUN_LAST,
670                     GTK_CLASS_TYPE (object_class),
671                     GTK_SIGNAL_OFFSET (GtkLayoutClass, set_scroll_adjustments),
672                     _gtk_marshal_VOID__OBJECT_OBJECT,
673                     GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
674 }
675
676 static void
677 gtk_layout_get_property (GObject     *object,
678                          guint        prop_id,
679                          GValue      *value,
680                          GParamSpec  *pspec)
681 {
682   GtkLayout *layout = GTK_LAYOUT (object);
683   
684   switch (prop_id)
685     {
686     case PROP_HADJUSTMENT:
687       g_value_set_object (value, layout->hadjustment);
688       break;
689     case PROP_VADJUSTMENT:
690       g_value_set_object (value, layout->vadjustment);
691       break;
692     case PROP_WIDTH:
693       g_value_set_uint (value, layout->width);
694       break;
695     case PROP_HEIGHT:
696       g_value_set_uint (value, layout->height);
697       break;
698     default:
699       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
700       break;
701     }
702 }
703
704 static void
705 gtk_layout_set_property (GObject      *object,
706                          guint         prop_id,
707                          const GValue *value,
708                          GParamSpec   *pspec)
709 {
710   GtkLayout *layout = GTK_LAYOUT (object);
711   
712   switch (prop_id)
713     {
714     case PROP_HADJUSTMENT:
715       gtk_layout_set_hadjustment (layout, 
716                                   (GtkAdjustment*) g_value_get_object (value));
717       break;
718     case PROP_VADJUSTMENT:
719       gtk_layout_set_vadjustment (layout, 
720                                   (GtkAdjustment*) g_value_get_object (value));
721       break;
722     case PROP_WIDTH:
723       gtk_layout_set_size (layout, g_value_get_uint (value),
724                            layout->height);
725       break;
726     case PROP_HEIGHT:
727       gtk_layout_set_size (layout, layout->width,
728                            g_value_get_uint (value));
729       break;
730     default:
731       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
732       break;
733     }
734 }
735
736 static void
737 gtk_layout_set_child_property (GtkContainer    *container,
738                                GtkWidget       *child,
739                                guint            property_id,
740                                const GValue    *value,
741                                GParamSpec      *pspec)
742 {
743   switch (property_id)
744     {
745     case CHILD_PROP_X:
746       gtk_layout_move_internal (GTK_LAYOUT (container),
747                                 child,
748                                 TRUE, g_value_get_int (value),
749                                 FALSE, 0);
750       break;
751     case CHILD_PROP_Y:
752       gtk_layout_move_internal (GTK_LAYOUT (container),
753                                 child,
754                                 FALSE, 0,
755                                 TRUE, g_value_get_int (value));
756       break;
757     default:
758       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
759       break;
760     }
761 }
762
763 static void
764 gtk_layout_get_child_property (GtkContainer *container,
765                                GtkWidget    *child,
766                                guint         property_id,
767                                GValue       *value,
768                                GParamSpec   *pspec)
769 {
770   GtkLayoutChild *layout_child;
771
772   layout_child = get_child (GTK_LAYOUT (container), child);
773   
774   switch (property_id)
775     {
776     case CHILD_PROP_X:
777       g_value_set_int (value, layout_child->x);
778       break;
779     case CHILD_PROP_Y:
780       g_value_set_int (value, layout_child->y);
781       break;
782     default:
783       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
784       break;
785     }
786 }
787
788 static void
789 gtk_layout_init (GtkLayout *layout)
790 {
791   layout->children = NULL;
792
793   layout->width = 100;
794   layout->height = 100;
795
796   layout->hadjustment = NULL;
797   layout->vadjustment = NULL;
798
799   layout->bin_window = NULL;
800
801   layout->scroll_x = 0;
802   layout->scroll_y = 0;
803   layout->visibility = GDK_VISIBILITY_PARTIAL;
804
805   layout->freeze_count = 0;
806 }
807
808 static GObject *
809 gtk_layout_constructor (GType                  type,
810                         guint                  n_properties,
811                         GObjectConstructParam *properties)
812 {
813   GtkLayout *layout;
814   GObject *object;
815   GtkAdjustment *hadj, *vadj;
816   
817   object = G_OBJECT_CLASS (parent_class)->constructor (type,
818                                                        n_properties,
819                                                        properties);
820
821   layout = GTK_LAYOUT (object);
822
823   hadj = layout->hadjustment ? layout->hadjustment : new_default_adjustment ();
824   vadj = layout->vadjustment ? layout->vadjustment : new_default_adjustment ();
825
826   if (!layout->hadjustment || !layout->vadjustment)
827     gtk_layout_set_adjustments (layout, hadj, vadj);
828
829   return object;
830 }
831
832 /* Widget methods
833  */
834
835 static void 
836 gtk_layout_realize (GtkWidget *widget)
837 {
838   GList *tmp_list;
839   GtkLayout *layout;
840   GdkWindowAttr attributes;
841   gint attributes_mask;
842
843   g_return_if_fail (GTK_IS_LAYOUT (widget));
844
845   layout = GTK_LAYOUT (widget);
846   GTK_WIDGET_SET_FLAGS (layout, GTK_REALIZED);
847
848   attributes.window_type = GDK_WINDOW_CHILD;
849   attributes.x = widget->allocation.x;
850   attributes.y = widget->allocation.y;
851   attributes.width = widget->allocation.width;
852   attributes.height = widget->allocation.height;
853   attributes.wclass = GDK_INPUT_OUTPUT;
854   attributes.visual = gtk_widget_get_visual (widget);
855   attributes.colormap = gtk_widget_get_colormap (widget);
856   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
857
858   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
859
860   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
861                                    &attributes, attributes_mask);
862   gdk_window_set_user_data (widget->window, widget);
863
864   attributes.x = - layout->hadjustment->value,
865   attributes.y = - layout->vadjustment->value;
866   attributes.width = MAX (layout->width, widget->allocation.width);
867   attributes.height = MAX (layout->height, widget->allocation.height);
868   attributes.event_mask = GDK_EXPOSURE_MASK | GDK_SCROLL_MASK | 
869                           gtk_widget_get_events (widget);
870
871   layout->bin_window = gdk_window_new (widget->window,
872                                         &attributes, attributes_mask);
873   gdk_window_set_user_data (layout->bin_window, widget);
874
875   widget->style = gtk_style_attach (widget->style, widget->window);
876   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
877   gtk_style_set_background (widget->style, layout->bin_window, GTK_STATE_NORMAL);
878
879   tmp_list = layout->children;
880   while (tmp_list)
881     {
882       GtkLayoutChild *child = tmp_list->data;
883       tmp_list = tmp_list->next;
884
885       gtk_widget_set_parent_window (child->widget, layout->bin_window);
886     }
887 }
888
889 static void
890 gtk_layout_style_set (GtkWidget *widget, GtkStyle *old_style)
891 {
892   if (GTK_WIDGET_CLASS (parent_class)->style_set)
893     (* GTK_WIDGET_CLASS (parent_class)->style_set) (widget, old_style);
894
895   if (GTK_WIDGET_REALIZED (widget))
896     {
897       gtk_style_set_background (widget->style, GTK_LAYOUT (widget)->bin_window, GTK_STATE_NORMAL);
898     }
899 }
900
901 static void 
902 gtk_layout_map (GtkWidget *widget)
903 {
904   GList *tmp_list;
905   GtkLayout *layout;
906
907   g_return_if_fail (GTK_IS_LAYOUT (widget));
908
909   layout = GTK_LAYOUT (widget);
910
911   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
912
913   tmp_list = layout->children;
914   while (tmp_list)
915     {
916       GtkLayoutChild *child = tmp_list->data;
917       tmp_list = tmp_list->next;
918
919       if (GTK_WIDGET_VISIBLE (child->widget))
920         {
921           if (!GTK_WIDGET_MAPPED (child->widget))
922             gtk_widget_map (child->widget);
923         }
924     }
925
926   gdk_window_show (layout->bin_window);
927   gdk_window_show (widget->window);
928 }
929
930 static void 
931 gtk_layout_unrealize (GtkWidget *widget)
932 {
933   GtkLayout *layout;
934
935   g_return_if_fail (GTK_IS_LAYOUT (widget));
936
937   layout = GTK_LAYOUT (widget);
938
939   gdk_window_set_user_data (layout->bin_window, NULL);
940   gdk_window_destroy (layout->bin_window);
941   layout->bin_window = NULL;
942
943   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
944     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
945 }
946
947 static void     
948 gtk_layout_size_request (GtkWidget     *widget,
949                          GtkRequisition *requisition)
950 {
951   GList *tmp_list;
952   GtkLayout *layout;
953
954   g_return_if_fail (GTK_IS_LAYOUT (widget));
955
956   layout = GTK_LAYOUT (widget);
957
958   requisition->width = 0;
959   requisition->height = 0;
960
961   tmp_list = layout->children;
962
963   while (tmp_list)
964     {
965       GtkLayoutChild *child = tmp_list->data;
966       GtkRequisition child_requisition;
967       
968       tmp_list = tmp_list->next;
969
970       gtk_widget_size_request (child->widget, &child_requisition);
971     }
972 }
973
974 static void     
975 gtk_layout_size_allocate (GtkWidget     *widget,
976                           GtkAllocation *allocation)
977 {
978   GList *tmp_list;
979   GtkLayout *layout;
980
981   g_return_if_fail (GTK_IS_LAYOUT (widget));
982
983   widget->allocation = *allocation;
984   
985   layout = GTK_LAYOUT (widget);
986
987   tmp_list = layout->children;
988
989   while (tmp_list)
990     {
991       GtkLayoutChild *child = tmp_list->data;
992       tmp_list = tmp_list->next;
993
994       gtk_layout_allocate_child (layout, child);
995     }
996
997   if (GTK_WIDGET_REALIZED (widget))
998     {
999       gdk_window_move_resize (widget->window,
1000                               allocation->x, allocation->y,
1001                               allocation->width, allocation->height);
1002
1003       gdk_window_resize (layout->bin_window,
1004                          MAX (layout->width, allocation->width),
1005                          MAX (layout->height, allocation->height));
1006     }
1007
1008   layout->hadjustment->page_size = allocation->width;
1009   layout->hadjustment->page_increment = allocation->width * 0.9;
1010   layout->hadjustment->lower = 0;
1011   /* set_adjustment_upper() emits ::changed */
1012   gtk_layout_set_adjustment_upper (layout->hadjustment, MAX (allocation->width, layout->width), TRUE);
1013
1014   layout->vadjustment->page_size = allocation->height;
1015   layout->vadjustment->page_increment = allocation->height * 0.9;
1016   layout->vadjustment->lower = 0;
1017   layout->vadjustment->upper = MAX (allocation->height, layout->height);
1018   gtk_layout_set_adjustment_upper (layout->vadjustment, MAX (allocation->height, layout->height), TRUE);
1019 }
1020
1021 static gint 
1022 gtk_layout_expose (GtkWidget *widget, GdkEventExpose *event)
1023 {
1024   GtkLayout *layout;
1025
1026   g_return_val_if_fail (GTK_IS_LAYOUT (widget), FALSE);
1027
1028   layout = GTK_LAYOUT (widget);
1029
1030   if (event->window != layout->bin_window)
1031     return FALSE;
1032   
1033   (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
1034
1035   return FALSE;
1036 }
1037
1038 /* Container method
1039  */
1040 static void
1041 gtk_layout_remove (GtkContainer *container, 
1042                    GtkWidget    *widget)
1043 {
1044   GList *tmp_list;
1045   GtkLayout *layout;
1046   GtkLayoutChild *child = NULL;
1047   
1048   g_return_if_fail (GTK_IS_LAYOUT (container));
1049   
1050   layout = GTK_LAYOUT (container);
1051
1052   tmp_list = layout->children;
1053   while (tmp_list)
1054     {
1055       child = tmp_list->data;
1056       if (child->widget == widget)
1057         break;
1058       tmp_list = tmp_list->next;
1059     }
1060
1061   if (tmp_list)
1062     {
1063       gtk_widget_unparent (widget);
1064
1065       layout->children = g_list_remove_link (layout->children, tmp_list);
1066       g_list_free_1 (tmp_list);
1067       g_free (child);
1068     }
1069 }
1070
1071 static void
1072 gtk_layout_forall (GtkContainer *container,
1073                    gboolean      include_internals,
1074                    GtkCallback   callback,
1075                    gpointer      callback_data)
1076 {
1077   GtkLayout *layout;
1078   GtkLayoutChild *child;
1079   GList *tmp_list;
1080
1081   g_return_if_fail (GTK_IS_LAYOUT (container));
1082   g_return_if_fail (callback != NULL);
1083
1084   layout = GTK_LAYOUT (container);
1085
1086   tmp_list = layout->children;
1087   while (tmp_list)
1088     {
1089       child = tmp_list->data;
1090       tmp_list = tmp_list->next;
1091
1092       (* callback) (child->widget, callback_data);
1093     }
1094 }
1095
1096 /* Operations on children
1097  */
1098
1099 static void
1100 gtk_layout_allocate_child (GtkLayout      *layout,
1101                            GtkLayoutChild *child)
1102 {
1103   GtkAllocation allocation;
1104   GtkRequisition requisition;
1105
1106   allocation.x = child->x;
1107   allocation.y = child->y;
1108   gtk_widget_get_child_requisition (child->widget, &requisition);
1109   allocation.width = requisition.width;
1110   allocation.height = requisition.height;
1111   
1112   gtk_widget_size_allocate (child->widget, &allocation);
1113 }
1114
1115 /* Callbacks */
1116
1117 static void
1118 gtk_layout_adjustment_changed (GtkAdjustment *adjustment,
1119                                GtkLayout     *layout)
1120 {
1121   GtkWidget *widget;
1122
1123   widget = GTK_WIDGET (layout);
1124
1125   if (layout->freeze_count)
1126     return;
1127
1128   if (GTK_WIDGET_REALIZED (layout))
1129     {
1130       gdk_window_move (layout->bin_window,
1131                        - layout->hadjustment->value,
1132                        - layout->vadjustment->value);
1133       
1134       gdk_window_process_updates (layout->bin_window, TRUE);
1135     }
1136 }