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