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.
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
27 #include "gtkscrolledwindow.h"
28 #include "gtksignal.h"
32 /* scrolled window policy and size requisition handling:
34 * gtk size requisition works as follows:
35 * a widget upon size-request reports the width and height that it finds
36 * to be best suited to display its contents, including children.
37 * the width and/or height reported from a widget upon size requisition
38 * may be overidden by the user by specifying a width and/or height
39 * other than 0 through gtk_widget_set_usize().
41 * a scrolled window needs (for imlementing all three policy types) to
42 * request its width and height based on two different rationales.
43 * 1) the user wants the scrolled window to just fit into the space
44 * that it gets allocated for a specifc dimension.
45 * 1.1) this does not apply if the user specified a concrete value
46 * value for that specific dimension by either specifying usize for the
47 * scrolled window or for its child.
48 * 2) the user wants the scrolled window to take as much space up as
49 * is desired by the child for a specifc dimension (i.e. POLICY_NEVER).
51 * also, kinda obvious:
52 * 3) a user would certainly not have choosen a scrolled window as a container
53 * for the child, if the resulting allocation takes up more space than the
54 * child would have allocated without the scrolled window.
57 * A) from 1) follows: the scrolled window shouldn't request more space for a
58 * specifc dimension than is required at minimum.
59 * B) from 1.1) follows: the requisition may be overidden by usize of the scrolled
60 * window (done automatically) or by usize of the child (needs to be checked).
61 * C) from 2) follows: for POLICY_NEVER, the scrolled window simply reports the
63 * D) from 3) follows: the scrolled window child's minimum width and minimum height
64 * under A) at least correspond to the space taken up by its scrollbars.
67 #define SCROLLBAR_SPACING(w) (GTK_SCROLLED_WINDOW_GET_CLASS (w)->scrollbar_spacing)
69 #define DEFAULT_SCROLLBAR_SPACING 3
75 PROP_HSCROLLBAR_POLICY,
76 PROP_VSCROLLBAR_POLICY,
77 PROP_WINDOW_PLACEMENT,
82 static void gtk_scrolled_window_class_init (GtkScrolledWindowClass *klass);
83 static void gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window);
84 static void gtk_scrolled_window_destroy (GtkObject *object);
85 static void gtk_scrolled_window_finalize (GObject *object);
86 static void gtk_scrolled_window_set_property (GObject *object,
90 static void gtk_scrolled_window_get_property (GObject *object,
95 static gint gtk_scrolled_window_expose (GtkWidget *widget,
96 GdkEventExpose *event);
97 static void gtk_scrolled_window_size_request (GtkWidget *widget,
98 GtkRequisition *requisition);
99 static void gtk_scrolled_window_size_allocate (GtkWidget *widget,
100 GtkAllocation *allocation);
101 static gint gtk_scrolled_window_scroll_event (GtkWidget *widget,
102 GdkEventScroll *event);
103 static void gtk_scrolled_window_add (GtkContainer *container,
105 static void gtk_scrolled_window_remove (GtkContainer *container,
107 static void gtk_scrolled_window_forall (GtkContainer *container,
108 gboolean include_internals,
109 GtkCallback callback,
110 gpointer callback_data);
111 static void gtk_scrolled_window_relative_allocation(GtkWidget *widget,
112 GtkAllocation *allocation);
113 static void gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment,
116 static GtkContainerClass *parent_class = NULL;
120 gtk_scrolled_window_get_type (void)
122 static GtkType scrolled_window_type = 0;
124 if (!scrolled_window_type)
126 static const GtkTypeInfo scrolled_window_info =
129 sizeof (GtkScrolledWindow),
130 sizeof (GtkScrolledWindowClass),
131 (GtkClassInitFunc) gtk_scrolled_window_class_init,
132 (GtkObjectInitFunc) gtk_scrolled_window_init,
133 /* reserved_1 */ NULL,
134 /* reserved_2 */ NULL,
135 (GtkClassInitFunc) NULL,
138 scrolled_window_type = gtk_type_unique (GTK_TYPE_BIN, &scrolled_window_info);
141 return scrolled_window_type;
145 gtk_scrolled_window_class_init (GtkScrolledWindowClass *class)
147 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
148 GtkObjectClass *object_class;
149 GtkWidgetClass *widget_class;
150 GtkContainerClass *container_class;
152 object_class = (GtkObjectClass*) class;
153 widget_class = (GtkWidgetClass*) class;
154 container_class = (GtkContainerClass*) class;
155 parent_class = gtk_type_class (GTK_TYPE_BIN);
157 gobject_class->finalize = gtk_scrolled_window_finalize;
158 gobject_class->set_property = gtk_scrolled_window_set_property;
159 gobject_class->get_property = gtk_scrolled_window_get_property;
161 object_class->destroy = gtk_scrolled_window_destroy;
163 widget_class->expose_event = gtk_scrolled_window_expose;
164 widget_class->size_request = gtk_scrolled_window_size_request;
165 widget_class->size_allocate = gtk_scrolled_window_size_allocate;
166 widget_class->scroll_event = gtk_scrolled_window_scroll_event;
168 container_class->add = gtk_scrolled_window_add;
169 container_class->remove = gtk_scrolled_window_remove;
170 container_class->forall = gtk_scrolled_window_forall;
172 class->scrollbar_spacing = DEFAULT_SCROLLBAR_SPACING;
174 g_object_class_install_property (gobject_class,
176 g_param_spec_object ("hadjustment",
177 _("Horizontal Adjustment"),
178 _("The GtkAdjustment for the horizontal position."),
180 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
181 g_object_class_install_property (gobject_class,
183 g_param_spec_object ("vadjustment",
184 _("Vertical Adjustment"),
185 _("The GtkAdjustment for the vertical position."),
187 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
188 g_object_class_install_property (gobject_class,
189 PROP_HSCROLLBAR_POLICY,
190 g_param_spec_enum ("hscrollbar_policy",
191 _("Horizontal Scrollbar Policy"),
192 _("When the horizontal scrollbar is displayed"),
193 GTK_TYPE_POLICY_TYPE,
195 G_PARAM_READABLE | G_PARAM_WRITABLE));
196 g_object_class_install_property (gobject_class,
197 PROP_VSCROLLBAR_POLICY,
198 g_param_spec_enum ("vscrollbar_policy",
199 _("Vertical Scrollbar Policy"),
200 _("When the vertical scrollbar is displayed"),
201 GTK_TYPE_POLICY_TYPE,
203 G_PARAM_READABLE | G_PARAM_WRITABLE));
205 g_object_class_install_property (gobject_class,
206 PROP_WINDOW_PLACEMENT,
207 g_param_spec_enum ("window_placement",
208 _("Window Placement"),
209 _("Where the contents are located with respect to the scrollbars"),
210 GTK_TYPE_CORNER_TYPE,
212 G_PARAM_READABLE | G_PARAM_WRITABLE));
213 g_object_class_install_property (gobject_class,
215 g_param_spec_enum ("shadow_type",
217 _("Style of bevel around the contents"),
218 GTK_TYPE_SHADOW_TYPE,
220 G_PARAM_READABLE | G_PARAM_WRITABLE));
224 gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
226 GTK_WIDGET_SET_FLAGS (scrolled_window, GTK_NO_WINDOW);
228 gtk_container_set_resize_mode (GTK_CONTAINER (scrolled_window), GTK_RESIZE_QUEUE);
230 scrolled_window->hscrollbar = NULL;
231 scrolled_window->vscrollbar = NULL;
232 scrolled_window->hscrollbar_policy = GTK_POLICY_ALWAYS;
233 scrolled_window->vscrollbar_policy = GTK_POLICY_ALWAYS;
234 scrolled_window->hscrollbar_visible = FALSE;
235 scrolled_window->vscrollbar_visible = FALSE;
236 scrolled_window->window_placement = GTK_CORNER_TOP_LEFT;
241 gtk_scrolled_window_new (GtkAdjustment *hadjustment,
242 GtkAdjustment *vadjustment)
244 GtkWidget *scrolled_window;
247 g_return_val_if_fail (GTK_IS_ADJUSTMENT (hadjustment), NULL);
250 g_return_val_if_fail (GTK_IS_ADJUSTMENT (vadjustment), NULL);
252 scrolled_window = gtk_widget_new (GTK_TYPE_SCROLLED_WINDOW,
253 "hadjustment", hadjustment,
254 "vadjustment", vadjustment,
257 return scrolled_window;
261 gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window,
262 GtkAdjustment *hadjustment)
266 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
268 g_return_if_fail (GTK_IS_ADJUSTMENT (hadjustment));
270 hadjustment = (GtkAdjustment*) gtk_object_new (GTK_TYPE_ADJUSTMENT, NULL);
272 bin = GTK_BIN (scrolled_window);
274 if (!scrolled_window->hscrollbar)
276 gtk_widget_push_composite_child ();
277 scrolled_window->hscrollbar = gtk_hscrollbar_new (hadjustment);
278 gtk_widget_set_composite_name (scrolled_window->hscrollbar, "hscrollbar");
279 gtk_widget_pop_composite_child ();
281 gtk_widget_set_parent (scrolled_window->hscrollbar, GTK_WIDGET (scrolled_window));
282 gtk_widget_ref (scrolled_window->hscrollbar);
283 gtk_widget_show (scrolled_window->hscrollbar);
287 GtkAdjustment *old_adjustment;
289 old_adjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
290 if (old_adjustment == hadjustment)
293 gtk_signal_disconnect_by_func (GTK_OBJECT (old_adjustment),
294 GTK_SIGNAL_FUNC (gtk_scrolled_window_adjustment_changed),
296 gtk_range_set_adjustment (GTK_RANGE (scrolled_window->hscrollbar),
299 hadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
300 gtk_signal_connect (GTK_OBJECT (hadjustment),
302 GTK_SIGNAL_FUNC (gtk_scrolled_window_adjustment_changed),
304 gtk_scrolled_window_adjustment_changed (hadjustment, scrolled_window);
307 gtk_widget_set_scroll_adjustments (bin->child,
308 gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
309 gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)));
311 g_object_notify (G_OBJECT (scrolled_window), "hadjustment");
315 gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window,
316 GtkAdjustment *vadjustment)
320 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
322 g_return_if_fail (GTK_IS_ADJUSTMENT (vadjustment));
324 vadjustment = (GtkAdjustment*) gtk_object_new (GTK_TYPE_ADJUSTMENT, NULL);
326 bin = GTK_BIN (scrolled_window);
328 if (!scrolled_window->vscrollbar)
330 gtk_widget_push_composite_child ();
331 scrolled_window->vscrollbar = gtk_vscrollbar_new (vadjustment);
332 gtk_widget_set_composite_name (scrolled_window->vscrollbar, "vscrollbar");
333 gtk_widget_pop_composite_child ();
335 gtk_widget_set_parent (scrolled_window->vscrollbar, GTK_WIDGET (scrolled_window));
336 gtk_widget_ref (scrolled_window->vscrollbar);
337 gtk_widget_show (scrolled_window->vscrollbar);
341 GtkAdjustment *old_adjustment;
343 old_adjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
344 if (old_adjustment == vadjustment)
347 gtk_signal_disconnect_by_func (GTK_OBJECT (old_adjustment),
348 GTK_SIGNAL_FUNC (gtk_scrolled_window_adjustment_changed),
350 gtk_range_set_adjustment (GTK_RANGE (scrolled_window->vscrollbar),
353 vadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
354 gtk_signal_connect (GTK_OBJECT (vadjustment),
356 GTK_SIGNAL_FUNC (gtk_scrolled_window_adjustment_changed),
358 gtk_scrolled_window_adjustment_changed (vadjustment, scrolled_window);
361 gtk_widget_set_scroll_adjustments (bin->child,
362 gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
363 gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)));
365 g_object_notify (G_OBJECT (scrolled_window), "vadjustment");
369 gtk_scrolled_window_get_hadjustment (GtkScrolledWindow *scrolled_window)
371 g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
373 return (scrolled_window->hscrollbar ?
374 gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)) :
379 gtk_scrolled_window_get_vadjustment (GtkScrolledWindow *scrolled_window)
381 g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
383 return (scrolled_window->vscrollbar ?
384 gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)) :
389 gtk_scrolled_window_set_policy (GtkScrolledWindow *scrolled_window,
390 GtkPolicyType hscrollbar_policy,
391 GtkPolicyType vscrollbar_policy)
393 GObject *object = G_OBJECT (scrolled_window);
395 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
397 if ((scrolled_window->hscrollbar_policy != hscrollbar_policy) ||
398 (scrolled_window->vscrollbar_policy != vscrollbar_policy))
400 scrolled_window->hscrollbar_policy = hscrollbar_policy;
401 scrolled_window->vscrollbar_policy = vscrollbar_policy;
403 gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
405 g_object_freeze_notify (object);
406 g_object_notify (object, "hscrollbar_policy");
407 g_object_notify (object, "vscrollbar_policy");
408 g_object_thaw_notify (object);
413 * gtk_scrolled_window_get_policy:
414 * @scrolled_window: a #GtkScrolledWindow
415 * @hscrollbar_policy: location to store the policy for the horizontal scrollbar, or %NULL.
416 * @vscrollbar_policy: location to store the policy for the horizontal scrollbar, or %NULL.
418 * Retrieves the current policy values for the horizontal and vertical
419 * scrollbars. See gtk_scrolled_window_set_policy().
422 gtk_scrolled_window_get_policy (GtkScrolledWindow *scrolled_window,
423 GtkPolicyType *hscrollbar_policy,
424 GtkPolicyType *vscrollbar_policy)
426 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
428 if (hscrollbar_policy)
429 *hscrollbar_policy = scrolled_window->hscrollbar_policy;
430 if (vscrollbar_policy)
431 *vscrollbar_policy = scrolled_window->vscrollbar_policy;
435 gtk_scrolled_window_set_placement (GtkScrolledWindow *scrolled_window,
436 GtkCornerType window_placement)
438 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
440 if (scrolled_window->window_placement != window_placement)
442 scrolled_window->window_placement = window_placement;
444 gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
446 g_object_notify (G_OBJECT (scrolled_window), "window_placement");
451 * gtk_scrolled_window_get_placement:
452 * @scrolled_window: a #GtkScrolledWindow
454 * Gets the placement of the scrollbars for the scrolled window. See
455 * gtk_scrolled_window_set_placement().
457 * Return value: the current placement value.
460 gtk_scrolled_window_get_placement (GtkScrolledWindow *scrolled_window)
462 g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), GTK_CORNER_TOP_LEFT);
464 return scrolled_window->window_placement;
468 * gtk_scrolled_window_set_shadow_type:
469 * @scrolled_window: a #GtkScrolledWindow
470 * @type: kind of shadow to draw around scrolled window contents
472 * Changes the type of shadow drawn around the contents of
477 gtk_scrolled_window_set_shadow_type (GtkScrolledWindow *scrolled_window,
480 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
481 g_return_if_fail (type >= GTK_SHADOW_NONE && type <= GTK_SHADOW_ETCHED_OUT);
483 if (scrolled_window->shadow_type != type)
485 scrolled_window->shadow_type = type;
487 if (GTK_WIDGET_DRAWABLE (scrolled_window))
488 gtk_widget_queue_clear (GTK_WIDGET (scrolled_window));
490 gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
492 g_object_notify (G_OBJECT (scrolled_window), "shadow_type");
497 * gtk_scrolled_window_get_shadow_type:
498 * @scrolled_window: a #GtkScrolledWindow
500 * Gets the shadow type of the scrolled window. See
501 * gtk_scrolled_window_set_shadow_type().
503 * Return value: the current shadow type
506 gtk_scrolled_window_get_shadow_type (GtkScrolledWindow *scrolled_window)
508 g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_NONE);
510 return scrolled_window->shadow_type;
514 gtk_scrolled_window_destroy (GtkObject *object)
516 GtkScrolledWindow *scrolled_window;
518 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (object));
520 scrolled_window = GTK_SCROLLED_WINDOW (object);
522 gtk_widget_unparent (scrolled_window->hscrollbar);
523 gtk_widget_unparent (scrolled_window->vscrollbar);
524 gtk_widget_destroy (scrolled_window->hscrollbar);
525 gtk_widget_destroy (scrolled_window->vscrollbar);
527 GTK_OBJECT_CLASS (parent_class)->destroy (object);
531 gtk_scrolled_window_finalize (GObject *object)
533 GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (object);
535 gtk_widget_unref (scrolled_window->hscrollbar);
536 gtk_widget_unref (scrolled_window->vscrollbar);
538 G_OBJECT_CLASS (parent_class)->finalize (object);
542 gtk_scrolled_window_set_property (GObject *object,
547 GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (object);
551 case PROP_HADJUSTMENT:
552 gtk_scrolled_window_set_hadjustment (scrolled_window,
553 g_value_get_object (value));
555 case PROP_VADJUSTMENT:
556 gtk_scrolled_window_set_vadjustment (scrolled_window,
557 g_value_get_object (value));
559 case PROP_HSCROLLBAR_POLICY:
560 gtk_scrolled_window_set_policy (scrolled_window,
561 g_value_get_enum (value),
562 scrolled_window->vscrollbar_policy);
564 case PROP_VSCROLLBAR_POLICY:
565 gtk_scrolled_window_set_policy (scrolled_window,
566 scrolled_window->hscrollbar_policy,
567 g_value_get_enum (value));
569 case PROP_WINDOW_PLACEMENT:
570 gtk_scrolled_window_set_placement (scrolled_window,
571 g_value_get_enum (value));
573 case PROP_SHADOW_TYPE:
574 gtk_scrolled_window_set_shadow_type (scrolled_window,
575 g_value_get_enum (value));
578 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
584 gtk_scrolled_window_get_property (GObject *object,
589 GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (object);
593 case PROP_HADJUSTMENT:
594 g_value_set_object (value,
595 G_OBJECT (gtk_scrolled_window_get_hadjustment (scrolled_window)));
597 case PROP_VADJUSTMENT:
598 g_value_set_object (value,
599 G_OBJECT (gtk_scrolled_window_get_vadjustment (scrolled_window)));
601 case PROP_HSCROLLBAR_POLICY:
602 g_value_set_enum (value, scrolled_window->hscrollbar_policy);
604 case PROP_VSCROLLBAR_POLICY:
605 g_value_set_enum (value, scrolled_window->vscrollbar_policy);
607 case PROP_WINDOW_PLACEMENT:
608 g_value_set_enum (value, scrolled_window->window_placement);
610 case PROP_SHADOW_TYPE:
611 g_value_set_enum (value, scrolled_window->shadow_type);
614 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
620 gtk_scrolled_window_paint (GtkWidget *widget,
623 GtkAllocation relative_allocation;
624 GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
626 if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
628 gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
630 relative_allocation.x -= widget->style->xthickness;
631 relative_allocation.y -= widget->style->ythickness;
632 relative_allocation.width += 2 * widget->style->xthickness;
633 relative_allocation.height += 2 * widget->style->ythickness;
635 gtk_paint_shadow (widget->style, widget->window,
636 GTK_STATE_NORMAL, scrolled_window->shadow_type,
637 area, widget, "scrolled_window",
638 widget->allocation.x + relative_allocation.x,
639 widget->allocation.y + relative_allocation.y,
640 relative_allocation.width,
641 relative_allocation.height);
646 gtk_scrolled_window_expose (GtkWidget *widget,
647 GdkEventExpose *event)
649 if (GTK_WIDGET_DRAWABLE (widget))
651 gtk_scrolled_window_paint (widget, &event->area);
653 (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
660 gtk_scrolled_window_forall (GtkContainer *container,
661 gboolean include_internals,
662 GtkCallback callback,
663 gpointer callback_data)
665 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container));
666 g_return_if_fail (callback != NULL);
668 GTK_CONTAINER_CLASS (parent_class)->forall (container,
672 if (include_internals)
674 GtkScrolledWindow *scrolled_window;
676 scrolled_window = GTK_SCROLLED_WINDOW (container);
678 if (scrolled_window->vscrollbar)
679 callback (scrolled_window->vscrollbar, callback_data);
680 if (scrolled_window->hscrollbar)
681 callback (scrolled_window->hscrollbar, callback_data);
686 gtk_scrolled_window_size_request (GtkWidget *widget,
687 GtkRequisition *requisition)
689 GtkScrolledWindow *scrolled_window;
693 GtkRequisition hscrollbar_requisition;
694 GtkRequisition vscrollbar_requisition;
695 GtkRequisition child_requisition;
697 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
698 g_return_if_fail (requisition != NULL);
700 scrolled_window = GTK_SCROLLED_WINDOW (widget);
701 bin = GTK_BIN (scrolled_window);
705 requisition->width = 0;
706 requisition->height = 0;
708 gtk_widget_size_request (scrolled_window->hscrollbar,
709 &hscrollbar_requisition);
710 gtk_widget_size_request (scrolled_window->vscrollbar,
711 &vscrollbar_requisition);
713 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
715 gtk_widget_size_request (bin->child, &child_requisition);
717 if (scrolled_window->hscrollbar_policy == GTK_POLICY_NEVER)
718 requisition->width += child_requisition.width;
721 GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (bin->child, FALSE);
723 if (aux_info && aux_info->width > 0)
725 requisition->width += aux_info->width;
729 requisition->width += vscrollbar_requisition.width;
732 if (scrolled_window->vscrollbar_policy == GTK_POLICY_NEVER)
733 requisition->height += child_requisition.height;
736 GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (bin->child, FALSE);
738 if (aux_info && aux_info->height > 0)
740 requisition->height += aux_info->height;
744 requisition->height += hscrollbar_requisition.height;
748 if (scrolled_window->hscrollbar_policy == GTK_POLICY_AUTOMATIC ||
749 scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
751 requisition->width = MAX (requisition->width, hscrollbar_requisition.width);
752 if (!extra_height || scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
753 extra_height = SCROLLBAR_SPACING (scrolled_window) + hscrollbar_requisition.height;
756 if (scrolled_window->vscrollbar_policy == GTK_POLICY_AUTOMATIC ||
757 scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
759 requisition->height = MAX (requisition->height, vscrollbar_requisition.height);
760 if (!extra_height || scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
761 extra_width = SCROLLBAR_SPACING (scrolled_window) + vscrollbar_requisition.width;
764 requisition->width += GTK_CONTAINER (widget)->border_width * 2 + MAX (0, extra_width);
765 requisition->height += GTK_CONTAINER (widget)->border_width * 2 + MAX (0, extra_height);
767 if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
769 requisition->width += 2 * widget->style->xthickness;
770 requisition->height += 2 * widget->style->ythickness;
775 gtk_scrolled_window_relative_allocation (GtkWidget *widget,
776 GtkAllocation *allocation)
778 GtkScrolledWindow *scrolled_window;
780 g_return_if_fail (widget != NULL);
781 g_return_if_fail (allocation != NULL);
783 scrolled_window = GTK_SCROLLED_WINDOW (widget);
785 allocation->x = GTK_CONTAINER (widget)->border_width;
786 allocation->y = GTK_CONTAINER (widget)->border_width;
788 if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
790 allocation->x += widget->style->xthickness;
791 allocation->y += widget->style->ythickness;
794 allocation->width = MAX (1, (gint)widget->allocation.width - allocation->x * 2);
795 allocation->height = MAX (1, (gint)widget->allocation.height - allocation->y * 2);
797 if (scrolled_window->vscrollbar_visible)
799 GtkRequisition vscrollbar_requisition;
800 gtk_widget_get_child_requisition (scrolled_window->vscrollbar,
801 &vscrollbar_requisition);
803 if (scrolled_window->window_placement == GTK_CORNER_TOP_RIGHT ||
804 scrolled_window->window_placement == GTK_CORNER_BOTTOM_RIGHT)
805 allocation->x += (vscrollbar_requisition.width +
806 SCROLLBAR_SPACING (scrolled_window));
808 allocation->width = MAX (1, (gint)allocation->width -
809 ((gint)vscrollbar_requisition.width +
810 (gint)SCROLLBAR_SPACING (scrolled_window)));
812 if (scrolled_window->hscrollbar_visible)
814 GtkRequisition hscrollbar_requisition;
815 gtk_widget_get_child_requisition (scrolled_window->hscrollbar,
816 &hscrollbar_requisition);
818 if (scrolled_window->window_placement == GTK_CORNER_BOTTOM_LEFT ||
819 scrolled_window->window_placement == GTK_CORNER_BOTTOM_RIGHT)
820 allocation->y += (hscrollbar_requisition.height +
821 SCROLLBAR_SPACING (scrolled_window));
823 allocation->height = MAX (1, (gint)allocation->height -
824 ((gint)hscrollbar_requisition.height +
825 (gint)SCROLLBAR_SPACING (scrolled_window)));
830 gtk_scrolled_window_size_allocate (GtkWidget *widget,
831 GtkAllocation *allocation)
833 GtkScrolledWindow *scrolled_window;
835 GtkAllocation relative_allocation;
836 GtkAllocation child_allocation;
838 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
839 g_return_if_fail (allocation != NULL);
841 scrolled_window = GTK_SCROLLED_WINDOW (widget);
842 bin = GTK_BIN (scrolled_window);
844 widget->allocation = *allocation;
846 if (scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
847 scrolled_window->hscrollbar_visible = TRUE;
848 else if (scrolled_window->hscrollbar_policy == GTK_POLICY_NEVER)
849 scrolled_window->hscrollbar_visible = FALSE;
850 if (scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
851 scrolled_window->vscrollbar_visible = TRUE;
852 else if (scrolled_window->vscrollbar_policy == GTK_POLICY_NEVER)
853 scrolled_window->vscrollbar_visible = FALSE;
855 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
857 gboolean previous_hvis;
858 gboolean previous_vvis;
863 gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
865 child_allocation.x = relative_allocation.x + allocation->x;
866 child_allocation.y = relative_allocation.y + allocation->y;
867 child_allocation.width = relative_allocation.width;
868 child_allocation.height = relative_allocation.height;
870 previous_hvis = scrolled_window->hscrollbar_visible;
871 previous_vvis = scrolled_window->vscrollbar_visible;
873 gtk_widget_size_allocate (bin->child, &child_allocation);
875 /* If, after the first iteration, the hscrollbar and the
876 * vscrollbar flip visiblity, then we need both.
879 previous_hvis != scrolled_window->hscrollbar_visible &&
880 previous_vvis != scrolled_window->vscrollbar_visible)
882 scrolled_window->hscrollbar_visible = TRUE;
883 scrolled_window->vscrollbar_visible = TRUE;
885 /* a new resize is already queued at this point,
886 * so we will immediatedly get reinvoked
893 while (previous_hvis != scrolled_window->hscrollbar_visible ||
894 previous_vvis != scrolled_window->vscrollbar_visible);
897 gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
899 if (scrolled_window->hscrollbar_visible)
901 GtkRequisition hscrollbar_requisition;
902 gtk_widget_get_child_requisition (scrolled_window->hscrollbar,
903 &hscrollbar_requisition);
905 if (!GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar))
906 gtk_widget_show (scrolled_window->hscrollbar);
908 child_allocation.x = relative_allocation.x;
909 if (scrolled_window->window_placement == GTK_CORNER_TOP_LEFT ||
910 scrolled_window->window_placement == GTK_CORNER_TOP_RIGHT)
911 child_allocation.y = (relative_allocation.y +
912 relative_allocation.height +
913 SCROLLBAR_SPACING (scrolled_window) +
914 (scrolled_window->shadow_type == GTK_SHADOW_NONE ?
915 0 : widget->style->ythickness));
917 child_allocation.y = GTK_CONTAINER (scrolled_window)->border_width;
919 child_allocation.width = relative_allocation.width;
920 child_allocation.height = hscrollbar_requisition.height;
921 child_allocation.x += allocation->x;
922 child_allocation.y += allocation->y;
924 if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
926 child_allocation.x -= widget->style->xthickness;
927 child_allocation.width += 2 * widget->style->xthickness;
930 gtk_widget_size_allocate (scrolled_window->hscrollbar, &child_allocation);
932 else if (GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar))
933 gtk_widget_hide (scrolled_window->hscrollbar);
935 if (scrolled_window->vscrollbar_visible)
937 GtkRequisition vscrollbar_requisition;
938 if (!GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar))
939 gtk_widget_show (scrolled_window->vscrollbar);
941 gtk_widget_get_child_requisition (scrolled_window->vscrollbar,
942 &vscrollbar_requisition);
944 if (scrolled_window->window_placement == GTK_CORNER_TOP_LEFT ||
945 scrolled_window->window_placement == GTK_CORNER_BOTTOM_LEFT)
946 child_allocation.x = (relative_allocation.x +
947 relative_allocation.width +
948 SCROLLBAR_SPACING (scrolled_window) +
949 (scrolled_window->shadow_type == GTK_SHADOW_NONE ?
950 0 : widget->style->xthickness));
952 child_allocation.x = GTK_CONTAINER (scrolled_window)->border_width;
954 child_allocation.y = relative_allocation.y;
955 child_allocation.width = vscrollbar_requisition.width;
956 child_allocation.height = relative_allocation.height;
957 child_allocation.x += allocation->x;
958 child_allocation.y += allocation->y;
960 if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
962 child_allocation.y -= widget->style->ythickness;
963 child_allocation.height += 2 * widget->style->ythickness;
966 gtk_widget_size_allocate (scrolled_window->vscrollbar, &child_allocation);
968 else if (GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar))
969 gtk_widget_hide (scrolled_window->vscrollbar);
973 gtk_scrolled_window_scroll_event (GtkWidget *widget,
974 GdkEventScroll *event)
978 g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (widget), FALSE);
979 g_return_val_if_fail (event != NULL, FALSE);
981 if (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_DOWN)
982 range = GTK_SCROLLED_WINDOW (widget)->vscrollbar;
984 range = GTK_SCROLLED_WINDOW (widget)->hscrollbar;
986 if (range && GTK_WIDGET_VISIBLE (range))
988 GtkAdjustment *adj = GTK_RANGE (range)->adjustment;
991 if (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_LEFT)
992 new_value = adj->value - adj->page_increment / 2;
994 new_value = adj->value + adj->page_increment / 2;
996 new_value = CLAMP (new_value, adj->lower, adj->upper - adj->page_size);
997 gtk_adjustment_set_value (adj, new_value);
1006 gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment,
1009 GtkScrolledWindow *scrolled_win;
1011 g_return_if_fail (adjustment != NULL);
1012 g_return_if_fail (data != NULL);
1014 scrolled_win = GTK_SCROLLED_WINDOW (data);
1016 if (scrolled_win->hscrollbar &&
1017 adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_win->hscrollbar)))
1019 if (scrolled_win->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
1023 visible = scrolled_win->hscrollbar_visible;
1024 scrolled_win->hscrollbar_visible = (adjustment->upper - adjustment->lower >
1025 adjustment->page_size);
1026 if (scrolled_win->hscrollbar_visible != visible)
1027 gtk_widget_queue_resize (GTK_WIDGET (scrolled_win));
1030 else if (scrolled_win->vscrollbar &&
1031 adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_win->vscrollbar)))
1033 if (scrolled_win->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
1037 visible = scrolled_win->vscrollbar_visible;
1038 scrolled_win->vscrollbar_visible = (adjustment->upper - adjustment->lower >
1039 adjustment->page_size);
1040 if (scrolled_win->vscrollbar_visible != visible)
1041 gtk_widget_queue_resize (GTK_WIDGET (scrolled_win));
1047 gtk_scrolled_window_add (GtkContainer *container,
1050 GtkScrolledWindow *scrolled_window;
1053 bin = GTK_BIN (container);
1054 g_return_if_fail (bin->child == NULL);
1056 scrolled_window = GTK_SCROLLED_WINDOW (container);
1059 gtk_widget_set_parent (child, GTK_WIDGET (bin));
1061 /* this is a temporary message */
1062 if (!gtk_widget_set_scroll_adjustments (child,
1063 gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
1064 gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar))))
1065 g_warning ("gtk_scrolled_window_add(): cannot add non scrollable widget "
1066 "use gtk_scrolled_window_add_with_viewport() instead");
1070 gtk_scrolled_window_remove (GtkContainer *container,
1073 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container));
1074 g_return_if_fail (child != NULL);
1075 g_return_if_fail (GTK_BIN (container)->child == child);
1077 gtk_widget_set_scroll_adjustments (child, NULL, NULL);
1079 /* chain parent class handler to remove child */
1080 GTK_CONTAINER_CLASS (parent_class)->remove (container, child);
1084 gtk_scrolled_window_add_with_viewport (GtkScrolledWindow *scrolled_window,
1088 GtkWidget *viewport;
1090 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
1091 g_return_if_fail (GTK_IS_WIDGET (child));
1092 g_return_if_fail (child->parent == NULL);
1094 bin = GTK_BIN (scrolled_window);
1096 if (bin->child != NULL)
1098 g_return_if_fail (GTK_IS_VIEWPORT (bin->child));
1099 g_return_if_fail (GTK_BIN (bin->child)->child == NULL);
1101 viewport = bin->child;
1106 gtk_viewport_new (gtk_scrolled_window_get_hadjustment (scrolled_window),
1107 gtk_scrolled_window_get_vadjustment (scrolled_window));
1108 gtk_container_add (GTK_CONTAINER (scrolled_window), viewport);
1111 gtk_widget_show (viewport);
1112 gtk_container_add (GTK_CONTAINER (viewport), child);