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