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