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