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