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