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"
31 /* scrolled window policy and size requisition handling:
33 * gtk size requisition works as follows:
34 * a widget upon size-request reports the width and height that it finds
35 * to be best suited to display its contents, including children.
36 * the width and/or height reported from a widget upon size requisition
37 * may be overidden by the user by specifying a width and/or height
38 * other than 0 through gtk_widget_set_usize().
40 * a scrolled window needs (for imlementing all three policy types) to
41 * request its width and height based on two different rationales.
42 * 1) the user wants the scrolled window to just fit into the space
43 * that it gets allocated for a specifc dimension.
44 * 1.1) this does not apply if the user specified a concrete value
45 * value for that specific dimension by either specifying usize for the
46 * scrolled window or for its child.
47 * 2) the user wants the scrolled window to take as much space up as
48 * is desired by the child for a specifc dimension (i.e. POLICY_NEVER).
50 * also, kinda obvious:
51 * 3) a user would certainly not have choosen a scrolled window as a container
52 * for the child, if the resulting allocation takes up more space than the
53 * child would have allocated without the scrolled window.
56 * A) from 1) follows: the scrolled window shouldn't request more space for a
57 * specifc dimension than is required at minimum.
58 * B) from 1.1) follows: the requisition may be overidden by usize of the scrolled
59 * window (done automatically) or by usize of the child (needs to be checked).
60 * C) from 2) follows: for POLICY_NEVER, the scrolled window simply reports the
62 * D) from 3) follows: the scrolled window child's minimum width and minimum height
63 * under A) at least correspond to the space taken up by its scrollbars.
66 #define SCROLLBAR_SPACING(w) (GTK_SCROLLED_WINDOW_GET_CLASS (w)->scrollbar_spacing)
68 #define DEFAULT_SCROLLBAR_SPACING 3
74 ARG_HSCROLLBAR_POLICY,
75 ARG_VSCROLLBAR_POLICY,
81 static void gtk_scrolled_window_class_init (GtkScrolledWindowClass *klass);
82 static void gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window);
83 static void gtk_scrolled_window_set_arg (GtkObject *object,
86 static void gtk_scrolled_window_get_arg (GtkObject *object,
89 static void gtk_scrolled_window_destroy (GtkObject *object);
90 static void gtk_scrolled_window_finalize (GObject *object);
91 static void gtk_scrolled_window_map (GtkWidget *widget);
92 static void gtk_scrolled_window_unmap (GtkWidget *widget);
93 static void gtk_scrolled_window_draw (GtkWidget *widget,
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;
159 object_class->set_arg = gtk_scrolled_window_set_arg;
160 object_class->get_arg = gtk_scrolled_window_get_arg;
161 object_class->destroy = gtk_scrolled_window_destroy;
163 widget_class->map = gtk_scrolled_window_map;
164 widget_class->unmap = gtk_scrolled_window_unmap;
165 widget_class->draw = gtk_scrolled_window_draw;
166 widget_class->expose_event = gtk_scrolled_window_expose;
167 widget_class->size_request = gtk_scrolled_window_size_request;
168 widget_class->size_allocate = gtk_scrolled_window_size_allocate;
169 widget_class->scroll_event = gtk_scrolled_window_scroll_event;
171 container_class->add = gtk_scrolled_window_add;
172 container_class->remove = gtk_scrolled_window_remove;
173 container_class->forall = gtk_scrolled_window_forall;
175 class->scrollbar_spacing = DEFAULT_SCROLLBAR_SPACING;
177 gtk_object_add_arg_type ("GtkScrolledWindow::hadjustment",
179 GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT,
181 gtk_object_add_arg_type ("GtkScrolledWindow::vadjustment",
183 GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT,
185 gtk_object_add_arg_type ("GtkScrolledWindow::hscrollbar_policy",
186 GTK_TYPE_POLICY_TYPE,
188 ARG_HSCROLLBAR_POLICY);
189 gtk_object_add_arg_type ("GtkScrolledWindow::vscrollbar_policy",
190 GTK_TYPE_POLICY_TYPE,
192 ARG_VSCROLLBAR_POLICY);
193 gtk_object_add_arg_type ("GtkScrolledWindow::window_placement",
194 GTK_TYPE_CORNER_TYPE,
196 ARG_WINDOW_PLACEMENT);
197 gtk_object_add_arg_type ("GtkScrolledWindow::shadow",
198 GTK_TYPE_SHADOW_TYPE,
204 gtk_scrolled_window_set_arg (GtkObject *object,
208 GtkScrolledWindow *scrolled_window;
210 scrolled_window = GTK_SCROLLED_WINDOW (object);
214 case ARG_HADJUSTMENT:
215 gtk_scrolled_window_set_hadjustment (scrolled_window, GTK_VALUE_POINTER (*arg));
217 case ARG_VADJUSTMENT:
218 gtk_scrolled_window_set_vadjustment (scrolled_window, GTK_VALUE_POINTER (*arg));
220 case ARG_HSCROLLBAR_POLICY:
221 gtk_scrolled_window_set_policy (scrolled_window,
222 GTK_VALUE_ENUM (*arg),
223 scrolled_window->vscrollbar_policy);
225 case ARG_VSCROLLBAR_POLICY:
226 gtk_scrolled_window_set_policy (scrolled_window,
227 scrolled_window->hscrollbar_policy,
228 GTK_VALUE_ENUM (*arg));
230 case ARG_WINDOW_PLACEMENT:
231 gtk_scrolled_window_set_placement (scrolled_window,
232 GTK_VALUE_ENUM (*arg));
235 gtk_scrolled_window_set_shadow_type (scrolled_window,
236 GTK_VALUE_ENUM (*arg));
244 gtk_scrolled_window_get_arg (GtkObject *object,
248 GtkScrolledWindow *scrolled_window;
250 scrolled_window = GTK_SCROLLED_WINDOW (object);
254 case ARG_HADJUSTMENT:
255 GTK_VALUE_POINTER (*arg) = gtk_scrolled_window_get_hadjustment (scrolled_window);
257 case ARG_VADJUSTMENT:
258 GTK_VALUE_POINTER (*arg) = gtk_scrolled_window_get_vadjustment (scrolled_window);
260 case ARG_HSCROLLBAR_POLICY:
261 GTK_VALUE_ENUM (*arg) = scrolled_window->hscrollbar_policy;
263 case ARG_VSCROLLBAR_POLICY:
264 GTK_VALUE_ENUM (*arg) = scrolled_window->vscrollbar_policy;
266 case ARG_WINDOW_PLACEMENT:
267 GTK_VALUE_ENUM (*arg) = scrolled_window->window_placement;
270 GTK_VALUE_ENUM (*arg) = scrolled_window->shadow_type;
273 arg->type = GTK_TYPE_INVALID;
279 gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
281 GTK_WIDGET_SET_FLAGS (scrolled_window, GTK_NO_WINDOW);
283 gtk_container_set_resize_mode (GTK_CONTAINER (scrolled_window), GTK_RESIZE_QUEUE);
285 scrolled_window->hscrollbar = NULL;
286 scrolled_window->vscrollbar = NULL;
287 scrolled_window->hscrollbar_policy = GTK_POLICY_ALWAYS;
288 scrolled_window->vscrollbar_policy = GTK_POLICY_ALWAYS;
289 scrolled_window->hscrollbar_visible = FALSE;
290 scrolled_window->vscrollbar_visible = FALSE;
291 scrolled_window->window_placement = GTK_CORNER_TOP_LEFT;
296 gtk_scrolled_window_new (GtkAdjustment *hadjustment,
297 GtkAdjustment *vadjustment)
299 GtkWidget *scrolled_window;
302 g_return_val_if_fail (GTK_IS_ADJUSTMENT (hadjustment), NULL);
305 g_return_val_if_fail (GTK_IS_ADJUSTMENT (vadjustment), NULL);
307 scrolled_window = gtk_widget_new (GTK_TYPE_SCROLLED_WINDOW,
308 "hadjustment", hadjustment,
309 "vadjustment", vadjustment,
312 return scrolled_window;
316 gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window,
317 GtkAdjustment *hadjustment)
321 g_return_if_fail (scrolled_window != NULL);
322 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
324 g_return_if_fail (GTK_IS_ADJUSTMENT (hadjustment));
326 hadjustment = (GtkAdjustment*) gtk_object_new (GTK_TYPE_ADJUSTMENT, NULL);
328 bin = GTK_BIN (scrolled_window);
330 if (!scrolled_window->hscrollbar)
332 gtk_widget_push_composite_child ();
333 scrolled_window->hscrollbar = gtk_hscrollbar_new (hadjustment);
334 gtk_widget_set_composite_name (scrolled_window->hscrollbar, "hscrollbar");
335 gtk_widget_pop_composite_child ();
337 gtk_widget_set_parent (scrolled_window->hscrollbar, GTK_WIDGET (scrolled_window));
338 gtk_widget_ref (scrolled_window->hscrollbar);
339 gtk_widget_show (scrolled_window->hscrollbar);
343 GtkAdjustment *old_adjustment;
345 old_adjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
346 if (old_adjustment == hadjustment)
349 gtk_signal_disconnect_by_func (GTK_OBJECT (old_adjustment),
350 GTK_SIGNAL_FUNC (gtk_scrolled_window_adjustment_changed),
352 gtk_range_set_adjustment (GTK_RANGE (scrolled_window->hscrollbar),
355 hadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
356 gtk_signal_connect (GTK_OBJECT (hadjustment),
358 GTK_SIGNAL_FUNC (gtk_scrolled_window_adjustment_changed),
360 gtk_scrolled_window_adjustment_changed (hadjustment, scrolled_window);
363 gtk_widget_set_scroll_adjustments (bin->child,
364 gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
365 gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)));
369 gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window,
370 GtkAdjustment *vadjustment)
374 g_return_if_fail (scrolled_window != NULL);
375 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
377 g_return_if_fail (GTK_IS_ADJUSTMENT (vadjustment));
379 vadjustment = (GtkAdjustment*) gtk_object_new (GTK_TYPE_ADJUSTMENT, NULL);
381 bin = GTK_BIN (scrolled_window);
383 if (!scrolled_window->vscrollbar)
385 gtk_widget_push_composite_child ();
386 scrolled_window->vscrollbar = gtk_vscrollbar_new (vadjustment);
387 gtk_widget_set_composite_name (scrolled_window->vscrollbar, "vscrollbar");
388 gtk_widget_pop_composite_child ();
390 gtk_widget_set_parent (scrolled_window->vscrollbar, GTK_WIDGET (scrolled_window));
391 gtk_widget_ref (scrolled_window->vscrollbar);
392 gtk_widget_show (scrolled_window->vscrollbar);
396 GtkAdjustment *old_adjustment;
398 old_adjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
399 if (old_adjustment == vadjustment)
402 gtk_signal_disconnect_by_func (GTK_OBJECT (old_adjustment),
403 GTK_SIGNAL_FUNC (gtk_scrolled_window_adjustment_changed),
405 gtk_range_set_adjustment (GTK_RANGE (scrolled_window->vscrollbar),
408 vadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
409 gtk_signal_connect (GTK_OBJECT (vadjustment),
411 GTK_SIGNAL_FUNC (gtk_scrolled_window_adjustment_changed),
413 gtk_scrolled_window_adjustment_changed (vadjustment, scrolled_window);
416 gtk_widget_set_scroll_adjustments (bin->child,
417 gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
418 gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)));
422 gtk_scrolled_window_get_hadjustment (GtkScrolledWindow *scrolled_window)
424 g_return_val_if_fail (scrolled_window != NULL, NULL);
425 g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
427 return (scrolled_window->hscrollbar ?
428 gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)) :
433 gtk_scrolled_window_get_vadjustment (GtkScrolledWindow *scrolled_window)
435 g_return_val_if_fail (scrolled_window != NULL, NULL);
436 g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
438 return (scrolled_window->vscrollbar ?
439 gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)) :
444 gtk_scrolled_window_set_policy (GtkScrolledWindow *scrolled_window,
445 GtkPolicyType hscrollbar_policy,
446 GtkPolicyType vscrollbar_policy)
448 g_return_if_fail (scrolled_window != NULL);
449 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
451 if ((scrolled_window->hscrollbar_policy != hscrollbar_policy) ||
452 (scrolled_window->vscrollbar_policy != vscrollbar_policy))
454 scrolled_window->hscrollbar_policy = hscrollbar_policy;
455 scrolled_window->vscrollbar_policy = vscrollbar_policy;
457 gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
462 gtk_scrolled_window_set_placement (GtkScrolledWindow *scrolled_window,
463 GtkCornerType window_placement)
465 g_return_if_fail (scrolled_window != NULL);
466 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
468 if (scrolled_window->window_placement != window_placement)
470 scrolled_window->window_placement = window_placement;
472 gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
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));
495 gtk_scrolled_window_destroy (GtkObject *object)
497 GtkScrolledWindow *scrolled_window;
499 g_return_if_fail (object != NULL);
500 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (object));
502 scrolled_window = GTK_SCROLLED_WINDOW (object);
504 gtk_widget_unparent (scrolled_window->hscrollbar);
505 gtk_widget_unparent (scrolled_window->vscrollbar);
506 gtk_widget_destroy (scrolled_window->hscrollbar);
507 gtk_widget_destroy (scrolled_window->vscrollbar);
509 GTK_OBJECT_CLASS (parent_class)->destroy (object);
513 gtk_scrolled_window_finalize (GObject *object)
515 GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (object);
517 gtk_widget_unref (scrolled_window->hscrollbar);
518 gtk_widget_unref (scrolled_window->vscrollbar);
520 G_OBJECT_CLASS (parent_class)->finalize (object);
524 gtk_scrolled_window_map (GtkWidget *widget)
526 GtkScrolledWindow *scrolled_window;
528 g_return_if_fail (widget != NULL);
529 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
531 scrolled_window = GTK_SCROLLED_WINDOW (widget);
533 /* chain parent class handler to map self and child */
534 GTK_WIDGET_CLASS (parent_class)->map (widget);
536 if (GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar) &&
537 !GTK_WIDGET_MAPPED (scrolled_window->hscrollbar))
538 gtk_widget_map (scrolled_window->hscrollbar);
540 if (GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar) &&
541 !GTK_WIDGET_MAPPED (scrolled_window->vscrollbar))
542 gtk_widget_map (scrolled_window->vscrollbar);
546 gtk_scrolled_window_unmap (GtkWidget *widget)
548 GtkScrolledWindow *scrolled_window;
550 g_return_if_fail (widget != NULL);
551 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
553 scrolled_window = GTK_SCROLLED_WINDOW (widget);
555 /* chain parent class handler to unmap self and child */
556 GTK_WIDGET_CLASS (parent_class)->unmap (widget);
558 if (GTK_WIDGET_MAPPED (scrolled_window->hscrollbar))
559 gtk_widget_unmap (scrolled_window->hscrollbar);
561 if (GTK_WIDGET_MAPPED (scrolled_window->vscrollbar))
562 gtk_widget_unmap (scrolled_window->vscrollbar);
566 gtk_scrolled_window_paint (GtkWidget *widget,
569 GtkAllocation relative_allocation;
570 GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
572 if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
574 gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
576 relative_allocation.x -= widget->style->xthickness;
577 relative_allocation.y -= widget->style->ythickness;
578 relative_allocation.width += 2 * widget->style->xthickness;
579 relative_allocation.height += 2 * widget->style->ythickness;
581 gtk_paint_shadow (widget->style, widget->window,
582 GTK_STATE_NORMAL, scrolled_window->shadow_type,
583 area, widget, "scrolled_window",
584 widget->allocation.x + relative_allocation.x,
585 widget->allocation.y + relative_allocation.y,
586 relative_allocation.width,
587 relative_allocation.height);
592 gtk_scrolled_window_draw (GtkWidget *widget,
595 GtkScrolledWindow *scrolled_window;
597 GdkRectangle child_area;
599 g_return_if_fail (widget != NULL);
600 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
601 g_return_if_fail (area != NULL);
603 scrolled_window = GTK_SCROLLED_WINDOW (widget);
604 bin = GTK_BIN (widget);
606 if (GTK_WIDGET_DRAWABLE (widget))
608 gtk_scrolled_window_paint (widget, area);
610 if (bin->child && GTK_WIDGET_VISIBLE (bin->child) &&
611 gtk_widget_intersect (bin->child, area, &child_area))
612 gtk_widget_draw (bin->child, &child_area);
614 if (GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar) &&
615 gtk_widget_intersect (scrolled_window->hscrollbar, area, &child_area))
616 gtk_widget_draw (scrolled_window->hscrollbar, &child_area);
618 if (GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar) &&
619 gtk_widget_intersect (scrolled_window->vscrollbar, area, &child_area))
620 gtk_widget_draw (scrolled_window->vscrollbar, &child_area);
625 gtk_scrolled_window_expose (GtkWidget *widget,
626 GdkEventExpose *event)
628 GtkBin *bin = GTK_BIN (widget);
629 GdkEventExpose child_event;
631 if (GTK_WIDGET_DRAWABLE (widget))
633 gtk_scrolled_window_paint (widget, &event->area);
635 if (bin->child && GTK_WIDGET_VISIBLE (bin->child) && GTK_WIDGET_NO_WINDOW (bin->child))
637 child_event = *event;
638 if (gtk_widget_intersect (bin->child, &event->area, &child_event.area))
639 gtk_widget_event (bin->child, (GdkEvent*) &child_event);
642 /* We rely on our knowledge that scrollbars are !NO_WINDOW widgets */
649 gtk_scrolled_window_forall (GtkContainer *container,
650 gboolean include_internals,
651 GtkCallback callback,
652 gpointer callback_data)
654 g_return_if_fail (container != NULL);
655 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container));
656 g_return_if_fail (callback != NULL);
658 GTK_CONTAINER_CLASS (parent_class)->forall (container,
662 if (include_internals)
664 GtkScrolledWindow *scrolled_window;
666 scrolled_window = GTK_SCROLLED_WINDOW (container);
668 if (scrolled_window->vscrollbar)
669 callback (scrolled_window->vscrollbar, callback_data);
670 if (scrolled_window->hscrollbar)
671 callback (scrolled_window->hscrollbar, callback_data);
676 gtk_scrolled_window_size_request (GtkWidget *widget,
677 GtkRequisition *requisition)
679 GtkScrolledWindow *scrolled_window;
683 GtkRequisition hscrollbar_requisition;
684 GtkRequisition vscrollbar_requisition;
685 GtkRequisition child_requisition;
687 g_return_if_fail (widget != NULL);
688 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
689 g_return_if_fail (requisition != NULL);
691 scrolled_window = GTK_SCROLLED_WINDOW (widget);
692 bin = GTK_BIN (scrolled_window);
696 requisition->width = 0;
697 requisition->height = 0;
699 gtk_widget_size_request (scrolled_window->hscrollbar,
700 &hscrollbar_requisition);
701 gtk_widget_size_request (scrolled_window->vscrollbar,
702 &vscrollbar_requisition);
704 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
706 static guint quark_aux_info = 0;
709 quark_aux_info = g_quark_from_static_string ("gtk-aux-info");
711 gtk_widget_size_request (bin->child, &child_requisition);
713 if (scrolled_window->hscrollbar_policy == GTK_POLICY_NEVER)
714 requisition->width += child_requisition.width;
717 GtkWidgetAuxInfo *aux_info;
719 aux_info = gtk_object_get_data_by_id (GTK_OBJECT (bin->child), quark_aux_info);
720 if (aux_info && aux_info->width > 0)
722 requisition->width += aux_info->width;
726 requisition->width += vscrollbar_requisition.width;
729 if (scrolled_window->vscrollbar_policy == GTK_POLICY_NEVER)
730 requisition->height += child_requisition.height;
733 GtkWidgetAuxInfo *aux_info;
735 aux_info = gtk_object_get_data_by_id (GTK_OBJECT (bin->child), quark_aux_info);
736 if (aux_info && aux_info->height > 0)
738 requisition->height += aux_info->height;
742 requisition->height += hscrollbar_requisition.height;
746 if (scrolled_window->hscrollbar_policy == GTK_POLICY_AUTOMATIC ||
747 scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
749 requisition->width = MAX (requisition->width, hscrollbar_requisition.width);
750 if (!extra_height || scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
751 extra_height = SCROLLBAR_SPACING (scrolled_window) + hscrollbar_requisition.height;
754 if (scrolled_window->vscrollbar_policy == GTK_POLICY_AUTOMATIC ||
755 scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
757 requisition->height = MAX (requisition->height, vscrollbar_requisition.height);
758 if (!extra_height || scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
759 extra_width = SCROLLBAR_SPACING (scrolled_window) + vscrollbar_requisition.width;
762 requisition->width += GTK_CONTAINER (widget)->border_width * 2 + MAX (0, extra_width);
763 requisition->height += GTK_CONTAINER (widget)->border_width * 2 + MAX (0, extra_height);
765 if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
767 requisition->width += 2 * widget->style->xthickness;
768 requisition->height += 2 * widget->style->ythickness;
773 gtk_scrolled_window_relative_allocation (GtkWidget *widget,
774 GtkAllocation *allocation)
776 GtkScrolledWindow *scrolled_window;
778 g_return_if_fail (widget != NULL);
779 g_return_if_fail (allocation != NULL);
781 scrolled_window = GTK_SCROLLED_WINDOW (widget);
783 allocation->x = GTK_CONTAINER (widget)->border_width;
784 allocation->y = GTK_CONTAINER (widget)->border_width;
786 if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
788 allocation->x += widget->style->xthickness;
789 allocation->y += widget->style->ythickness;
792 allocation->width = MAX (1, (gint)widget->allocation.width - allocation->x * 2);
793 allocation->height = MAX (1, (gint)widget->allocation.height - allocation->y * 2);
795 if (scrolled_window->vscrollbar_visible)
797 GtkRequisition vscrollbar_requisition;
798 gtk_widget_get_child_requisition (scrolled_window->vscrollbar,
799 &vscrollbar_requisition);
801 if (scrolled_window->window_placement == GTK_CORNER_TOP_RIGHT ||
802 scrolled_window->window_placement == GTK_CORNER_BOTTOM_RIGHT)
803 allocation->x += (vscrollbar_requisition.width +
804 SCROLLBAR_SPACING (scrolled_window));
806 allocation->width = MAX (1, (gint)allocation->width -
807 ((gint)vscrollbar_requisition.width +
808 (gint)SCROLLBAR_SPACING (scrolled_window)));
810 if (scrolled_window->hscrollbar_visible)
812 GtkRequisition hscrollbar_requisition;
813 gtk_widget_get_child_requisition (scrolled_window->hscrollbar,
814 &hscrollbar_requisition);
816 if (scrolled_window->window_placement == GTK_CORNER_BOTTOM_LEFT ||
817 scrolled_window->window_placement == GTK_CORNER_BOTTOM_RIGHT)
818 allocation->y += (hscrollbar_requisition.height +
819 SCROLLBAR_SPACING (scrolled_window));
821 allocation->height = MAX (1, (gint)allocation->height -
822 ((gint)hscrollbar_requisition.height +
823 (gint)SCROLLBAR_SPACING (scrolled_window)));
828 gtk_scrolled_window_size_allocate (GtkWidget *widget,
829 GtkAllocation *allocation)
831 GtkScrolledWindow *scrolled_window;
833 GtkAllocation relative_allocation;
834 GtkAllocation child_allocation;
836 g_return_if_fail (widget != NULL);
837 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
838 g_return_if_fail (allocation != NULL);
840 scrolled_window = GTK_SCROLLED_WINDOW (widget);
841 bin = GTK_BIN (scrolled_window);
843 widget->allocation = *allocation;
845 if (scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
846 scrolled_window->hscrollbar_visible = TRUE;
847 else if (scrolled_window->hscrollbar_policy == GTK_POLICY_NEVER)
848 scrolled_window->hscrollbar_visible = FALSE;
849 if (scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
850 scrolled_window->vscrollbar_visible = TRUE;
851 else if (scrolled_window->vscrollbar_policy == GTK_POLICY_NEVER)
852 scrolled_window->vscrollbar_visible = FALSE;
854 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
856 gboolean previous_hvis;
857 gboolean previous_vvis;
862 gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
864 child_allocation.x = relative_allocation.x + allocation->x;
865 child_allocation.y = relative_allocation.y + allocation->y;
866 child_allocation.width = relative_allocation.width;
867 child_allocation.height = relative_allocation.height;
869 previous_hvis = scrolled_window->hscrollbar_visible;
870 previous_vvis = scrolled_window->vscrollbar_visible;
872 gtk_widget_size_allocate (bin->child, &child_allocation);
874 /* If, after the first iteration, the hscrollbar and the
875 * vscrollbar flip visiblity, then we need both.
878 previous_hvis != scrolled_window->hscrollbar_visible &&
879 previous_vvis != scrolled_window->vscrollbar_visible)
881 scrolled_window->hscrollbar_visible = TRUE;
882 scrolled_window->vscrollbar_visible = TRUE;
884 /* a new resize is already queued at this point,
885 * so we will immediatedly get reinvoked
892 while (previous_hvis != scrolled_window->hscrollbar_visible ||
893 previous_vvis != scrolled_window->vscrollbar_visible);
896 gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
898 if (scrolled_window->hscrollbar_visible)
900 GtkRequisition hscrollbar_requisition;
901 gtk_widget_get_child_requisition (scrolled_window->hscrollbar,
902 &hscrollbar_requisition);
904 if (!GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar))
905 gtk_widget_show (scrolled_window->hscrollbar);
907 child_allocation.x = relative_allocation.x;
908 if (scrolled_window->window_placement == GTK_CORNER_TOP_LEFT ||
909 scrolled_window->window_placement == GTK_CORNER_TOP_RIGHT)
910 child_allocation.y = (relative_allocation.y +
911 relative_allocation.height +
912 SCROLLBAR_SPACING (scrolled_window) +
913 (scrolled_window->shadow_type == GTK_SHADOW_NONE ?
914 0 : widget->style->ythickness));
916 child_allocation.y = GTK_CONTAINER (scrolled_window)->border_width;
918 child_allocation.width = relative_allocation.width;
919 child_allocation.height = hscrollbar_requisition.height;
920 child_allocation.x += allocation->x;
921 child_allocation.y += allocation->y;
923 if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
925 child_allocation.x -= widget->style->xthickness;
926 child_allocation.width += 2 * widget->style->xthickness;
929 gtk_widget_size_allocate (scrolled_window->hscrollbar, &child_allocation);
931 else if (GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar))
932 gtk_widget_hide (scrolled_window->hscrollbar);
934 if (scrolled_window->vscrollbar_visible)
936 GtkRequisition vscrollbar_requisition;
937 if (!GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar))
938 gtk_widget_show (scrolled_window->vscrollbar);
940 gtk_widget_get_child_requisition (scrolled_window->vscrollbar,
941 &vscrollbar_requisition);
943 if (scrolled_window->window_placement == GTK_CORNER_TOP_LEFT ||
944 scrolled_window->window_placement == GTK_CORNER_BOTTOM_LEFT)
945 child_allocation.x = (relative_allocation.x +
946 relative_allocation.width +
947 SCROLLBAR_SPACING (scrolled_window) +
948 (scrolled_window->shadow_type == GTK_SHADOW_NONE ?
949 0 : widget->style->xthickness));
951 child_allocation.x = GTK_CONTAINER (scrolled_window)->border_width;
953 child_allocation.y = relative_allocation.y;
954 child_allocation.width = vscrollbar_requisition.width;
955 child_allocation.height = relative_allocation.height;
956 child_allocation.x += allocation->x;
957 child_allocation.y += allocation->y;
959 if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
961 child_allocation.y -= widget->style->ythickness;
962 child_allocation.height += 2 * widget->style->ythickness;
965 gtk_widget_size_allocate (scrolled_window->vscrollbar, &child_allocation);
967 else if (GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar))
968 gtk_widget_hide (scrolled_window->vscrollbar);
972 gtk_scrolled_window_scroll_event (GtkWidget *widget,
973 GdkEventScroll *event)
977 g_return_val_if_fail (widget != NULL, FALSE);
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 (adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_win->hscrollbar)))
1018 if (scrolled_win->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
1022 visible = scrolled_win->hscrollbar_visible;
1023 scrolled_win->hscrollbar_visible = (adjustment->upper - adjustment->lower >
1024 adjustment->page_size);
1025 if (scrolled_win->hscrollbar_visible != visible)
1026 gtk_widget_queue_resize (GTK_WIDGET (scrolled_win));
1029 else if (adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_win->vscrollbar)))
1031 if (scrolled_win->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
1035 visible = scrolled_win->vscrollbar_visible;
1036 scrolled_win->vscrollbar_visible = (adjustment->upper - adjustment->lower >
1037 adjustment->page_size);
1038 if (scrolled_win->vscrollbar_visible != visible)
1039 gtk_widget_queue_resize (GTK_WIDGET (scrolled_win));
1045 gtk_scrolled_window_add (GtkContainer *container,
1048 GtkScrolledWindow *scrolled_window;
1051 bin = GTK_BIN (container);
1052 g_return_if_fail (bin->child == NULL);
1054 scrolled_window = GTK_SCROLLED_WINDOW (container);
1057 gtk_widget_set_parent (child, GTK_WIDGET (bin));
1059 /* this is a temporary message */
1060 if (!gtk_widget_set_scroll_adjustments (child,
1061 gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
1062 gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar))))
1063 g_warning ("gtk_scrolled_window_add(): cannot add non scrollable widget "
1064 "use gtk_scrolled_window_add_with_viewport() instead");
1066 if (GTK_WIDGET_REALIZED (child->parent))
1067 gtk_widget_realize (child);
1069 if (GTK_WIDGET_VISIBLE (child->parent) && GTK_WIDGET_VISIBLE (child))
1071 if (GTK_WIDGET_MAPPED (child->parent))
1072 gtk_widget_map (child);
1074 gtk_widget_queue_resize (child);
1079 gtk_scrolled_window_remove (GtkContainer *container,
1082 g_return_if_fail (container != NULL);
1083 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container));
1084 g_return_if_fail (child != NULL);
1085 g_return_if_fail (GTK_BIN (container)->child == child);
1087 gtk_widget_set_scroll_adjustments (child, NULL, NULL);
1089 /* chain parent class handler to remove child */
1090 GTK_CONTAINER_CLASS (parent_class)->remove (container, child);
1094 gtk_scrolled_window_add_with_viewport (GtkScrolledWindow *scrolled_window,
1098 GtkWidget *viewport;
1100 g_return_if_fail (scrolled_window != NULL);
1101 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
1102 g_return_if_fail (child != NULL);
1103 g_return_if_fail (GTK_IS_WIDGET (child));
1104 g_return_if_fail (child->parent == NULL);
1106 bin = GTK_BIN (scrolled_window);
1108 if (bin->child != NULL)
1110 g_return_if_fail (GTK_IS_VIEWPORT (bin->child));
1111 g_return_if_fail (GTK_BIN (bin->child)->child == NULL);
1113 viewport = bin->child;
1118 gtk_viewport_new (gtk_scrolled_window_get_hadjustment (scrolled_window),
1119 gtk_scrolled_window_get_vadjustment (scrolled_window));
1120 gtk_container_add (GTK_CONTAINER (scrolled_window), viewport);
1123 gtk_widget_show (viewport);
1124 gtk_container_add (GTK_CONTAINER (viewport), child);