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