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