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