1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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.
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.
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.
19 * GtkLayout: Widget for scrolling of arbitrary-sized areas.
21 * Copyright Owen Taylor, 1998
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/.
31 #include "gdkconfig.h"
33 #include "gtklayout.h"
34 #include "gtksignal.h"
35 #include "gtkprivate.h"
38 typedef struct _GtkLayoutChild GtkLayoutChild;
40 struct _GtkLayoutChild {
54 static void gtk_layout_class_init (GtkLayoutClass *class);
55 static void gtk_layout_get_property (GObject *object,
59 static void gtk_layout_set_property (GObject *object,
63 static void gtk_layout_init (GtkLayout *layout);
65 static void gtk_layout_finalize (GObject *object);
66 static void gtk_layout_realize (GtkWidget *widget);
67 static void gtk_layout_unrealize (GtkWidget *widget);
68 static void gtk_layout_map (GtkWidget *widget);
69 static void gtk_layout_size_request (GtkWidget *widget,
70 GtkRequisition *requisition);
71 static void gtk_layout_size_allocate (GtkWidget *widget,
72 GtkAllocation *allocation);
73 static gint gtk_layout_expose (GtkWidget *widget,
74 GdkEventExpose *event);
76 static void gtk_layout_remove (GtkContainer *container,
78 static void gtk_layout_forall (GtkContainer *container,
79 gboolean include_internals,
81 gpointer callback_data);
82 static void gtk_layout_set_adjustments (GtkLayout *layout,
86 static void gtk_layout_allocate_child (GtkLayout *layout,
87 GtkLayoutChild *child);
90 static void gtk_layout_adjustment_changed (GtkAdjustment *adjustment,
93 static GtkWidgetClass *parent_class = NULL;
99 gtk_layout_new (GtkAdjustment *hadjustment,
100 GtkAdjustment *vadjustment)
104 layout = gtk_type_new (GTK_TYPE_LAYOUT);
106 gtk_layout_set_adjustments (layout, hadjustment, vadjustment);
108 return GTK_WIDGET (layout);
112 gtk_layout_get_hadjustment (GtkLayout *layout)
114 g_return_val_if_fail (layout != NULL, NULL);
115 g_return_val_if_fail (GTK_IS_LAYOUT (layout), NULL);
117 return layout->hadjustment;
120 gtk_layout_get_vadjustment (GtkLayout *layout)
122 g_return_val_if_fail (layout != NULL, NULL);
123 g_return_val_if_fail (GTK_IS_LAYOUT (layout), NULL);
125 return layout->vadjustment;
129 gtk_layout_set_adjustments (GtkLayout *layout,
133 gboolean need_adjust = FALSE;
135 g_return_if_fail (layout != NULL);
136 g_return_if_fail (GTK_IS_LAYOUT (layout));
139 g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
141 hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
143 g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
145 vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
147 if (layout->hadjustment && (layout->hadjustment != hadj))
149 gtk_signal_disconnect_by_data (GTK_OBJECT (layout->hadjustment), layout);
150 gtk_object_unref (GTK_OBJECT (layout->hadjustment));
153 if (layout->vadjustment && (layout->vadjustment != vadj))
155 gtk_signal_disconnect_by_data (GTK_OBJECT (layout->vadjustment), layout);
156 gtk_object_unref (GTK_OBJECT (layout->vadjustment));
159 if (layout->hadjustment != hadj)
161 layout->hadjustment = hadj;
162 gtk_object_ref (GTK_OBJECT (layout->hadjustment));
163 gtk_object_sink (GTK_OBJECT (layout->hadjustment));
165 gtk_signal_connect (GTK_OBJECT (layout->hadjustment), "value_changed",
166 (GtkSignalFunc) gtk_layout_adjustment_changed,
171 if (layout->vadjustment != vadj)
173 layout->vadjustment = vadj;
174 gtk_object_ref (GTK_OBJECT (layout->vadjustment));
175 gtk_object_sink (GTK_OBJECT (layout->vadjustment));
177 gtk_signal_connect (GTK_OBJECT (layout->vadjustment), "value_changed",
178 (GtkSignalFunc) gtk_layout_adjustment_changed,
184 gtk_layout_adjustment_changed (NULL, layout);
188 gtk_layout_finalize (GObject *object)
190 GtkLayout *layout = GTK_LAYOUT (object);
192 gtk_object_unref (GTK_OBJECT (layout->hadjustment));
193 gtk_object_unref (GTK_OBJECT (layout->vadjustment));
195 G_OBJECT_CLASS (parent_class)->finalize (object);
199 gtk_layout_set_hadjustment (GtkLayout *layout,
200 GtkAdjustment *adjustment)
202 g_return_if_fail (layout != NULL);
203 g_return_if_fail (GTK_IS_LAYOUT (layout));
205 gtk_layout_set_adjustments (layout, adjustment, layout->vadjustment);
206 g_object_notify (G_OBJECT (layout), "hadjustment");
211 gtk_layout_set_vadjustment (GtkLayout *layout,
212 GtkAdjustment *adjustment)
214 g_return_if_fail (layout != NULL);
215 g_return_if_fail (GTK_IS_LAYOUT (layout));
217 gtk_layout_set_adjustments (layout, layout->hadjustment, adjustment);
218 g_object_notify (G_OBJECT (layout), "vadjustment");
223 gtk_layout_put (GtkLayout *layout,
224 GtkWidget *child_widget,
228 GtkLayoutChild *child;
230 g_return_if_fail (layout != NULL);
231 g_return_if_fail (GTK_IS_LAYOUT (layout));
232 g_return_if_fail (child_widget != NULL);
233 g_return_if_fail (GTK_IS_WIDGET (child_widget));
235 child = g_new (GtkLayoutChild, 1);
237 child->widget = child_widget;
241 layout->children = g_list_append (layout->children, child);
243 gtk_widget_set_parent (child_widget, GTK_WIDGET (layout));
244 if (GTK_WIDGET_REALIZED (layout))
245 gtk_widget_set_parent_window (child->widget, layout->bin_window);
247 if (GTK_WIDGET_REALIZED (layout))
248 gtk_widget_realize (child_widget);
250 if (GTK_WIDGET_VISIBLE (layout) && GTK_WIDGET_VISIBLE (child_widget))
252 if (GTK_WIDGET_MAPPED (layout))
253 gtk_widget_map (child_widget);
255 gtk_widget_queue_resize (child_widget);
260 gtk_layout_move (GtkLayout *layout,
261 GtkWidget *child_widget,
266 GtkLayoutChild *child;
268 g_return_if_fail (layout != NULL);
269 g_return_if_fail (GTK_IS_LAYOUT (layout));
271 tmp_list = layout->children;
274 child = tmp_list->data;
275 tmp_list = tmp_list->next;
277 if (child->widget == child_widget)
282 if (GTK_WIDGET_VISIBLE (child_widget) && GTK_WIDGET_VISIBLE (layout))
283 gtk_widget_queue_resize (child_widget);
291 gtk_layout_set_adjustment_upper (GtkAdjustment *adj,
294 if (upper != adj->upper)
296 gdouble min = MAX (0., upper - adj->page_size);
297 gboolean value_changed = FALSE;
301 if (adj->value > min)
304 value_changed = TRUE;
307 gtk_signal_emit_by_name (GTK_OBJECT (adj), "changed");
309 gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
314 gtk_layout_set_size (GtkLayout *layout,
320 g_return_if_fail (layout != NULL);
321 g_return_if_fail (GTK_IS_LAYOUT (layout));
323 widget = GTK_WIDGET (layout);
325 if (width != layout->width)
327 layout->width = width;
328 g_object_notify (G_OBJECT (layout), "width");
330 if (height != layout->height)
332 layout->height = height;
333 g_object_notify (G_OBJECT (layout), "height");
336 gtk_layout_set_adjustment_upper (layout->hadjustment, layout->width);
337 gtk_layout_set_adjustment_upper (layout->vadjustment, layout->height);
339 if (GTK_WIDGET_REALIZED (layout))
341 width = MAX (width, widget->allocation.width);
342 height = MAX (height, widget->allocation.height);
343 gdk_window_resize (layout->bin_window, width, height);
348 gtk_layout_freeze (GtkLayout *layout)
350 g_return_if_fail (layout != NULL);
351 g_return_if_fail (GTK_IS_LAYOUT (layout));
353 layout->freeze_count++;
357 gtk_layout_thaw (GtkLayout *layout)
359 g_return_if_fail (layout != NULL);
360 g_return_if_fail (GTK_IS_LAYOUT (layout));
362 if (layout->freeze_count)
363 if (!(--layout->freeze_count))
364 gtk_widget_draw (GTK_WIDGET (layout), NULL);
367 /* Basic Object handling procedures
370 gtk_layout_get_type (void)
372 static GtkType layout_type = 0;
376 static const GTypeInfo layout_info =
378 sizeof (GtkLayoutClass),
379 NULL, /* base_init */
380 NULL, /* base_finalize */
381 (GClassInitFunc) gtk_layout_class_init,
382 NULL, /* class_finalize */
383 NULL, /* class_data */
385 16, /* n_preallocs */
386 (GInstanceInitFunc) gtk_layout_init,
389 layout_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkLayout", &layout_info, 0);
396 gtk_layout_class_init (GtkLayoutClass *class)
398 GObjectClass *gobject_class;
399 GtkObjectClass *object_class;
400 GtkWidgetClass *widget_class;
401 GtkContainerClass *container_class;
403 gobject_class = (GObjectClass*) class;
404 object_class = (GtkObjectClass*) class;
405 widget_class = (GtkWidgetClass*) class;
406 container_class = (GtkContainerClass*) class;
408 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
410 gobject_class->set_property = gtk_layout_set_property;
411 gobject_class->get_property = gtk_layout_get_property;
412 gobject_class->finalize = gtk_layout_finalize;
414 g_object_class_install_property (gobject_class,
416 g_param_spec_object ("hadjustment",
417 _("Horizontal adjustment"),
418 _("The GtkAdjustment for the horizontal position."),
422 g_object_class_install_property (gobject_class,
424 g_param_spec_object ("vadjustment",
425 _("Vertical adjustment"),
426 _("The GtkAdjustment for the vertical position."),
430 g_object_class_install_property (gobject_class,
432 g_param_spec_uint ("width",
434 _("The width of the layout."),
439 g_object_class_install_property (gobject_class,
441 g_param_spec_uint ("height",
443 _("The height of the layout."),
448 widget_class->realize = gtk_layout_realize;
449 widget_class->unrealize = gtk_layout_unrealize;
450 widget_class->map = gtk_layout_map;
451 widget_class->size_request = gtk_layout_size_request;
452 widget_class->size_allocate = gtk_layout_size_allocate;
453 widget_class->expose_event = gtk_layout_expose;
455 container_class->remove = gtk_layout_remove;
456 container_class->forall = gtk_layout_forall;
458 class->set_scroll_adjustments = gtk_layout_set_adjustments;
460 widget_class->set_scroll_adjustments_signal =
461 gtk_signal_new ("set_scroll_adjustments",
463 GTK_CLASS_TYPE (object_class),
464 GTK_SIGNAL_OFFSET (GtkLayoutClass, set_scroll_adjustments),
465 gtk_marshal_VOID__OBJECT_OBJECT,
466 GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
470 gtk_layout_get_property (GObject *object,
475 GtkLayout *layout = GTK_LAYOUT (object);
479 case PROP_HADJUSTMENT:
480 g_value_set_object (value, G_OBJECT (layout->hadjustment));
482 case PROP_VADJUSTMENT:
483 g_value_set_object (value, G_OBJECT (layout->vadjustment));
486 g_value_set_uint (value, layout->width);
489 g_value_set_uint (value, layout->height);
492 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
498 gtk_layout_set_property (GObject *object,
503 GtkLayout *layout = GTK_LAYOUT (object);
507 case PROP_HADJUSTMENT:
508 gtk_layout_set_hadjustment (layout,
509 (GtkAdjustment*) g_value_get_object (value));
511 case PROP_VADJUSTMENT:
512 gtk_layout_set_vadjustment (layout,
513 (GtkAdjustment*) g_value_get_object (value));
516 gtk_layout_set_size (layout, g_value_get_uint (value),
520 gtk_layout_set_size (layout, layout->width,
521 g_value_get_uint (value));
524 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
531 gtk_layout_init (GtkLayout *layout)
533 layout->children = NULL;
536 layout->height = 100;
538 layout->hadjustment = NULL;
539 layout->vadjustment = NULL;
541 layout->bin_window = NULL;
543 layout->scroll_x = 0;
544 layout->scroll_y = 0;
545 layout->visibility = GDK_VISIBILITY_PARTIAL;
547 layout->freeze_count = 0;
554 gtk_layout_realize (GtkWidget *widget)
558 GdkWindowAttr attributes;
559 gint attributes_mask;
561 g_return_if_fail (widget != NULL);
562 g_return_if_fail (GTK_IS_LAYOUT (widget));
564 layout = GTK_LAYOUT (widget);
565 GTK_WIDGET_SET_FLAGS (layout, GTK_REALIZED);
567 attributes.window_type = GDK_WINDOW_CHILD;
568 attributes.x = widget->allocation.x;
569 attributes.y = widget->allocation.y;
570 attributes.width = widget->allocation.width;
571 attributes.height = widget->allocation.height;
572 attributes.wclass = GDK_INPUT_OUTPUT;
573 attributes.visual = gtk_widget_get_visual (widget);
574 attributes.colormap = gtk_widget_get_colormap (widget);
575 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
577 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
579 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
580 &attributes, attributes_mask);
581 gdk_window_set_user_data (widget->window, widget);
585 attributes.width = MAX (layout->width, widget->allocation.width);
586 attributes.height = MAX (layout->height, widget->allocation.height);
587 attributes.event_mask = GDK_EXPOSURE_MASK | GDK_SCROLL_MASK |
588 gtk_widget_get_events (widget);
590 layout->bin_window = gdk_window_new (widget->window,
591 &attributes, attributes_mask);
592 gdk_window_set_user_data (layout->bin_window, widget);
594 widget->style = gtk_style_attach (widget->style, widget->window);
595 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
596 gtk_style_set_background (widget->style, layout->bin_window, GTK_STATE_NORMAL);
598 tmp_list = layout->children;
601 GtkLayoutChild *child = tmp_list->data;
602 tmp_list = tmp_list->next;
604 gtk_widget_set_parent_window (child->widget, layout->bin_window);
609 gtk_layout_map (GtkWidget *widget)
614 g_return_if_fail (widget != NULL);
615 g_return_if_fail (GTK_IS_LAYOUT (widget));
617 layout = GTK_LAYOUT (widget);
619 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
621 tmp_list = layout->children;
624 GtkLayoutChild *child = tmp_list->data;
625 tmp_list = tmp_list->next;
627 if (GTK_WIDGET_VISIBLE (child->widget))
629 if (!GTK_WIDGET_MAPPED (child->widget))
630 gtk_widget_map (child->widget);
634 gdk_window_show (layout->bin_window);
635 gdk_window_show (widget->window);
639 gtk_layout_unrealize (GtkWidget *widget)
643 g_return_if_fail (widget != NULL);
644 g_return_if_fail (GTK_IS_LAYOUT (widget));
646 layout = GTK_LAYOUT (widget);
648 gdk_window_set_user_data (layout->bin_window, NULL);
649 gdk_window_destroy (layout->bin_window);
650 layout->bin_window = NULL;
652 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
653 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
657 gtk_layout_size_request (GtkWidget *widget,
658 GtkRequisition *requisition)
663 g_return_if_fail (widget != NULL);
664 g_return_if_fail (GTK_IS_LAYOUT (widget));
666 layout = GTK_LAYOUT (widget);
668 requisition->width = 0;
669 requisition->height = 0;
671 tmp_list = layout->children;
675 GtkLayoutChild *child = tmp_list->data;
676 GtkRequisition child_requisition;
678 tmp_list = tmp_list->next;
680 gtk_widget_size_request (child->widget, &child_requisition);
685 gtk_layout_size_allocate (GtkWidget *widget,
686 GtkAllocation *allocation)
691 g_return_if_fail (widget != NULL);
692 g_return_if_fail (GTK_IS_LAYOUT (widget));
694 widget->allocation = *allocation;
696 layout = GTK_LAYOUT (widget);
698 tmp_list = layout->children;
702 GtkLayoutChild *child = tmp_list->data;
703 tmp_list = tmp_list->next;
705 gtk_layout_allocate_child (layout, child);
708 if (GTK_WIDGET_REALIZED (widget))
710 gdk_window_move_resize (widget->window,
711 allocation->x, allocation->y,
712 allocation->width, allocation->height);
714 gdk_window_resize (layout->bin_window,
715 MAX (layout->width, allocation->width),
716 MAX (layout->height, allocation->height));
719 layout->hadjustment->page_size = allocation->width;
720 layout->hadjustment->page_increment = allocation->width / 2;
721 layout->hadjustment->lower = 0;
722 layout->hadjustment->upper = MAX (allocation->width, layout->width);
723 gtk_signal_emit_by_name (GTK_OBJECT (layout->hadjustment), "changed");
725 layout->vadjustment->page_size = allocation->height;
726 layout->vadjustment->page_increment = allocation->height / 2;
727 layout->vadjustment->lower = 0;
728 layout->vadjustment->upper = MAX (allocation->height, layout->height);
729 gtk_signal_emit_by_name (GTK_OBJECT (layout->vadjustment), "changed");
733 gtk_layout_expose (GtkWidget *widget, GdkEventExpose *event)
737 g_return_val_if_fail (widget != NULL, FALSE);
738 g_return_val_if_fail (GTK_IS_LAYOUT (widget), FALSE);
740 layout = GTK_LAYOUT (widget);
742 if (event->window != layout->bin_window)
745 (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
753 gtk_layout_remove (GtkContainer *container,
758 GtkLayoutChild *child = NULL;
760 g_return_if_fail (container != NULL);
761 g_return_if_fail (GTK_IS_LAYOUT (container));
763 layout = GTK_LAYOUT (container);
765 tmp_list = layout->children;
768 child = tmp_list->data;
769 if (child->widget == widget)
771 tmp_list = tmp_list->next;
776 gtk_widget_unparent (widget);
778 layout->children = g_list_remove_link (layout->children, tmp_list);
779 g_list_free_1 (tmp_list);
785 gtk_layout_forall (GtkContainer *container,
786 gboolean include_internals,
787 GtkCallback callback,
788 gpointer callback_data)
791 GtkLayoutChild *child;
794 g_return_if_fail (container != NULL);
795 g_return_if_fail (GTK_IS_LAYOUT (container));
796 g_return_if_fail (callback != NULL);
798 layout = GTK_LAYOUT (container);
800 tmp_list = layout->children;
803 child = tmp_list->data;
804 tmp_list = tmp_list->next;
806 (* callback) (child->widget, callback_data);
810 /* Operations on children
814 gtk_layout_allocate_child (GtkLayout *layout,
815 GtkLayoutChild *child)
817 GtkAllocation allocation;
818 GtkRequisition requisition;
820 allocation.x = child->x;
821 allocation.y = child->y;
822 gtk_widget_get_child_requisition (child->widget, &requisition);
823 allocation.width = requisition.width;
824 allocation.height = requisition.height;
826 gtk_widget_size_allocate (child->widget, &allocation);
832 gtk_layout_adjustment_changed (GtkAdjustment *adjustment,
837 widget = GTK_WIDGET (layout);
839 if (layout->freeze_count)
842 if (GTK_WIDGET_REALIZED (layout))
844 gdk_window_move (layout->bin_window,
845 - layout->hadjustment->value,
846 - layout->vadjustment->value);
848 gdk_window_process_updates (layout->bin_window, TRUE);