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/.
29 #include <gdk/gdkkeysyms.h>
30 #include "gtkbindings.h"
31 #include "gtkmarshalers.h"
32 #include "gtkscrolledwindow.h"
33 #include "gtkwindow.h"
34 #include "gtkprivate.h"
37 /* scrolled window policy and size requisition handling:
39 * gtk size requisition works as follows:
40 * a widget upon size-request reports the width and height that it finds
41 * to be best suited to display its contents, including children.
42 * the width and/or height reported from a widget upon size requisition
43 * may be overidden by the user by specifying a width and/or height
44 * other than 0 through gtk_widget_set_size_request().
46 * a scrolled window needs (for implementing all three policy types) to
47 * request its width and height based on two different rationales.
48 * 1) the user wants the scrolled window to just fit into the space
49 * that it gets allocated for a specifc dimension.
50 * 1.1) this does not apply if the user specified a concrete value
51 * value for that specific dimension by either specifying usize for the
52 * scrolled window or for its child.
53 * 2) the user wants the scrolled window to take as much space up as
54 * is desired by the child for a specifc dimension (i.e. POLICY_NEVER).
56 * also, kinda obvious:
57 * 3) a user would certainly not have choosen a scrolled window as a container
58 * for the child, if the resulting allocation takes up more space than the
59 * child would have allocated without the scrolled window.
62 * A) from 1) follows: the scrolled window shouldn't request more space for a
63 * specifc dimension than is required at minimum.
64 * B) from 1.1) follows: the requisition may be overidden by usize of the scrolled
65 * window (done automatically) or by usize of the child (needs to be checked).
66 * C) from 2) follows: for POLICY_NEVER, the scrolled window simply reports the
68 * D) from 3) follows: the scrolled window child's minimum width and minimum height
69 * under A) at least correspond to the space taken up by its scrollbars.
72 #define DEFAULT_SCROLLBAR_SPACING 3
74 struct _GtkScrolledWindowPrivate
76 GtkCornerType real_window_placement;
77 GtkWidget *hscrollbar;
78 GtkWidget *vscrollbar;
80 gboolean window_placement_set;
84 guint hscrollbar_policy : 2;
85 guint vscrollbar_policy : 2;
86 guint hscrollbar_visible : 1;
87 guint vscrollbar_visible : 1;
88 guint window_placement : 2;
89 guint focus_out : 1; /* Flag used by ::move-focus-out implementation */
97 PROP_HSCROLLBAR_POLICY,
98 PROP_VSCROLLBAR_POLICY,
99 PROP_WINDOW_PLACEMENT,
100 PROP_WINDOW_PLACEMENT_SET,
112 static void gtk_scrolled_window_set_property (GObject *object,
116 static void gtk_scrolled_window_get_property (GObject *object,
121 static void gtk_scrolled_window_destroy (GtkWidget *widget);
122 static void gtk_scrolled_window_screen_changed (GtkWidget *widget,
123 GdkScreen *previous_screen);
124 static gboolean gtk_scrolled_window_draw (GtkWidget *widget,
126 static void gtk_scrolled_window_size_allocate (GtkWidget *widget,
127 GtkAllocation *allocation);
128 static gboolean gtk_scrolled_window_scroll_event (GtkWidget *widget,
129 GdkEventScroll *event);
130 static gboolean gtk_scrolled_window_focus (GtkWidget *widget,
131 GtkDirectionType direction);
132 static void gtk_scrolled_window_add (GtkContainer *container,
134 static void gtk_scrolled_window_remove (GtkContainer *container,
136 static void gtk_scrolled_window_forall (GtkContainer *container,
137 gboolean include_internals,
138 GtkCallback callback,
139 gpointer callback_data);
140 static gboolean gtk_scrolled_window_scroll_child (GtkScrolledWindow *scrolled_window,
141 GtkScrollType scroll,
142 gboolean horizontal);
143 static void gtk_scrolled_window_move_focus_out (GtkScrolledWindow *scrolled_window,
144 GtkDirectionType direction_type);
146 static void gtk_scrolled_window_relative_allocation(GtkWidget *widget,
147 GtkAllocation *allocation);
148 static void gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment,
151 static void gtk_scrolled_window_update_real_placement (GtkScrolledWindow *scrolled_window);
153 static void gtk_scrolled_window_get_preferred_width (GtkWidget *widget,
156 static void gtk_scrolled_window_get_preferred_height (GtkWidget *widget,
159 static void gtk_scrolled_window_get_preferred_height_for_width (GtkWidget *layout,
161 gint *minimum_height,
162 gint *natural_height);
163 static void gtk_scrolled_window_get_preferred_width_for_height (GtkWidget *layout,
165 gint *minimum_height,
166 gint *natural_height);
168 static guint signals[LAST_SIGNAL] = {0};
170 G_DEFINE_TYPE (GtkScrolledWindow, gtk_scrolled_window, GTK_TYPE_BIN)
174 add_scroll_binding (GtkBindingSet *binding_set,
176 GdkModifierType mask,
177 GtkScrollType scroll,
180 guint keypad_keyval = keyval - GDK_KEY_Left + GDK_KEY_KP_Left;
182 gtk_binding_entry_add_signal (binding_set, keyval, mask,
184 GTK_TYPE_SCROLL_TYPE, scroll,
185 G_TYPE_BOOLEAN, horizontal);
186 gtk_binding_entry_add_signal (binding_set, keypad_keyval, mask,
188 GTK_TYPE_SCROLL_TYPE, scroll,
189 G_TYPE_BOOLEAN, horizontal);
193 add_tab_bindings (GtkBindingSet *binding_set,
194 GdkModifierType modifiers,
195 GtkDirectionType direction)
197 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, modifiers,
199 GTK_TYPE_DIRECTION_TYPE, direction);
200 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, modifiers,
202 GTK_TYPE_DIRECTION_TYPE, direction);
206 gtk_scrolled_window_class_init (GtkScrolledWindowClass *class)
208 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
209 GtkWidgetClass *widget_class;
210 GtkContainerClass *container_class;
211 GtkBindingSet *binding_set;
213 widget_class = (GtkWidgetClass*) class;
214 container_class = (GtkContainerClass*) class;
216 gobject_class->set_property = gtk_scrolled_window_set_property;
217 gobject_class->get_property = gtk_scrolled_window_get_property;
219 widget_class->destroy = gtk_scrolled_window_destroy;
220 widget_class->screen_changed = gtk_scrolled_window_screen_changed;
221 widget_class->draw = gtk_scrolled_window_draw;
222 widget_class->size_allocate = gtk_scrolled_window_size_allocate;
223 widget_class->scroll_event = gtk_scrolled_window_scroll_event;
224 widget_class->focus = gtk_scrolled_window_focus;
225 widget_class->get_preferred_width = gtk_scrolled_window_get_preferred_width;
226 widget_class->get_preferred_height = gtk_scrolled_window_get_preferred_height;
227 widget_class->get_preferred_height_for_width = gtk_scrolled_window_get_preferred_height_for_width;
228 widget_class->get_preferred_width_for_height = gtk_scrolled_window_get_preferred_width_for_height;
230 container_class->add = gtk_scrolled_window_add;
231 container_class->remove = gtk_scrolled_window_remove;
232 container_class->forall = gtk_scrolled_window_forall;
234 class->scrollbar_spacing = -1;
236 class->scroll_child = gtk_scrolled_window_scroll_child;
237 class->move_focus_out = gtk_scrolled_window_move_focus_out;
239 g_object_class_install_property (gobject_class,
241 g_param_spec_object ("hadjustment",
242 P_("Horizontal Adjustment"),
243 P_("The GtkAdjustment for the horizontal position"),
245 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
246 g_object_class_install_property (gobject_class,
248 g_param_spec_object ("vadjustment",
249 P_("Vertical Adjustment"),
250 P_("The GtkAdjustment for the vertical position"),
252 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
253 g_object_class_install_property (gobject_class,
254 PROP_HSCROLLBAR_POLICY,
255 g_param_spec_enum ("hscrollbar-policy",
256 P_("Horizontal Scrollbar Policy"),
257 P_("When the horizontal scrollbar is displayed"),
258 GTK_TYPE_POLICY_TYPE,
259 GTK_POLICY_AUTOMATIC,
260 GTK_PARAM_READABLE | GTK_PARAM_WRITABLE));
261 g_object_class_install_property (gobject_class,
262 PROP_VSCROLLBAR_POLICY,
263 g_param_spec_enum ("vscrollbar-policy",
264 P_("Vertical Scrollbar Policy"),
265 P_("When the vertical scrollbar is displayed"),
266 GTK_TYPE_POLICY_TYPE,
267 GTK_POLICY_AUTOMATIC,
268 GTK_PARAM_READABLE | GTK_PARAM_WRITABLE));
270 g_object_class_install_property (gobject_class,
271 PROP_WINDOW_PLACEMENT,
272 g_param_spec_enum ("window-placement",
273 P_("Window Placement"),
274 P_("Where the contents are located with respect to the scrollbars. This property only takes effect if \"window-placement-set\" is TRUE."),
275 GTK_TYPE_CORNER_TYPE,
277 GTK_PARAM_READABLE | GTK_PARAM_WRITABLE));
280 * GtkScrolledWindow:window-placement-set:
282 * Whether "window-placement" should be used to determine the location
283 * of the contents with respect to the scrollbars. Otherwise, the
284 * "gtk-scrolled-window-placement" setting is used.
288 g_object_class_install_property (gobject_class,
289 PROP_WINDOW_PLACEMENT_SET,
290 g_param_spec_boolean ("window-placement-set",
291 P_("Window Placement Set"),
292 P_("Whether \"window-placement\" should be used to determine the location of the contents with respect to the scrollbars."),
294 GTK_PARAM_READABLE | GTK_PARAM_WRITABLE));
295 g_object_class_install_property (gobject_class,
297 g_param_spec_enum ("shadow-type",
299 P_("Style of bevel around the contents"),
300 GTK_TYPE_SHADOW_TYPE,
302 GTK_PARAM_READABLE | GTK_PARAM_WRITABLE));
305 * GtkScrolledWindow:scrollbars-within-bevel:
307 * Whether to place scrollbars within the scrolled window's bevel.
311 gtk_widget_class_install_style_property (widget_class,
312 g_param_spec_boolean ("scrollbars-within-bevel",
313 P_("Scrollbars within bevel"),
314 P_("Place scrollbars within the scrolled window's bevel"),
316 GTK_PARAM_READABLE));
318 gtk_widget_class_install_style_property (widget_class,
319 g_param_spec_int ("scrollbar-spacing",
320 P_("Scrollbar spacing"),
321 P_("Number of pixels between the scrollbars and the scrolled window"),
324 DEFAULT_SCROLLBAR_SPACING,
325 GTK_PARAM_READABLE));
328 * GtkSettings:gtk-scrolled-window-placement:
330 * Where the contents of scrolled windows are located with respect to the
331 * scrollbars, if not overridden by the scrolled window's own placement.
335 gtk_settings_install_property (g_param_spec_enum ("gtk-scrolled-window-placement",
336 P_("Scrolled Window Placement"),
337 P_("Where the contents of scrolled windows are located with respect to the scrollbars, if not overridden by the scrolled window's own placement."),
338 GTK_TYPE_CORNER_TYPE,
340 G_PARAM_READABLE | G_PARAM_WRITABLE));
343 signals[SCROLL_CHILD] =
344 g_signal_new (I_("scroll-child"),
345 G_TYPE_FROM_CLASS (gobject_class),
346 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
347 G_STRUCT_OFFSET (GtkScrolledWindowClass, scroll_child),
349 _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
351 GTK_TYPE_SCROLL_TYPE,
353 signals[MOVE_FOCUS_OUT] =
354 g_signal_new (I_("move-focus-out"),
355 G_TYPE_FROM_CLASS (gobject_class),
356 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
357 G_STRUCT_OFFSET (GtkScrolledWindowClass, move_focus_out),
359 _gtk_marshal_VOID__ENUM,
361 GTK_TYPE_DIRECTION_TYPE);
363 binding_set = gtk_binding_set_by_class (class);
365 add_scroll_binding (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK, GTK_SCROLL_STEP_BACKWARD, TRUE);
366 add_scroll_binding (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK, GTK_SCROLL_STEP_FORWARD, TRUE);
367 add_scroll_binding (binding_set, GDK_KEY_Up, GDK_CONTROL_MASK, GTK_SCROLL_STEP_BACKWARD, FALSE);
368 add_scroll_binding (binding_set, GDK_KEY_Down, GDK_CONTROL_MASK, GTK_SCROLL_STEP_FORWARD, FALSE);
370 add_scroll_binding (binding_set, GDK_KEY_Page_Up, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_BACKWARD, TRUE);
371 add_scroll_binding (binding_set, GDK_KEY_Page_Down, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_FORWARD, TRUE);
372 add_scroll_binding (binding_set, GDK_KEY_Page_Up, 0, GTK_SCROLL_PAGE_BACKWARD, FALSE);
373 add_scroll_binding (binding_set, GDK_KEY_Page_Down, 0, GTK_SCROLL_PAGE_FORWARD, FALSE);
375 add_scroll_binding (binding_set, GDK_KEY_Home, GDK_CONTROL_MASK, GTK_SCROLL_START, TRUE);
376 add_scroll_binding (binding_set, GDK_KEY_End, GDK_CONTROL_MASK, GTK_SCROLL_END, TRUE);
377 add_scroll_binding (binding_set, GDK_KEY_Home, 0, GTK_SCROLL_START, FALSE);
378 add_scroll_binding (binding_set, GDK_KEY_End, 0, GTK_SCROLL_END, FALSE);
380 add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
381 add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
383 g_type_class_add_private (class, sizeof (GtkScrolledWindowPrivate));
387 gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
389 GtkScrolledWindowPrivate *priv;
391 scrolled_window->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (scrolled_window,
392 GTK_TYPE_SCROLLED_WINDOW,
393 GtkScrolledWindowPrivate);
395 gtk_widget_set_has_window (GTK_WIDGET (scrolled_window), FALSE);
396 gtk_widget_set_can_focus (GTK_WIDGET (scrolled_window), TRUE);
398 priv->hscrollbar = NULL;
399 priv->vscrollbar = NULL;
400 priv->hscrollbar_policy = GTK_POLICY_AUTOMATIC;
401 priv->vscrollbar_policy = GTK_POLICY_AUTOMATIC;
402 priv->hscrollbar_visible = FALSE;
403 priv->vscrollbar_visible = FALSE;
404 priv->focus_out = FALSE;
405 priv->window_placement = GTK_CORNER_TOP_LEFT;
406 gtk_scrolled_window_update_real_placement (scrolled_window);
410 * gtk_scrolled_window_new:
411 * @hadjustment: (allow-none): horizontal adjustment
412 * @vadjustment: (allow-none): vertical adjustment
414 * Creates a new scrolled window.
416 * The two arguments are the scrolled window's adjustments; these will be
417 * shared with the scrollbars and the child widget to keep the bars in sync
418 * with the child. Usually you want to pass %NULL for the adjustments, which
419 * will cause the scrolled window to create them for you.
421 * Returns: a new scrolled window
424 gtk_scrolled_window_new (GtkAdjustment *hadjustment,
425 GtkAdjustment *vadjustment)
427 GtkWidget *scrolled_window;
430 g_return_val_if_fail (GTK_IS_ADJUSTMENT (hadjustment), NULL);
433 g_return_val_if_fail (GTK_IS_ADJUSTMENT (vadjustment), NULL);
435 scrolled_window = g_object_new (GTK_TYPE_SCROLLED_WINDOW,
436 "hadjustment", hadjustment,
437 "vadjustment", vadjustment,
440 return scrolled_window;
444 * gtk_scrolled_window_set_hadjustment:
445 * @scrolled_window: a #GtkScrolledWindow
446 * @hadjustment: horizontal scroll adjustment
448 * Sets the #GtkAdjustment for the horizontal scrollbar.
451 gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window,
452 GtkAdjustment *hadjustment)
454 GtkScrolledWindowPrivate *priv;
458 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
460 g_return_if_fail (GTK_IS_ADJUSTMENT (hadjustment));
462 hadjustment = (GtkAdjustment*) g_object_new (GTK_TYPE_ADJUSTMENT, NULL);
464 bin = GTK_BIN (scrolled_window);
465 priv = scrolled_window->priv;
467 if (!priv->hscrollbar)
469 gtk_widget_push_composite_child ();
470 priv->hscrollbar = gtk_hscrollbar_new (hadjustment);
471 gtk_widget_set_composite_name (priv->hscrollbar, "hscrollbar");
472 gtk_widget_pop_composite_child ();
474 gtk_widget_set_parent (priv->hscrollbar, GTK_WIDGET (scrolled_window));
475 g_object_ref (priv->hscrollbar);
476 gtk_widget_show (priv->hscrollbar);
480 GtkAdjustment *old_adjustment;
482 old_adjustment = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar));
483 if (old_adjustment == hadjustment)
486 g_signal_handlers_disconnect_by_func (old_adjustment,
487 gtk_scrolled_window_adjustment_changed,
489 gtk_range_set_adjustment (GTK_RANGE (priv->hscrollbar),
492 hadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar));
493 g_signal_connect (hadjustment,
495 G_CALLBACK (gtk_scrolled_window_adjustment_changed),
497 gtk_scrolled_window_adjustment_changed (hadjustment, scrolled_window);
499 child = gtk_bin_get_child (bin);
501 gtk_widget_set_scroll_adjustments (child,
502 gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar)),
503 gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar)));
505 g_object_notify (G_OBJECT (scrolled_window), "hadjustment");
509 * gtk_scrolled_window_set_vadjustment:
510 * @scrolled_window: a #GtkScrolledWindow
511 * @vadjustment: vertical scroll adjustment
513 * Sets the #GtkAdjustment for the vertical scrollbar.
516 gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window,
517 GtkAdjustment *vadjustment)
519 GtkScrolledWindowPrivate *priv;
523 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
525 g_return_if_fail (GTK_IS_ADJUSTMENT (vadjustment));
527 vadjustment = (GtkAdjustment*) g_object_new (GTK_TYPE_ADJUSTMENT, NULL);
529 bin = GTK_BIN (scrolled_window);
530 priv = scrolled_window->priv;
532 if (!priv->vscrollbar)
534 gtk_widget_push_composite_child ();
535 priv->vscrollbar = gtk_vscrollbar_new (vadjustment);
536 gtk_widget_set_composite_name (priv->vscrollbar, "vscrollbar");
537 gtk_widget_pop_composite_child ();
539 gtk_widget_set_parent (priv->vscrollbar, GTK_WIDGET (scrolled_window));
540 g_object_ref (priv->vscrollbar);
541 gtk_widget_show (priv->vscrollbar);
545 GtkAdjustment *old_adjustment;
547 old_adjustment = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar));
548 if (old_adjustment == vadjustment)
551 g_signal_handlers_disconnect_by_func (old_adjustment,
552 gtk_scrolled_window_adjustment_changed,
554 gtk_range_set_adjustment (GTK_RANGE (priv->vscrollbar),
557 vadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar));
558 g_signal_connect (vadjustment,
560 G_CALLBACK (gtk_scrolled_window_adjustment_changed),
562 gtk_scrolled_window_adjustment_changed (vadjustment, scrolled_window);
564 child = gtk_bin_get_child (bin);
566 gtk_widget_set_scroll_adjustments (child,
567 gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar)),
568 gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar)));
570 g_object_notify (G_OBJECT (scrolled_window), "vadjustment");
574 * gtk_scrolled_window_get_hadjustment:
575 * @scrolled_window: a #GtkScrolledWindow
577 * Returns the horizontal scrollbar's adjustment, used to connect the
578 * horizontal scrollbar to the child widget's horizontal scroll
581 * Returns: (transfer none): the horizontal #GtkAdjustment
584 gtk_scrolled_window_get_hadjustment (GtkScrolledWindow *scrolled_window)
586 GtkScrolledWindowPrivate *priv;
588 g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
590 priv = scrolled_window->priv;
592 return (priv->hscrollbar ?
593 gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar)) :
598 * gtk_scrolled_window_get_vadjustment:
599 * @scrolled_window: a #GtkScrolledWindow
601 * Returns the vertical scrollbar's adjustment, used to connect the
602 * vertical scrollbar to the child widget's vertical scroll functionality.
604 * Returns: (transfer none): the vertical #GtkAdjustment
607 gtk_scrolled_window_get_vadjustment (GtkScrolledWindow *scrolled_window)
609 GtkScrolledWindowPrivate *priv;
611 g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
613 priv = scrolled_window->priv;
615 return (priv->vscrollbar ?
616 gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar)) :
621 * gtk_scrolled_window_get_hscrollbar:
622 * @scrolled_window: a #GtkScrolledWindow
624 * Returns the horizontal scrollbar of @scrolled_window.
626 * Returns: (transfer none): the horizontal scrollbar of the scrolled window,
627 * or %NULL if it does not have one.
632 gtk_scrolled_window_get_hscrollbar (GtkScrolledWindow *scrolled_window)
634 g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
636 return scrolled_window->priv->hscrollbar;
640 * gtk_scrolled_window_get_vscrollbar:
641 * @scrolled_window: a #GtkScrolledWindow
643 * Returns the vertical scrollbar of @scrolled_window.
645 * Returns: (transfer none): the vertical scrollbar of the scrolled window,
646 * or %NULL if it does not have one.
651 gtk_scrolled_window_get_vscrollbar (GtkScrolledWindow *scrolled_window)
653 g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
655 return scrolled_window->priv->vscrollbar;
659 * gtk_scrolled_window_set_policy:
660 * @scrolled_window: a #GtkScrolledWindow
661 * @hscrollbar_policy: policy for horizontal bar
662 * @vscrollbar_policy: policy for vertical bar
664 * Sets the scrollbar policy for the horizontal and vertical scrollbars.
666 * The policy determines when the scrollbar should appear; it is a value
667 * from the #GtkPolicyType enumeration. If %GTK_POLICY_ALWAYS, the
668 * scrollbar is always present; if %GTK_POLICY_NEVER, the scrollbar is
669 * never present; if %GTK_POLICY_AUTOMATIC, the scrollbar is present only
670 * if needed (that is, if the slider part of the bar would be smaller
671 * than the trough - the display is larger than the page size).
674 gtk_scrolled_window_set_policy (GtkScrolledWindow *scrolled_window,
675 GtkPolicyType hscrollbar_policy,
676 GtkPolicyType vscrollbar_policy)
678 GtkScrolledWindowPrivate *priv;
679 GObject *object = G_OBJECT (scrolled_window);
681 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
683 priv = scrolled_window->priv;
685 if ((priv->hscrollbar_policy != hscrollbar_policy) ||
686 (priv->vscrollbar_policy != vscrollbar_policy))
688 priv->hscrollbar_policy = hscrollbar_policy;
689 priv->vscrollbar_policy = vscrollbar_policy;
691 gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
693 g_object_freeze_notify (object);
694 g_object_notify (object, "hscrollbar-policy");
695 g_object_notify (object, "vscrollbar-policy");
696 g_object_thaw_notify (object);
701 * gtk_scrolled_window_get_policy:
702 * @scrolled_window: a #GtkScrolledWindow
703 * @hscrollbar_policy: location to store the policy for the horizontal
704 * scrollbar, or %NULL.
705 * @vscrollbar_policy: location to store the policy for the vertical
706 * scrollbar, or %NULL.
708 * Retrieves the current policy values for the horizontal and vertical
709 * scrollbars. See gtk_scrolled_window_set_policy().
712 gtk_scrolled_window_get_policy (GtkScrolledWindow *scrolled_window,
713 GtkPolicyType *hscrollbar_policy,
714 GtkPolicyType *vscrollbar_policy)
716 GtkScrolledWindowPrivate *priv;
718 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
720 priv = scrolled_window->priv;
722 if (hscrollbar_policy)
723 *hscrollbar_policy = priv->hscrollbar_policy;
724 if (vscrollbar_policy)
725 *vscrollbar_policy = priv->vscrollbar_policy;
729 gtk_scrolled_window_update_real_placement (GtkScrolledWindow *scrolled_window)
731 GtkScrolledWindowPrivate *priv = scrolled_window->priv;
732 GtkSettings *settings;
734 settings = gtk_widget_get_settings (GTK_WIDGET (scrolled_window));
736 if (priv->window_placement_set || settings == NULL)
737 priv->real_window_placement = priv->window_placement;
739 g_object_get (settings,
740 "gtk-scrolled-window-placement",
741 &priv->real_window_placement,
746 gtk_scrolled_window_set_placement_internal (GtkScrolledWindow *scrolled_window,
747 GtkCornerType window_placement)
749 GtkScrolledWindowPrivate *priv = scrolled_window->priv;
751 if (priv->window_placement != window_placement)
753 priv->window_placement = window_placement;
755 gtk_scrolled_window_update_real_placement (scrolled_window);
756 gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
758 g_object_notify (G_OBJECT (scrolled_window), "window-placement");
763 gtk_scrolled_window_set_placement_set (GtkScrolledWindow *scrolled_window,
764 gboolean placement_set,
765 gboolean emit_resize)
767 GtkScrolledWindowPrivate *priv = scrolled_window->priv;
769 if (priv->window_placement_set != placement_set)
771 priv->window_placement_set = placement_set;
773 gtk_scrolled_window_update_real_placement (scrolled_window);
775 gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
777 g_object_notify (G_OBJECT (scrolled_window), "window-placement-set");
782 * gtk_scrolled_window_set_placement:
783 * @scrolled_window: a #GtkScrolledWindow
784 * @window_placement: position of the child window
786 * Sets the placement of the contents with respect to the scrollbars
787 * for the scrolled window.
789 * The default is %GTK_CORNER_TOP_LEFT, meaning the child is
790 * in the top left, with the scrollbars underneath and to the right.
791 * Other values in #GtkCornerType are %GTK_CORNER_TOP_RIGHT,
792 * %GTK_CORNER_BOTTOM_LEFT, and %GTK_CORNER_BOTTOM_RIGHT.
794 * See also gtk_scrolled_window_get_placement() and
795 * gtk_scrolled_window_unset_placement().
798 gtk_scrolled_window_set_placement (GtkScrolledWindow *scrolled_window,
799 GtkCornerType window_placement)
801 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
803 gtk_scrolled_window_set_placement_set (scrolled_window, TRUE, FALSE);
804 gtk_scrolled_window_set_placement_internal (scrolled_window, window_placement);
808 * gtk_scrolled_window_get_placement:
809 * @scrolled_window: a #GtkScrolledWindow
811 * Gets the placement of the contents with respect to the scrollbars
812 * for the scrolled window. See gtk_scrolled_window_set_placement().
814 * Return value: the current placement value.
816 * See also gtk_scrolled_window_set_placement() and
817 * gtk_scrolled_window_unset_placement().
820 gtk_scrolled_window_get_placement (GtkScrolledWindow *scrolled_window)
822 g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), GTK_CORNER_TOP_LEFT);
824 return scrolled_window->priv->window_placement;
828 * gtk_scrolled_window_unset_placement:
829 * @scrolled_window: a #GtkScrolledWindow
831 * Unsets the placement of the contents with respect to the scrollbars
832 * for the scrolled window. If no window placement is set for a scrolled
833 * window, it obeys the "gtk-scrolled-window-placement" XSETTING.
835 * See also gtk_scrolled_window_set_placement() and
836 * gtk_scrolled_window_get_placement().
841 gtk_scrolled_window_unset_placement (GtkScrolledWindow *scrolled_window)
843 GtkScrolledWindowPrivate *priv;
845 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
847 priv = scrolled_window->priv;
849 if (priv->window_placement_set)
851 priv->window_placement_set = FALSE;
853 gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
855 g_object_notify (G_OBJECT (scrolled_window), "window-placement-set");
860 * gtk_scrolled_window_set_shadow_type:
861 * @scrolled_window: a #GtkScrolledWindow
862 * @type: kind of shadow to draw around scrolled window contents
864 * Changes the type of shadow drawn around the contents of
869 gtk_scrolled_window_set_shadow_type (GtkScrolledWindow *scrolled_window,
872 GtkScrolledWindowPrivate *priv;
874 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
875 g_return_if_fail (type >= GTK_SHADOW_NONE && type <= GTK_SHADOW_ETCHED_OUT);
877 priv = scrolled_window->priv;
879 if (priv->shadow_type != type)
881 priv->shadow_type = type;
883 if (gtk_widget_is_drawable (GTK_WIDGET (scrolled_window)))
884 gtk_widget_queue_draw (GTK_WIDGET (scrolled_window));
886 gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
888 g_object_notify (G_OBJECT (scrolled_window), "shadow-type");
893 * gtk_scrolled_window_get_shadow_type:
894 * @scrolled_window: a #GtkScrolledWindow
896 * Gets the shadow type of the scrolled window. See
897 * gtk_scrolled_window_set_shadow_type().
899 * Return value: the current shadow type
902 gtk_scrolled_window_get_shadow_type (GtkScrolledWindow *scrolled_window)
904 g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_NONE);
906 return scrolled_window->priv->shadow_type;
910 gtk_scrolled_window_destroy (GtkWidget *widget)
912 GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
913 GtkScrolledWindowPrivate *priv = scrolled_window->priv;
915 if (priv->hscrollbar)
917 g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar)),
918 gtk_scrolled_window_adjustment_changed,
920 gtk_widget_unparent (priv->hscrollbar);
921 gtk_widget_destroy (priv->hscrollbar);
922 g_object_unref (priv->hscrollbar);
923 priv->hscrollbar = NULL;
925 if (priv->vscrollbar)
927 g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar)),
928 gtk_scrolled_window_adjustment_changed,
930 gtk_widget_unparent (priv->vscrollbar);
931 gtk_widget_destroy (priv->vscrollbar);
932 g_object_unref (priv->vscrollbar);
933 priv->vscrollbar = NULL;
936 GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->destroy (widget);
940 gtk_scrolled_window_set_property (GObject *object,
945 GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (object);
946 GtkScrolledWindowPrivate *priv = scrolled_window->priv;
950 case PROP_HADJUSTMENT:
951 gtk_scrolled_window_set_hadjustment (scrolled_window,
952 g_value_get_object (value));
954 case PROP_VADJUSTMENT:
955 gtk_scrolled_window_set_vadjustment (scrolled_window,
956 g_value_get_object (value));
958 case PROP_HSCROLLBAR_POLICY:
959 gtk_scrolled_window_set_policy (scrolled_window,
960 g_value_get_enum (value),
961 priv->vscrollbar_policy);
963 case PROP_VSCROLLBAR_POLICY:
964 gtk_scrolled_window_set_policy (scrolled_window,
965 priv->hscrollbar_policy,
966 g_value_get_enum (value));
968 case PROP_WINDOW_PLACEMENT:
969 gtk_scrolled_window_set_placement_internal (scrolled_window,
970 g_value_get_enum (value));
972 case PROP_WINDOW_PLACEMENT_SET:
973 gtk_scrolled_window_set_placement_set (scrolled_window,
974 g_value_get_boolean (value),
977 case PROP_SHADOW_TYPE:
978 gtk_scrolled_window_set_shadow_type (scrolled_window,
979 g_value_get_enum (value));
982 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
988 gtk_scrolled_window_get_property (GObject *object,
993 GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (object);
994 GtkScrolledWindowPrivate *priv = scrolled_window->priv;
998 case PROP_HADJUSTMENT:
999 g_value_set_object (value,
1000 G_OBJECT (gtk_scrolled_window_get_hadjustment (scrolled_window)));
1002 case PROP_VADJUSTMENT:
1003 g_value_set_object (value,
1004 G_OBJECT (gtk_scrolled_window_get_vadjustment (scrolled_window)));
1006 case PROP_HSCROLLBAR_POLICY:
1007 g_value_set_enum (value, priv->hscrollbar_policy);
1009 case PROP_VSCROLLBAR_POLICY:
1010 g_value_set_enum (value, priv->vscrollbar_policy);
1012 case PROP_WINDOW_PLACEMENT:
1013 g_value_set_enum (value, priv->window_placement);
1015 case PROP_WINDOW_PLACEMENT_SET:
1016 g_value_set_boolean (value, priv->window_placement_set);
1018 case PROP_SHADOW_TYPE:
1019 g_value_set_enum (value, priv->shadow_type);
1022 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1028 traverse_container (GtkWidget *widget,
1031 if (GTK_IS_SCROLLED_WINDOW (widget))
1033 gtk_scrolled_window_update_real_placement (GTK_SCROLLED_WINDOW (widget));
1034 gtk_widget_queue_resize (widget);
1036 else if (GTK_IS_CONTAINER (widget))
1037 gtk_container_forall (GTK_CONTAINER (widget), traverse_container, NULL);
1041 gtk_scrolled_window_settings_changed (GtkSettings *settings)
1045 list = gtk_window_list_toplevels ();
1047 for (l = list; l; l = l->next)
1048 gtk_container_forall (GTK_CONTAINER (l->data),
1049 traverse_container, NULL);
1055 gtk_scrolled_window_screen_changed (GtkWidget *widget,
1056 GdkScreen *previous_screen)
1058 GtkSettings *settings;
1059 guint window_placement_connection;
1061 gtk_scrolled_window_update_real_placement (GTK_SCROLLED_WINDOW (widget));
1063 if (!gtk_widget_has_screen (widget))
1066 settings = gtk_widget_get_settings (widget);
1068 window_placement_connection =
1069 GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (settings),
1070 "gtk-scrolled-window-connection"));
1072 if (window_placement_connection)
1075 window_placement_connection =
1076 g_signal_connect (settings, "notify::gtk-scrolled-window-placement",
1077 G_CALLBACK (gtk_scrolled_window_settings_changed), NULL);
1078 g_object_set_data (G_OBJECT (settings),
1079 I_("gtk-scrolled-window-connection"),
1080 GUINT_TO_POINTER (window_placement_connection));
1084 gtk_scrolled_window_draw (GtkWidget *widget,
1087 GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
1088 GtkScrolledWindowPrivate *priv = scrolled_window->priv;
1090 if (priv->shadow_type != GTK_SHADOW_NONE)
1092 GtkAllocation relative_allocation;
1094 gboolean scrollbars_within_bevel;
1096 style = gtk_widget_get_style (widget);
1097 gtk_widget_style_get (widget, "scrollbars-within-bevel", &scrollbars_within_bevel, NULL);
1099 if (!scrollbars_within_bevel)
1101 gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
1103 relative_allocation.x -= style->xthickness;
1104 relative_allocation.y -= style->ythickness;
1105 relative_allocation.width += 2 * style->xthickness;
1106 relative_allocation.height += 2 * style->ythickness;
1110 GtkContainer *container = GTK_CONTAINER (widget);
1113 border_width = gtk_container_get_border_width (container);
1115 relative_allocation.x = border_width;
1116 relative_allocation.y = border_width;
1117 relative_allocation.width = gtk_widget_get_allocated_width (widget) - 2 * border_width;
1118 relative_allocation.height = gtk_widget_get_allocated_height (widget) - 2 * border_width;
1121 gtk_paint_shadow (style,
1123 GTK_STATE_NORMAL, priv->shadow_type,
1124 widget, "scrolled_window",
1125 relative_allocation.x,
1126 relative_allocation.y,
1127 relative_allocation.width,
1128 relative_allocation.height);
1131 GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->draw (widget, cr);
1137 gtk_scrolled_window_forall (GtkContainer *container,
1138 gboolean include_internals,
1139 GtkCallback callback,
1140 gpointer callback_data)
1142 GtkScrolledWindowPrivate *priv;
1143 GtkScrolledWindow *scrolled_window;
1145 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container));
1146 g_return_if_fail (callback != NULL);
1148 GTK_CONTAINER_CLASS (gtk_scrolled_window_parent_class)->forall (container,
1152 if (include_internals)
1154 scrolled_window = GTK_SCROLLED_WINDOW (container);
1155 priv = scrolled_window->priv;
1157 if (priv->vscrollbar)
1158 callback (priv->vscrollbar, callback_data);
1159 if (priv->hscrollbar)
1160 callback (priv->hscrollbar, callback_data);
1165 gtk_scrolled_window_scroll_child (GtkScrolledWindow *scrolled_window,
1166 GtkScrollType scroll,
1167 gboolean horizontal)
1169 GtkScrolledWindowPrivate *priv = scrolled_window->priv;
1170 GtkAdjustment *adjustment = NULL;
1174 case GTK_SCROLL_STEP_UP:
1175 scroll = GTK_SCROLL_STEP_BACKWARD;
1178 case GTK_SCROLL_STEP_DOWN:
1179 scroll = GTK_SCROLL_STEP_FORWARD;
1182 case GTK_SCROLL_STEP_LEFT:
1183 scroll = GTK_SCROLL_STEP_BACKWARD;
1186 case GTK_SCROLL_STEP_RIGHT:
1187 scroll = GTK_SCROLL_STEP_FORWARD;
1190 case GTK_SCROLL_PAGE_UP:
1191 scroll = GTK_SCROLL_PAGE_BACKWARD;
1194 case GTK_SCROLL_PAGE_DOWN:
1195 scroll = GTK_SCROLL_PAGE_FORWARD;
1198 case GTK_SCROLL_PAGE_LEFT:
1199 scroll = GTK_SCROLL_STEP_BACKWARD;
1202 case GTK_SCROLL_PAGE_RIGHT:
1203 scroll = GTK_SCROLL_STEP_FORWARD;
1206 case GTK_SCROLL_STEP_BACKWARD:
1207 case GTK_SCROLL_STEP_FORWARD:
1208 case GTK_SCROLL_PAGE_BACKWARD:
1209 case GTK_SCROLL_PAGE_FORWARD:
1210 case GTK_SCROLL_START:
1211 case GTK_SCROLL_END:
1214 g_warning ("Invalid scroll type %u for GtkScrolledWindow::scroll-child", scroll);
1218 if ((horizontal && (!priv->hscrollbar || !priv->hscrollbar_visible)) ||
1219 (!horizontal && (!priv->vscrollbar || !priv->vscrollbar_visible)))
1224 if (priv->hscrollbar)
1225 adjustment = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar));
1229 if (priv->vscrollbar)
1230 adjustment = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar));
1235 gdouble value = adjustment->value;
1239 case GTK_SCROLL_STEP_FORWARD:
1240 value += adjustment->step_increment;
1242 case GTK_SCROLL_STEP_BACKWARD:
1243 value -= adjustment->step_increment;
1245 case GTK_SCROLL_PAGE_FORWARD:
1246 value += adjustment->page_increment;
1248 case GTK_SCROLL_PAGE_BACKWARD:
1249 value -= adjustment->page_increment;
1251 case GTK_SCROLL_START:
1252 value = adjustment->lower;
1254 case GTK_SCROLL_END:
1255 value = adjustment->upper;
1258 g_assert_not_reached ();
1262 gtk_adjustment_set_value (adjustment, value);
1271 gtk_scrolled_window_move_focus_out (GtkScrolledWindow *scrolled_window,
1272 GtkDirectionType direction_type)
1274 GtkScrolledWindowPrivate *priv = scrolled_window->priv;
1275 GtkWidget *toplevel;
1277 /* Focus out of the scrolled window entirely. We do this by setting
1278 * a flag, then propagating the focus motion to the notebook.
1280 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (scrolled_window));
1281 if (!gtk_widget_is_toplevel (toplevel))
1284 g_object_ref (scrolled_window);
1286 priv->focus_out = TRUE;
1287 g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1288 priv->focus_out = FALSE;
1290 g_object_unref (scrolled_window);
1294 gtk_scrolled_window_relative_allocation (GtkWidget *widget,
1295 GtkAllocation *allocation)
1297 GtkAllocation widget_allocation;
1298 GtkScrolledWindow *scrolled_window;
1299 GtkScrolledWindowPrivate *priv;
1301 gint scrollbar_spacing;
1304 g_return_if_fail (widget != NULL);
1305 g_return_if_fail (allocation != NULL);
1307 scrolled_window = GTK_SCROLLED_WINDOW (widget);
1308 priv = scrolled_window->priv;
1310 scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
1312 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
1313 allocation->x = border_width;
1314 allocation->y = border_width;
1316 if (priv->shadow_type != GTK_SHADOW_NONE)
1318 style = gtk_widget_get_style (widget);
1319 allocation->x += style->xthickness;
1320 allocation->y += style->ythickness;
1323 gtk_widget_get_allocation (widget, &widget_allocation);
1324 allocation->width = MAX (1, (gint) widget_allocation.width - allocation->x * 2);
1325 allocation->height = MAX (1, (gint) widget_allocation.height - allocation->y * 2);
1327 if (priv->vscrollbar_visible)
1329 GtkRequisition vscrollbar_requisition;
1332 gtk_widget_get_preferred_size (priv->vscrollbar,
1333 &vscrollbar_requisition, NULL);
1334 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1337 (priv->real_window_placement == GTK_CORNER_TOP_RIGHT ||
1338 priv->real_window_placement == GTK_CORNER_BOTTOM_RIGHT)) ||
1340 (priv->real_window_placement == GTK_CORNER_TOP_LEFT ||
1341 priv->real_window_placement == GTK_CORNER_BOTTOM_LEFT)))
1342 allocation->x += (vscrollbar_requisition.width + scrollbar_spacing);
1344 allocation->width = MAX (1, allocation->width - (vscrollbar_requisition.width + scrollbar_spacing));
1346 if (priv->hscrollbar_visible)
1348 GtkRequisition hscrollbar_requisition;
1350 gtk_widget_get_preferred_size (priv->hscrollbar,
1351 &hscrollbar_requisition, NULL);
1353 if (priv->real_window_placement == GTK_CORNER_BOTTOM_LEFT ||
1354 priv->real_window_placement == GTK_CORNER_BOTTOM_RIGHT)
1355 allocation->y += (hscrollbar_requisition.height + scrollbar_spacing);
1357 allocation->height = MAX (1, allocation->height - (hscrollbar_requisition.height + scrollbar_spacing));
1362 gtk_scrolled_window_size_allocate (GtkWidget *widget,
1363 GtkAllocation *allocation)
1365 GtkScrolledWindow *scrolled_window;
1366 GtkScrolledWindowPrivate *priv;
1369 GtkAllocation relative_allocation;
1370 GtkAllocation child_allocation;
1372 gboolean scrollbars_within_bevel;
1373 gint scrollbar_spacing;
1376 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
1377 g_return_if_fail (allocation != NULL);
1379 scrolled_window = GTK_SCROLLED_WINDOW (widget);
1380 bin = GTK_BIN (scrolled_window);
1381 priv = scrolled_window->priv;
1383 scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
1385 style = gtk_widget_get_style (widget);
1386 gtk_widget_style_get (widget, "scrollbars-within-bevel", &scrollbars_within_bevel, NULL);
1388 border_width = gtk_container_get_border_width (GTK_CONTAINER (scrolled_window));
1390 gtk_widget_set_allocation (widget, allocation);
1392 if (priv->hscrollbar_policy == GTK_POLICY_ALWAYS)
1393 priv->hscrollbar_visible = TRUE;
1394 else if (priv->hscrollbar_policy == GTK_POLICY_NEVER)
1395 priv->hscrollbar_visible = FALSE;
1396 if (priv->vscrollbar_policy == GTK_POLICY_ALWAYS)
1397 priv->vscrollbar_visible = TRUE;
1398 else if (priv->vscrollbar_policy == GTK_POLICY_NEVER)
1399 priv->vscrollbar_visible = FALSE;
1401 child = gtk_bin_get_child (bin);
1402 if (child && gtk_widget_get_visible (child))
1404 gboolean previous_hvis;
1405 gboolean previous_vvis;
1410 gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
1412 child_allocation.x = relative_allocation.x + allocation->x;
1413 child_allocation.y = relative_allocation.y + allocation->y;
1414 child_allocation.width = relative_allocation.width;
1415 child_allocation.height = relative_allocation.height;
1417 previous_hvis = priv->hscrollbar_visible;
1418 previous_vvis = priv->vscrollbar_visible;
1420 gtk_widget_size_allocate (child, &child_allocation);
1422 /* If, after the first iteration, the hscrollbar and the
1423 * vscrollbar flip visiblity, then we need both.
1426 previous_hvis != priv->hscrollbar_visible &&
1427 previous_vvis != priv->vscrollbar_visible)
1429 priv->hscrollbar_visible = TRUE;
1430 priv->vscrollbar_visible = TRUE;
1432 /* a new resize is already queued at this point,
1433 * so we will immediatedly get reinvoked
1440 while (previous_hvis != priv->hscrollbar_visible ||
1441 previous_vvis != priv->vscrollbar_visible);
1445 priv->hscrollbar_visible = priv->hscrollbar_policy == GTK_POLICY_ALWAYS;
1446 priv->vscrollbar_visible = priv->vscrollbar_policy == GTK_POLICY_ALWAYS;
1447 gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
1450 if (priv->hscrollbar_visible)
1452 GtkRequisition hscrollbar_requisition;
1454 gtk_widget_get_preferred_size (priv->hscrollbar,
1455 &hscrollbar_requisition, NULL);
1457 if (!gtk_widget_get_visible (priv->hscrollbar))
1458 gtk_widget_show (priv->hscrollbar);
1460 child_allocation.x = relative_allocation.x;
1461 if (priv->real_window_placement == GTK_CORNER_TOP_LEFT ||
1462 priv->real_window_placement == GTK_CORNER_TOP_RIGHT)
1463 child_allocation.y = (relative_allocation.y +
1464 relative_allocation.height +
1466 (priv->shadow_type == GTK_SHADOW_NONE ?
1467 0 : style->ythickness));
1469 child_allocation.y = border_width;
1471 child_allocation.width = relative_allocation.width;
1472 child_allocation.height = hscrollbar_requisition.height;
1473 child_allocation.x += allocation->x;
1474 child_allocation.y += allocation->y;
1476 if (priv->shadow_type != GTK_SHADOW_NONE)
1478 if (!scrollbars_within_bevel)
1480 child_allocation.x -= style->xthickness;
1481 child_allocation.width += 2 * style->xthickness;
1483 else if (GTK_CORNER_TOP_RIGHT == priv->real_window_placement ||
1484 GTK_CORNER_TOP_LEFT == priv->real_window_placement)
1486 child_allocation.y -= style->ythickness;
1490 child_allocation.y += style->ythickness;
1494 gtk_widget_size_allocate (priv->hscrollbar, &child_allocation);
1496 else if (gtk_widget_get_visible (priv->hscrollbar))
1497 gtk_widget_hide (priv->hscrollbar);
1499 if (priv->vscrollbar_visible)
1501 GtkRequisition vscrollbar_requisition;
1502 if (!gtk_widget_get_visible (priv->vscrollbar))
1503 gtk_widget_show (priv->vscrollbar);
1505 gtk_widget_get_preferred_size (priv->vscrollbar,
1506 &vscrollbar_requisition, NULL);
1508 if ((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL &&
1509 (priv->real_window_placement == GTK_CORNER_TOP_RIGHT ||
1510 priv->real_window_placement == GTK_CORNER_BOTTOM_RIGHT)) ||
1511 (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR &&
1512 (priv->real_window_placement == GTK_CORNER_TOP_LEFT ||
1513 priv->real_window_placement == GTK_CORNER_BOTTOM_LEFT)))
1514 child_allocation.x = (relative_allocation.x +
1515 relative_allocation.width +
1517 (priv->shadow_type == GTK_SHADOW_NONE ?
1518 0 : style->xthickness));
1520 child_allocation.x = border_width;
1522 child_allocation.y = relative_allocation.y;
1523 child_allocation.width = vscrollbar_requisition.width;
1524 child_allocation.height = relative_allocation.height;
1525 child_allocation.x += allocation->x;
1526 child_allocation.y += allocation->y;
1528 if (priv->shadow_type != GTK_SHADOW_NONE)
1530 if (!scrollbars_within_bevel)
1532 child_allocation.y -= style->ythickness;
1533 child_allocation.height += 2 * style->ythickness;
1535 else if (GTK_CORNER_BOTTOM_LEFT == priv->real_window_placement ||
1536 GTK_CORNER_TOP_LEFT == priv->real_window_placement)
1538 child_allocation.x -= style->xthickness;
1542 child_allocation.x += style->xthickness;
1546 gtk_widget_size_allocate (priv->vscrollbar, &child_allocation);
1548 else if (gtk_widget_get_visible (priv->vscrollbar))
1549 gtk_widget_hide (priv->vscrollbar);
1553 gtk_scrolled_window_scroll_event (GtkWidget *widget,
1554 GdkEventScroll *event)
1556 GtkScrolledWindowPrivate *priv;
1557 GtkScrolledWindow *scrolled_window;
1560 g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (widget), FALSE);
1561 g_return_val_if_fail (event != NULL, FALSE);
1563 scrolled_window = GTK_SCROLLED_WINDOW (widget);
1564 priv = scrolled_window->priv;
1566 if (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_DOWN)
1567 range = priv->vscrollbar;
1569 range = priv->hscrollbar;
1571 if (range && gtk_widget_get_visible (range))
1573 GtkAdjustment *adj = gtk_range_get_adjustment (GTK_RANGE (range));
1576 delta = _gtk_range_get_wheel_delta (GTK_RANGE (range), event->direction);
1578 gtk_adjustment_set_value (adj, adj->value + delta);
1587 gtk_scrolled_window_focus (GtkWidget *widget,
1588 GtkDirectionType direction)
1590 GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
1591 GtkScrolledWindowPrivate *priv = scrolled_window->priv;
1593 gboolean had_focus_child;
1595 had_focus_child = gtk_container_get_focus_child (GTK_CONTAINER (widget)) != NULL;
1597 if (priv->focus_out)
1599 priv->focus_out = FALSE; /* Clear this to catch the wrap-around case */
1603 if (gtk_widget_is_focus (widget))
1606 /* We only put the scrolled window itself in the focus chain if it
1607 * isn't possible to focus any children.
1609 child = gtk_bin_get_child (GTK_BIN (widget));
1612 if (gtk_widget_child_focus (child, direction))
1616 if (!had_focus_child && gtk_widget_get_can_focus (widget))
1618 gtk_widget_grab_focus (widget);
1626 gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment,
1629 GtkScrolledWindowPrivate *priv;;
1630 GtkScrolledWindow *scrolled_window;
1632 g_return_if_fail (adjustment != NULL);
1633 g_return_if_fail (data != NULL);
1635 scrolled_window = GTK_SCROLLED_WINDOW (data);
1636 priv = scrolled_window->priv;
1638 if (priv->hscrollbar &&
1639 adjustment == gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar)))
1641 if (priv->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
1645 visible = priv->hscrollbar_visible;
1646 priv->hscrollbar_visible = (adjustment->upper - adjustment->lower >
1647 adjustment->page_size);
1648 if (priv->hscrollbar_visible != visible)
1649 gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
1652 else if (priv->vscrollbar &&
1653 adjustment == gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar)))
1655 if (priv->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
1659 visible = priv->vscrollbar_visible;
1660 priv->vscrollbar_visible = (adjustment->upper - adjustment->lower >
1661 adjustment->page_size);
1662 if (priv->vscrollbar_visible != visible)
1663 gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
1669 gtk_scrolled_window_add (GtkContainer *container,
1672 GtkScrolledWindowPrivate *priv;
1673 GtkScrolledWindow *scrolled_window;
1675 GtkWidget *child_widget;
1677 bin = GTK_BIN (container);
1678 child_widget = gtk_bin_get_child (bin);
1679 g_return_if_fail (child_widget == NULL);
1681 scrolled_window = GTK_SCROLLED_WINDOW (container);
1682 priv = scrolled_window->priv;
1684 _gtk_bin_set_child (bin, child);
1685 gtk_widget_set_parent (child, GTK_WIDGET (bin));
1687 /* this is a temporary message */
1688 if (!gtk_widget_set_scroll_adjustments (child,
1689 gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar)),
1690 gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar))))
1691 g_warning ("gtk_scrolled_window_add(): cannot add non scrollable widget "
1692 "use gtk_scrolled_window_add_with_viewport() instead");
1696 gtk_scrolled_window_remove (GtkContainer *container,
1699 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container));
1700 g_return_if_fail (child != NULL);
1701 g_return_if_fail (gtk_bin_get_child (GTK_BIN (container)) == child);
1703 gtk_widget_set_scroll_adjustments (child, NULL, NULL);
1705 /* chain parent class handler to remove child */
1706 GTK_CONTAINER_CLASS (gtk_scrolled_window_parent_class)->remove (container, child);
1710 * gtk_scrolled_window_add_with_viewport:
1711 * @scrolled_window: a #GtkScrolledWindow
1712 * @child: the widget you want to scroll
1714 * Used to add children without native scrolling capabilities. This
1715 * is simply a convenience function; it is equivalent to adding the
1716 * unscrollable child to a viewport, then adding the viewport to the
1717 * scrolled window. If a child has native scrolling, use
1718 * gtk_container_add() instead of this function.
1720 * The viewport scrolls the child by moving its #GdkWindow, and takes
1721 * the size of the child to be the size of its toplevel #GdkWindow.
1722 * This will be very wrong for most widgets that support native scrolling;
1723 * for example, if you add a widget such as #GtkTreeView with a viewport,
1724 * the whole widget will scroll, including the column headings. Thus,
1725 * widgets with native scrolling support should not be used with the
1726 * #GtkViewport proxy.
1728 * A widget supports scrolling natively if the
1729 * set_scroll_adjustments_signal field in #GtkWidgetClass is non-zero,
1730 * i.e. has been filled in with a valid signal identifier.
1733 gtk_scrolled_window_add_with_viewport (GtkScrolledWindow *scrolled_window,
1737 GtkWidget *viewport;
1738 GtkWidget *child_widget;
1740 g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
1741 g_return_if_fail (GTK_IS_WIDGET (child));
1742 g_return_if_fail (gtk_widget_get_parent (child) == NULL);
1744 bin = GTK_BIN (scrolled_window);
1745 child_widget = gtk_bin_get_child (bin);
1749 g_return_if_fail (GTK_IS_VIEWPORT (child_widget));
1750 g_return_if_fail (gtk_bin_get_child (GTK_BIN (child_widget)) == NULL);
1752 viewport = child_widget;
1757 gtk_viewport_new (gtk_scrolled_window_get_hadjustment (scrolled_window),
1758 gtk_scrolled_window_get_vadjustment (scrolled_window));
1759 gtk_container_add (GTK_CONTAINER (scrolled_window), viewport);
1762 gtk_widget_show (viewport);
1763 gtk_container_add (GTK_CONTAINER (viewport), child);
1767 * _gtk_scrolled_window_get_spacing:
1768 * @scrolled_window: a scrolled window
1770 * Gets the spacing between the scrolled window's scrollbars and
1771 * the scrolled widget. Used by GtkCombo
1773 * Return value: the spacing, in pixels.
1776 _gtk_scrolled_window_get_scrollbar_spacing (GtkScrolledWindow *scrolled_window)
1778 GtkScrolledWindowClass *class;
1780 g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), 0);
1782 class = GTK_SCROLLED_WINDOW_GET_CLASS (scrolled_window);
1784 if (class->scrollbar_spacing >= 0)
1785 return class->scrollbar_spacing;
1788 gint scrollbar_spacing;
1790 gtk_widget_style_get (GTK_WIDGET (scrolled_window),
1791 "scrollbar-spacing", &scrollbar_spacing,
1794 return scrollbar_spacing;
1800 gtk_scrolled_window_get_preferred_size (GtkWidget *widget,
1801 GtkOrientation orientation,
1805 GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
1806 GtkScrolledWindowPrivate *priv = scrolled_window->priv;
1807 GtkBin *bin = GTK_BIN (scrolled_window);
1810 gint scrollbar_spacing;
1811 GtkRequisition hscrollbar_requisition;
1812 GtkRequisition vscrollbar_requisition;
1813 GtkRequisition minimum_req, natural_req;
1816 gint min_child_size, nat_child_size;
1819 scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
1823 minimum_req.width = 0;
1824 minimum_req.height = 0;
1825 natural_req.width = 0;
1826 natural_req.height = 0;
1828 gtk_widget_get_preferred_size (priv->hscrollbar,
1829 &hscrollbar_requisition, NULL);
1830 gtk_widget_get_preferred_size (priv->vscrollbar,
1831 &vscrollbar_requisition, NULL);
1833 child = gtk_bin_get_child (bin);
1834 if (child && gtk_widget_get_visible (child))
1836 if (orientation == GTK_ORIENTATION_HORIZONTAL)
1838 gtk_widget_get_preferred_width (child,
1842 if (priv->hscrollbar_policy == GTK_POLICY_NEVER)
1844 minimum_req.width += min_child_size;
1845 natural_req.width += nat_child_size;
1849 GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (child, FALSE);
1851 if (aux_info && aux_info->width > 0)
1853 minimum_req.width += aux_info->width;
1854 natural_req.width += aux_info->width;
1859 minimum_req.width += vscrollbar_requisition.width;
1860 natural_req.width += vscrollbar_requisition.width;
1864 else /* GTK_ORIENTATION_VERTICAL */
1866 gtk_widget_get_preferred_height (child,
1870 if (priv->vscrollbar_policy == GTK_POLICY_NEVER)
1872 minimum_req.height += min_child_size;
1873 natural_req.height += nat_child_size;
1877 GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (child, FALSE);
1879 if (aux_info && aux_info->height > 0)
1881 minimum_req.height += aux_info->height;
1882 natural_req.height += aux_info->height;
1887 minimum_req.height += hscrollbar_requisition.height;
1888 natural_req.height += hscrollbar_requisition.height;
1894 if (priv->hscrollbar_policy == GTK_POLICY_AUTOMATIC ||
1895 priv->hscrollbar_policy == GTK_POLICY_ALWAYS)
1897 minimum_req.width = MAX (minimum_req.width, hscrollbar_requisition.width);
1898 natural_req.width = MAX (natural_req.width, hscrollbar_requisition.width);
1899 if (!extra_height || priv->hscrollbar_policy == GTK_POLICY_ALWAYS)
1900 extra_height = scrollbar_spacing + hscrollbar_requisition.height;
1903 if (priv->vscrollbar_policy == GTK_POLICY_AUTOMATIC ||
1904 priv->vscrollbar_policy == GTK_POLICY_ALWAYS)
1906 minimum_req.height = MAX (minimum_req.height, vscrollbar_requisition.height);
1907 natural_req.height = MAX (natural_req.height, vscrollbar_requisition.height);
1908 if (!extra_height || priv->vscrollbar_policy == GTK_POLICY_ALWAYS)
1909 extra_width = scrollbar_spacing + vscrollbar_requisition.width;
1912 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
1913 minimum_req.width += border_width * 2 + MAX (0, extra_width);
1914 minimum_req.height += border_width * 2 + MAX (0, extra_height);
1915 natural_req.width += border_width * 2 + MAX (0, extra_width);
1916 natural_req.height += border_width * 2 + MAX (0, extra_height);
1918 if (priv->shadow_type != GTK_SHADOW_NONE)
1920 style = gtk_widget_get_style (GTK_WIDGET (widget));
1921 minimum_req.width += 2 * style->xthickness;
1922 minimum_req.height += 2 * style->ythickness;
1923 natural_req.width += 2 * style->xthickness;
1924 natural_req.height += 2 * style->ythickness;
1927 if (orientation == GTK_ORIENTATION_HORIZONTAL)
1930 *minimum_size = minimum_req.width;
1932 *natural_size = natural_req.width;
1937 *minimum_size = minimum_req.height;
1939 *natural_size = natural_req.height;
1944 gtk_scrolled_window_get_preferred_width (GtkWidget *widget,
1948 gtk_scrolled_window_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size);
1952 gtk_scrolled_window_get_preferred_height (GtkWidget *widget,
1956 gtk_scrolled_window_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size);
1960 gtk_scrolled_window_get_preferred_height_for_width (GtkWidget *widget,
1962 gint *minimum_height,
1963 gint *natural_height)
1965 g_return_if_fail (GTK_IS_WIDGET (widget));
1967 GTK_WIDGET_GET_CLASS (widget)->get_preferred_height (widget, minimum_height, natural_height);
1971 gtk_scrolled_window_get_preferred_width_for_height (GtkWidget *widget,
1973 gint *minimum_width,
1974 gint *natural_width)
1976 g_return_if_fail (GTK_IS_WIDGET (widget));
1978 GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, minimum_width, natural_width);