X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkscrolledwindow.c;h=cc78baaa651e155d26b293522da20705610a6e3e;hb=73b15ba391b3a533786e2a2f4f80274b80866822;hp=674ebc9bfd000e6467845ab60fc32bc93a0ad11c;hpb=4e2b60ac4d32c5bef5b192a12a59f8c2a3124f81;p=~andy%2Fgtk diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c index 674ebc9bf..cc78baaa6 100644 --- a/gtk/gtkscrolledwindow.c +++ b/gtk/gtkscrolledwindow.c @@ -24,8 +24,11 @@ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ +#include +#include "gtkbindings.h" +#include "gtkmarshalers.h" #include "gtkscrolledwindow.h" -#include "gtksignal.h" +#include "gtkintl.h" /* scrolled window policy and size requisition handling: @@ -63,33 +66,40 @@ * under A) at least correspond to the space taken up by its scrollbars. */ -#define SCROLLBAR_SPACING(w) (GTK_SCROLLED_WINDOW_GET_CLASS (w)->scrollbar_spacing) - #define DEFAULT_SCROLLBAR_SPACING 3 enum { - ARG_0, - ARG_HADJUSTMENT, - ARG_VADJUSTMENT, - ARG_HSCROLLBAR_POLICY, - ARG_VSCROLLBAR_POLICY, - ARG_WINDOW_PLACEMENT, - ARG_SHADOW + PROP_0, + PROP_HADJUSTMENT, + PROP_VADJUSTMENT, + PROP_HSCROLLBAR_POLICY, + PROP_VSCROLLBAR_POLICY, + PROP_WINDOW_PLACEMENT, + PROP_SHADOW_TYPE, + PROP_LAST }; +/* Signals */ +enum +{ + SCROLL_CHILD, + MOVE_FOCUS_OUT, + LAST_SIGNAL +}; static void gtk_scrolled_window_class_init (GtkScrolledWindowClass *klass); static void gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window); -static void gtk_scrolled_window_set_arg (GtkObject *object, - GtkArg *arg, - guint arg_id); -static void gtk_scrolled_window_get_arg (GtkObject *object, - GtkArg *arg, - guint arg_id); static void gtk_scrolled_window_destroy (GtkObject *object); static void gtk_scrolled_window_finalize (GObject *object); -static void gtk_scrolled_window_map (GtkWidget *widget); -static void gtk_scrolled_window_unmap (GtkWidget *widget); +static void gtk_scrolled_window_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void gtk_scrolled_window_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + static gint gtk_scrolled_window_expose (GtkWidget *widget, GdkEventExpose *event); static void gtk_scrolled_window_size_request (GtkWidget *widget, @@ -98,6 +108,8 @@ static void gtk_scrolled_window_size_allocate (GtkWidget *widg GtkAllocation *allocation); static gint gtk_scrolled_window_scroll_event (GtkWidget *widget, GdkEventScroll *event); +static gint gtk_scrolled_window_focus (GtkWidget *widget, + GtkDirectionType direction); static void gtk_scrolled_window_add (GtkContainer *container, GtkWidget *widget); static void gtk_scrolled_window_remove (GtkContainer *container, @@ -106,6 +118,12 @@ static void gtk_scrolled_window_forall (GtkContainer *cont gboolean include_internals, GtkCallback callback, gpointer callback_data); +static void gtk_scrolled_window_scroll_child (GtkScrolledWindow *scrolled_window, + GtkScrollType scroll, + gboolean horizontal); +static void gtk_scrolled_window_move_focus_out (GtkScrolledWindow *scrolled_window, + GtkDirectionType direction_type); + static void gtk_scrolled_window_relative_allocation(GtkWidget *widget, GtkAllocation *allocation); static void gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment, @@ -113,32 +131,68 @@ static void gtk_scrolled_window_adjustment_changed (GtkAdjustment *adju static GtkContainerClass *parent_class = NULL; +static guint signals[LAST_SIGNAL] = {0}; -GtkType +GType gtk_scrolled_window_get_type (void) { - static GtkType scrolled_window_type = 0; + static GType scrolled_window_type = 0; if (!scrolled_window_type) { - static const GtkTypeInfo scrolled_window_info = + static const GTypeInfo scrolled_window_info = { - "GtkScrolledWindow", - sizeof (GtkScrolledWindow), sizeof (GtkScrolledWindowClass), - (GtkClassInitFunc) gtk_scrolled_window_class_init, - (GtkObjectInitFunc) gtk_scrolled_window_init, - /* reserved_1 */ NULL, - /* reserved_2 */ NULL, - (GtkClassInitFunc) NULL, + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) gtk_scrolled_window_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (GtkScrolledWindow), + 0, /* n_preallocs */ + (GInstanceInitFunc) gtk_scrolled_window_init, }; - scrolled_window_type = gtk_type_unique (GTK_TYPE_BIN, &scrolled_window_info); + scrolled_window_type = + g_type_register_static (GTK_TYPE_BIN, "GtkScrolledWindow", + &scrolled_window_info, 0); } return scrolled_window_type; } +static void +add_scroll_binding (GtkBindingSet *binding_set, + guint keyval, + GdkModifierType mask, + GtkScrollType scroll, + gboolean horizontal) +{ + guint keypad_keyval = keyval - GDK_Left + GDK_KP_Left; + + gtk_binding_entry_add_signal (binding_set, keyval, mask, + "scroll_child", 2, + GTK_TYPE_SCROLL_TYPE, scroll, + G_TYPE_BOOLEAN, horizontal); + gtk_binding_entry_add_signal (binding_set, keypad_keyval, mask, + "scroll_child", 2, + GTK_TYPE_SCROLL_TYPE, scroll, + G_TYPE_BOOLEAN, horizontal); +} + +static void +add_tab_bindings (GtkBindingSet *binding_set, + GdkModifierType modifiers, + GtkDirectionType direction) +{ + gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers, + "move_focus_out", 1, + GTK_TYPE_DIRECTION_TYPE, direction); + gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers, + "move_focus_out", 1, + GTK_TYPE_DIRECTION_TYPE, direction); +} + static void gtk_scrolled_window_class_init (GtkScrolledWindowClass *class) { @@ -146,138 +200,137 @@ gtk_scrolled_window_class_init (GtkScrolledWindowClass *class) GtkObjectClass *object_class; GtkWidgetClass *widget_class; GtkContainerClass *container_class; + GtkBindingSet *binding_set; object_class = (GtkObjectClass*) class; widget_class = (GtkWidgetClass*) class; container_class = (GtkContainerClass*) class; - parent_class = gtk_type_class (GTK_TYPE_BIN); + + parent_class = g_type_class_peek_parent (class); gobject_class->finalize = gtk_scrolled_window_finalize; + gobject_class->set_property = gtk_scrolled_window_set_property; + gobject_class->get_property = gtk_scrolled_window_get_property; - object_class->set_arg = gtk_scrolled_window_set_arg; - object_class->get_arg = gtk_scrolled_window_get_arg; object_class->destroy = gtk_scrolled_window_destroy; - widget_class->map = gtk_scrolled_window_map; - widget_class->unmap = gtk_scrolled_window_unmap; widget_class->expose_event = gtk_scrolled_window_expose; widget_class->size_request = gtk_scrolled_window_size_request; widget_class->size_allocate = gtk_scrolled_window_size_allocate; widget_class->scroll_event = gtk_scrolled_window_scroll_event; + widget_class->focus = gtk_scrolled_window_focus; container_class->add = gtk_scrolled_window_add; container_class->remove = gtk_scrolled_window_remove; container_class->forall = gtk_scrolled_window_forall; - class->scrollbar_spacing = DEFAULT_SCROLLBAR_SPACING; - - gtk_object_add_arg_type ("GtkScrolledWindow::hadjustment", - GTK_TYPE_ADJUSTMENT, - GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT, - ARG_HADJUSTMENT); - gtk_object_add_arg_type ("GtkScrolledWindow::vadjustment", - GTK_TYPE_ADJUSTMENT, - GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT, - ARG_VADJUSTMENT); - gtk_object_add_arg_type ("GtkScrolledWindow::hscrollbar_policy", - GTK_TYPE_POLICY_TYPE, - GTK_ARG_READWRITE, - ARG_HSCROLLBAR_POLICY); - gtk_object_add_arg_type ("GtkScrolledWindow::vscrollbar_policy", - GTK_TYPE_POLICY_TYPE, - GTK_ARG_READWRITE, - ARG_VSCROLLBAR_POLICY); - gtk_object_add_arg_type ("GtkScrolledWindow::window_placement", - GTK_TYPE_CORNER_TYPE, - GTK_ARG_READWRITE, - ARG_WINDOW_PLACEMENT); - gtk_object_add_arg_type ("GtkScrolledWindow::shadow", - GTK_TYPE_SHADOW_TYPE, - GTK_ARG_READWRITE, - ARG_SHADOW); -} + class->scrollbar_spacing = -1; -static void -gtk_scrolled_window_set_arg (GtkObject *object, - GtkArg *arg, - guint arg_id) -{ - GtkScrolledWindow *scrolled_window; - - scrolled_window = GTK_SCROLLED_WINDOW (object); + class->scroll_child = gtk_scrolled_window_scroll_child; + class->move_focus_out = gtk_scrolled_window_move_focus_out; + + g_object_class_install_property (gobject_class, + PROP_HADJUSTMENT, + g_param_spec_object ("hadjustment", + _("Horizontal Adjustment"), + _("The GtkAdjustment for the horizontal position"), + GTK_TYPE_ADJUSTMENT, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + g_object_class_install_property (gobject_class, + PROP_VADJUSTMENT, + g_param_spec_object ("vadjustment", + _("Vertical Adjustment"), + _("The GtkAdjustment for the vertical position"), + GTK_TYPE_ADJUSTMENT, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + g_object_class_install_property (gobject_class, + PROP_HSCROLLBAR_POLICY, + g_param_spec_enum ("hscrollbar_policy", + _("Horizontal Scrollbar Policy"), + _("When the horizontal scrollbar is displayed"), + GTK_TYPE_POLICY_TYPE, + GTK_POLICY_ALWAYS, + G_PARAM_READABLE | G_PARAM_WRITABLE)); + g_object_class_install_property (gobject_class, + PROP_VSCROLLBAR_POLICY, + g_param_spec_enum ("vscrollbar_policy", + _("Vertical Scrollbar Policy"), + _("When the vertical scrollbar is displayed"), + GTK_TYPE_POLICY_TYPE, + GTK_POLICY_ALWAYS, + G_PARAM_READABLE | G_PARAM_WRITABLE)); + + g_object_class_install_property (gobject_class, + PROP_WINDOW_PLACEMENT, + g_param_spec_enum ("window_placement", + _("Window Placement"), + _("Where the contents are located with respect to the scrollbars"), + GTK_TYPE_CORNER_TYPE, + GTK_CORNER_TOP_LEFT, + G_PARAM_READABLE | G_PARAM_WRITABLE)); + g_object_class_install_property (gobject_class, + PROP_SHADOW_TYPE, + g_param_spec_enum ("shadow_type", + _("Shadow Type"), + _("Style of bevel around the contents"), + GTK_TYPE_SHADOW_TYPE, + GTK_SHADOW_NONE, + G_PARAM_READABLE | G_PARAM_WRITABLE)); + + gtk_widget_class_install_style_property (widget_class, + g_param_spec_int ("scrollbar_spacing", + _("Scrollbar spacing"), + _("Number of pixels between the scrollbars and the scrolled window"), + 0, + G_MAXINT, + DEFAULT_SCROLLBAR_SPACING, + G_PARAM_READABLE)); + + signals[SCROLL_CHILD] = + g_signal_new ("scroll_child", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GtkScrolledWindowClass, scroll_child), + NULL, NULL, + _gtk_marshal_VOID__ENUM_BOOLEAN, + G_TYPE_NONE, 2, + GTK_TYPE_SCROLL_TYPE, + G_TYPE_BOOLEAN); + signals[MOVE_FOCUS_OUT] = + g_signal_new ("move_focus_out", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GtkScrolledWindowClass, move_focus_out), + NULL, NULL, + _gtk_marshal_VOID__ENUM, + G_TYPE_NONE, 1, + GTK_TYPE_DIRECTION_TYPE); + + binding_set = gtk_binding_set_by_class (class); - switch (arg_id) - { - case ARG_HADJUSTMENT: - gtk_scrolled_window_set_hadjustment (scrolled_window, GTK_VALUE_POINTER (*arg)); - break; - case ARG_VADJUSTMENT: - gtk_scrolled_window_set_vadjustment (scrolled_window, GTK_VALUE_POINTER (*arg)); - break; - case ARG_HSCROLLBAR_POLICY: - gtk_scrolled_window_set_policy (scrolled_window, - GTK_VALUE_ENUM (*arg), - scrolled_window->vscrollbar_policy); - break; - case ARG_VSCROLLBAR_POLICY: - gtk_scrolled_window_set_policy (scrolled_window, - scrolled_window->hscrollbar_policy, - GTK_VALUE_ENUM (*arg)); - break; - case ARG_WINDOW_PLACEMENT: - gtk_scrolled_window_set_placement (scrolled_window, - GTK_VALUE_ENUM (*arg)); - break; - case ARG_SHADOW: - gtk_scrolled_window_set_shadow_type (scrolled_window, - GTK_VALUE_ENUM (*arg)); - break; - default: - break; - } -} + add_scroll_binding (binding_set, GDK_Left, GDK_CONTROL_MASK, GTK_SCROLL_STEP_BACKWARD, TRUE); + add_scroll_binding (binding_set, GDK_Right, GDK_CONTROL_MASK, GTK_SCROLL_STEP_FORWARD, TRUE); + add_scroll_binding (binding_set, GDK_Up, GDK_CONTROL_MASK, GTK_SCROLL_STEP_BACKWARD, FALSE); + add_scroll_binding (binding_set, GDK_Down, GDK_CONTROL_MASK, GTK_SCROLL_STEP_FORWARD, FALSE); -static void -gtk_scrolled_window_get_arg (GtkObject *object, - GtkArg *arg, - guint arg_id) -{ - GtkScrolledWindow *scrolled_window; + add_scroll_binding (binding_set, GDK_Page_Up, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_BACKWARD, TRUE); + add_scroll_binding (binding_set, GDK_Page_Down, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_FORWARD, TRUE); + add_scroll_binding (binding_set, GDK_Page_Up, 0, GTK_SCROLL_PAGE_BACKWARD, FALSE); + add_scroll_binding (binding_set, GDK_Page_Down, 0, GTK_SCROLL_PAGE_FORWARD, FALSE); - scrolled_window = GTK_SCROLLED_WINDOW (object); + add_scroll_binding (binding_set, GDK_Home, GDK_CONTROL_MASK, GTK_SCROLL_START, TRUE); + add_scroll_binding (binding_set, GDK_End, GDK_CONTROL_MASK, GTK_SCROLL_END, TRUE); + add_scroll_binding (binding_set, GDK_Home, 0, GTK_SCROLL_START, FALSE); + add_scroll_binding (binding_set, GDK_End, 0, GTK_SCROLL_END, FALSE); - switch (arg_id) - { - case ARG_HADJUSTMENT: - GTK_VALUE_POINTER (*arg) = gtk_scrolled_window_get_hadjustment (scrolled_window); - break; - case ARG_VADJUSTMENT: - GTK_VALUE_POINTER (*arg) = gtk_scrolled_window_get_vadjustment (scrolled_window); - break; - case ARG_HSCROLLBAR_POLICY: - GTK_VALUE_ENUM (*arg) = scrolled_window->hscrollbar_policy; - break; - case ARG_VSCROLLBAR_POLICY: - GTK_VALUE_ENUM (*arg) = scrolled_window->vscrollbar_policy; - break; - case ARG_WINDOW_PLACEMENT: - GTK_VALUE_ENUM (*arg) = scrolled_window->window_placement; - break; - case ARG_SHADOW: - GTK_VALUE_ENUM (*arg) = scrolled_window->shadow_type; - break; - default: - arg->type = GTK_TYPE_INVALID; - break; - } + add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD); + add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD); } static void gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window) { - GTK_WIDGET_SET_FLAGS (scrolled_window, GTK_NO_WINDOW); - - gtk_container_set_resize_mode (GTK_CONTAINER (scrolled_window), GTK_RESIZE_QUEUE); + GTK_WIDGET_SET_FLAGS (scrolled_window, GTK_NO_WINDOW | GTK_CAN_FOCUS); scrolled_window->hscrollbar = NULL; scrolled_window->vscrollbar = NULL; @@ -285,6 +338,7 @@ gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window) scrolled_window->vscrollbar_policy = GTK_POLICY_ALWAYS; scrolled_window->hscrollbar_visible = FALSE; scrolled_window->vscrollbar_visible = FALSE; + scrolled_window->focus_out = FALSE; scrolled_window->window_placement = GTK_CORNER_TOP_LEFT; } @@ -331,7 +385,7 @@ gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window, gtk_widget_pop_composite_child (); gtk_widget_set_parent (scrolled_window->hscrollbar, GTK_WIDGET (scrolled_window)); - gtk_widget_ref (scrolled_window->hscrollbar); + g_object_ref (scrolled_window->hscrollbar); gtk_widget_show (scrolled_window->hscrollbar); } else @@ -342,23 +396,25 @@ gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window, if (old_adjustment == hadjustment) return; - gtk_signal_disconnect_by_func (GTK_OBJECT (old_adjustment), - GTK_SIGNAL_FUNC (gtk_scrolled_window_adjustment_changed), - scrolled_window); + g_signal_handlers_disconnect_by_func (old_adjustment, + gtk_scrolled_window_adjustment_changed, + scrolled_window); gtk_range_set_adjustment (GTK_RANGE (scrolled_window->hscrollbar), hadjustment); } hadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)); - gtk_signal_connect (GTK_OBJECT (hadjustment), - "changed", - GTK_SIGNAL_FUNC (gtk_scrolled_window_adjustment_changed), - scrolled_window); + g_signal_connect (hadjustment, + "changed", + G_CALLBACK (gtk_scrolled_window_adjustment_changed), + scrolled_window); gtk_scrolled_window_adjustment_changed (hadjustment, scrolled_window); if (bin->child) gtk_widget_set_scroll_adjustments (bin->child, gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)), gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar))); + + g_object_notify (G_OBJECT (scrolled_window), "hadjustment"); } void @@ -383,7 +439,7 @@ gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window, gtk_widget_pop_composite_child (); gtk_widget_set_parent (scrolled_window->vscrollbar, GTK_WIDGET (scrolled_window)); - gtk_widget_ref (scrolled_window->vscrollbar); + g_object_ref (scrolled_window->vscrollbar); gtk_widget_show (scrolled_window->vscrollbar); } else @@ -394,23 +450,25 @@ gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window, if (old_adjustment == vadjustment) return; - gtk_signal_disconnect_by_func (GTK_OBJECT (old_adjustment), - GTK_SIGNAL_FUNC (gtk_scrolled_window_adjustment_changed), - scrolled_window); + g_signal_handlers_disconnect_by_func (old_adjustment, + gtk_scrolled_window_adjustment_changed, + scrolled_window); gtk_range_set_adjustment (GTK_RANGE (scrolled_window->vscrollbar), vadjustment); } vadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)); - gtk_signal_connect (GTK_OBJECT (vadjustment), - "changed", - GTK_SIGNAL_FUNC (gtk_scrolled_window_adjustment_changed), - scrolled_window); + g_signal_connect (vadjustment, + "changed", + G_CALLBACK (gtk_scrolled_window_adjustment_changed), + scrolled_window); gtk_scrolled_window_adjustment_changed (vadjustment, scrolled_window); if (bin->child) gtk_widget_set_scroll_adjustments (bin->child, gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)), gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar))); + + g_object_notify (G_OBJECT (scrolled_window), "vadjustment"); } GtkAdjustment* @@ -438,6 +496,8 @@ gtk_scrolled_window_set_policy (GtkScrolledWindow *scrolled_window, GtkPolicyType hscrollbar_policy, GtkPolicyType vscrollbar_policy) { + GObject *object = G_OBJECT (scrolled_window); + g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window)); if ((scrolled_window->hscrollbar_policy != hscrollbar_policy) || @@ -447,6 +507,11 @@ gtk_scrolled_window_set_policy (GtkScrolledWindow *scrolled_window, scrolled_window->vscrollbar_policy = vscrollbar_policy; gtk_widget_queue_resize (GTK_WIDGET (scrolled_window)); + + g_object_freeze_notify (object); + g_object_notify (object, "hscrollbar_policy"); + g_object_notify (object, "vscrollbar_policy"); + g_object_thaw_notify (object); } } @@ -483,6 +548,8 @@ gtk_scrolled_window_set_placement (GtkScrolledWindow *scrolled_window, scrolled_window->window_placement = window_placement; gtk_widget_queue_resize (GTK_WIDGET (scrolled_window)); + + g_object_notify (G_OBJECT (scrolled_window), "window_placement"); } } @@ -524,9 +591,11 @@ gtk_scrolled_window_set_shadow_type (GtkScrolledWindow *scrolled_window, scrolled_window->shadow_type = type; if (GTK_WIDGET_DRAWABLE (scrolled_window)) - gtk_widget_queue_clear (GTK_WIDGET (scrolled_window)); + gtk_widget_queue_draw (GTK_WIDGET (scrolled_window)); gtk_widget_queue_resize (GTK_WIDGET (scrolled_window)); + + g_object_notify (G_OBJECT (scrolled_window), "shadow_type"); } } @@ -569,50 +638,88 @@ gtk_scrolled_window_finalize (GObject *object) { GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (object); - gtk_widget_unref (scrolled_window->hscrollbar); - gtk_widget_unref (scrolled_window->vscrollbar); + g_object_unref (scrolled_window->hscrollbar); + g_object_unref (scrolled_window->vscrollbar); G_OBJECT_CLASS (parent_class)->finalize (object); } static void -gtk_scrolled_window_map (GtkWidget *widget) +gtk_scrolled_window_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) { - GtkScrolledWindow *scrolled_window; - - g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget)); - - scrolled_window = GTK_SCROLLED_WINDOW (widget); - - /* chain parent class handler to map self and child */ - GTK_WIDGET_CLASS (parent_class)->map (widget); - - if (GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar) && - !GTK_WIDGET_MAPPED (scrolled_window->hscrollbar)) - gtk_widget_map (scrolled_window->hscrollbar); + GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (object); - if (GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar) && - !GTK_WIDGET_MAPPED (scrolled_window->vscrollbar)) - gtk_widget_map (scrolled_window->vscrollbar); + switch (prop_id) + { + case PROP_HADJUSTMENT: + gtk_scrolled_window_set_hadjustment (scrolled_window, + g_value_get_object (value)); + break; + case PROP_VADJUSTMENT: + gtk_scrolled_window_set_vadjustment (scrolled_window, + g_value_get_object (value)); + break; + case PROP_HSCROLLBAR_POLICY: + gtk_scrolled_window_set_policy (scrolled_window, + g_value_get_enum (value), + scrolled_window->vscrollbar_policy); + break; + case PROP_VSCROLLBAR_POLICY: + gtk_scrolled_window_set_policy (scrolled_window, + scrolled_window->hscrollbar_policy, + g_value_get_enum (value)); + break; + case PROP_WINDOW_PLACEMENT: + gtk_scrolled_window_set_placement (scrolled_window, + g_value_get_enum (value)); + break; + case PROP_SHADOW_TYPE: + gtk_scrolled_window_set_shadow_type (scrolled_window, + g_value_get_enum (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } } static void -gtk_scrolled_window_unmap (GtkWidget *widget) +gtk_scrolled_window_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) { - GtkScrolledWindow *scrolled_window; - - g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget)); - - scrolled_window = GTK_SCROLLED_WINDOW (widget); - - /* chain parent class handler to unmap self and child */ - GTK_WIDGET_CLASS (parent_class)->unmap (widget); - - if (GTK_WIDGET_MAPPED (scrolled_window->hscrollbar)) - gtk_widget_unmap (scrolled_window->hscrollbar); + GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (object); - if (GTK_WIDGET_MAPPED (scrolled_window->vscrollbar)) - gtk_widget_unmap (scrolled_window->vscrollbar); + switch (prop_id) + { + case PROP_HADJUSTMENT: + g_value_set_object (value, + G_OBJECT (gtk_scrolled_window_get_hadjustment (scrolled_window))); + break; + case PROP_VADJUSTMENT: + g_value_set_object (value, + G_OBJECT (gtk_scrolled_window_get_vadjustment (scrolled_window))); + break; + case PROP_HSCROLLBAR_POLICY: + g_value_set_enum (value, scrolled_window->hscrollbar_policy); + break; + case PROP_VSCROLLBAR_POLICY: + g_value_set_enum (value, scrolled_window->vscrollbar_policy); + break; + case PROP_WINDOW_PLACEMENT: + g_value_set_enum (value, scrolled_window->window_placement); + break; + case PROP_SHADOW_TYPE: + g_value_set_enum (value, scrolled_window->shadow_type); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } } static void @@ -681,6 +788,127 @@ gtk_scrolled_window_forall (GtkContainer *container, } } +static void +gtk_scrolled_window_scroll_child (GtkScrolledWindow *scrolled_window, + GtkScrollType scroll, + gboolean horizontal) +{ + GtkAdjustment *adjustment = NULL; + + switch (scroll) + { + case GTK_SCROLL_STEP_UP: + scroll = GTK_SCROLL_STEP_BACKWARD; + horizontal = FALSE; + break; + case GTK_SCROLL_STEP_DOWN: + scroll = GTK_SCROLL_STEP_FORWARD; + horizontal = FALSE; + break; + case GTK_SCROLL_STEP_LEFT: + scroll = GTK_SCROLL_STEP_BACKWARD; + horizontal = TRUE; + break; + case GTK_SCROLL_STEP_RIGHT: + scroll = GTK_SCROLL_STEP_FORWARD; + horizontal = TRUE; + break; + case GTK_SCROLL_PAGE_UP: + scroll = GTK_SCROLL_PAGE_BACKWARD; + horizontal = FALSE; + break; + case GTK_SCROLL_PAGE_DOWN: + scroll = GTK_SCROLL_PAGE_FORWARD; + horizontal = FALSE; + break; + case GTK_SCROLL_PAGE_LEFT: + scroll = GTK_SCROLL_STEP_BACKWARD; + horizontal = TRUE; + break; + case GTK_SCROLL_PAGE_RIGHT: + scroll = GTK_SCROLL_STEP_FORWARD; + horizontal = TRUE; + break; + case GTK_SCROLL_STEP_BACKWARD: + case GTK_SCROLL_STEP_FORWARD: + case GTK_SCROLL_PAGE_BACKWARD: + case GTK_SCROLL_PAGE_FORWARD: + case GTK_SCROLL_START: + case GTK_SCROLL_END: + break; + default: + g_warning ("Invalid scroll type %d for GtkSpinButton::change-value", scroll); + return; + } + + if (horizontal) + { + if (scrolled_window->hscrollbar) + adjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)); + } + else + { + if (scrolled_window->vscrollbar) + adjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)); + } + + if (adjustment) + { + gdouble value = adjustment->value; + + switch (scroll) + { + case GTK_SCROLL_STEP_FORWARD: + value += adjustment->step_increment; + break; + case GTK_SCROLL_STEP_BACKWARD: + value -= adjustment->step_increment; + break; + case GTK_SCROLL_PAGE_FORWARD: + value += adjustment->page_increment; + break; + case GTK_SCROLL_PAGE_BACKWARD: + value -= adjustment->page_increment; + break; + case GTK_SCROLL_START: + value = adjustment->lower; + break; + case GTK_SCROLL_END: + value = adjustment->upper; + break; + default: + g_assert_not_reached (); + break; + } + + value = CLAMP (value, adjustment->lower, adjustment->upper - adjustment->page_size); + + gtk_adjustment_set_value (adjustment, value); + } +} + +static void +gtk_scrolled_window_move_focus_out (GtkScrolledWindow *scrolled_window, + GtkDirectionType direction_type) +{ + GtkWidget *toplevel; + + /* Focus out of the scrolled window entirely. We do this by setting + * a flag, then propagating the focus motion to the notebook. + */ + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (scrolled_window)); + if (!GTK_WIDGET_TOPLEVEL (toplevel)) + return; + + g_object_ref (scrolled_window); + + scrolled_window->focus_out = TRUE; + g_signal_emit_by_name (toplevel, "move_focus", direction_type); + scrolled_window->focus_out = FALSE; + + g_object_unref (scrolled_window); +} + static void gtk_scrolled_window_size_request (GtkWidget *widget, GtkRequisition *requisition) @@ -689,6 +917,7 @@ gtk_scrolled_window_size_request (GtkWidget *widget, GtkBin *bin; gint extra_width; gint extra_height; + gint scrollbar_spacing; GtkRequisition hscrollbar_requisition; GtkRequisition vscrollbar_requisition; GtkRequisition child_requisition; @@ -699,6 +928,8 @@ gtk_scrolled_window_size_request (GtkWidget *widget, scrolled_window = GTK_SCROLLED_WINDOW (widget); bin = GTK_BIN (scrolled_window); + scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window); + extra_width = 0; extra_height = 0; requisition->width = 0; @@ -749,7 +980,7 @@ gtk_scrolled_window_size_request (GtkWidget *widget, { requisition->width = MAX (requisition->width, hscrollbar_requisition.width); if (!extra_height || scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS) - extra_height = SCROLLBAR_SPACING (scrolled_window) + hscrollbar_requisition.height; + extra_height = scrollbar_spacing + hscrollbar_requisition.height; } if (scrolled_window->vscrollbar_policy == GTK_POLICY_AUTOMATIC || @@ -757,7 +988,7 @@ gtk_scrolled_window_size_request (GtkWidget *widget, { requisition->height = MAX (requisition->height, vscrollbar_requisition.height); if (!extra_height || scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS) - extra_width = SCROLLBAR_SPACING (scrolled_window) + vscrollbar_requisition.width; + extra_width = scrollbar_spacing + vscrollbar_requisition.width; } requisition->width += GTK_CONTAINER (widget)->border_width * 2 + MAX (0, extra_width); @@ -775,11 +1006,13 @@ gtk_scrolled_window_relative_allocation (GtkWidget *widget, GtkAllocation *allocation) { GtkScrolledWindow *scrolled_window; + gint scrollbar_spacing; g_return_if_fail (widget != NULL); g_return_if_fail (allocation != NULL); scrolled_window = GTK_SCROLLED_WINDOW (widget); + scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window); allocation->x = GTK_CONTAINER (widget)->border_width; allocation->y = GTK_CONTAINER (widget)->border_width; @@ -801,12 +1034,9 @@ gtk_scrolled_window_relative_allocation (GtkWidget *widget, if (scrolled_window->window_placement == GTK_CORNER_TOP_RIGHT || scrolled_window->window_placement == GTK_CORNER_BOTTOM_RIGHT) - allocation->x += (vscrollbar_requisition.width + - SCROLLBAR_SPACING (scrolled_window)); + allocation->x += (vscrollbar_requisition.width + scrollbar_spacing); - allocation->width = MAX (1, (gint)allocation->width - - ((gint)vscrollbar_requisition.width + - (gint)SCROLLBAR_SPACING (scrolled_window))); + allocation->width = MAX (1, allocation->width - (vscrollbar_requisition.width + scrollbar_spacing)); } if (scrolled_window->hscrollbar_visible) { @@ -816,12 +1046,9 @@ gtk_scrolled_window_relative_allocation (GtkWidget *widget, if (scrolled_window->window_placement == GTK_CORNER_BOTTOM_LEFT || scrolled_window->window_placement == GTK_CORNER_BOTTOM_RIGHT) - allocation->y += (hscrollbar_requisition.height + - SCROLLBAR_SPACING (scrolled_window)); + allocation->y += (hscrollbar_requisition.height + scrollbar_spacing); - allocation->height = MAX (1, (gint)allocation->height - - ((gint)hscrollbar_requisition.height + - (gint)SCROLLBAR_SPACING (scrolled_window))); + allocation->height = MAX (1, allocation->height - (hscrollbar_requisition.height + scrollbar_spacing)); } } @@ -833,6 +1060,7 @@ gtk_scrolled_window_size_allocate (GtkWidget *widget, GtkBin *bin; GtkAllocation relative_allocation; GtkAllocation child_allocation; + gint scrollbar_spacing; g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget)); g_return_if_fail (allocation != NULL); @@ -840,6 +1068,8 @@ gtk_scrolled_window_size_allocate (GtkWidget *widget, scrolled_window = GTK_SCROLLED_WINDOW (widget); bin = GTK_BIN (scrolled_window); + scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window); + widget->allocation = *allocation; if (scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS) @@ -909,7 +1139,7 @@ gtk_scrolled_window_size_allocate (GtkWidget *widget, scrolled_window->window_placement == GTK_CORNER_TOP_RIGHT) child_allocation.y = (relative_allocation.y + relative_allocation.height + - SCROLLBAR_SPACING (scrolled_window) + + scrollbar_spacing + (scrolled_window->shadow_type == GTK_SHADOW_NONE ? 0 : widget->style->ythickness)); else @@ -944,7 +1174,7 @@ gtk_scrolled_window_size_allocate (GtkWidget *widget, scrolled_window->window_placement == GTK_CORNER_BOTTOM_LEFT) child_allocation.x = (relative_allocation.x + relative_allocation.width + - SCROLLBAR_SPACING (scrolled_window) + + scrollbar_spacing + (scrolled_window->shadow_type == GTK_SHADOW_NONE ? 0 : widget->style->xthickness)); else @@ -1001,6 +1231,40 @@ gtk_scrolled_window_scroll_event (GtkWidget *widget, return FALSE; } +static gint +gtk_scrolled_window_focus (GtkWidget *widget, + GtkDirectionType direction) +{ + GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget); + gboolean had_focus_child = GTK_CONTAINER (widget)->focus_child != NULL; + + if (scrolled_window->focus_out) + { + scrolled_window->focus_out = FALSE; /* Clear this to catch the wrap-around case */ + return FALSE; + } + + if (gtk_widget_is_focus (widget)) + return FALSE; + + /* We only put the scrolled window itself in the focus chain if it + * isn't possible to focus any children. + */ + if (GTK_BIN (widget)->child) + { + if (gtk_widget_child_focus (GTK_BIN (widget)->child, direction)) + return TRUE; + } + + if (!had_focus_child) + { + gtk_widget_grab_focus (widget); + return TRUE; + } + else + return FALSE; +} + static void gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment, gpointer data) @@ -1063,17 +1327,6 @@ gtk_scrolled_window_add (GtkContainer *container, gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)))) g_warning ("gtk_scrolled_window_add(): cannot add non scrollable widget " "use gtk_scrolled_window_add_with_viewport() instead"); - - if (GTK_WIDGET_REALIZED (child->parent)) - gtk_widget_realize (child); - - if (GTK_WIDGET_VISIBLE (child->parent) && GTK_WIDGET_VISIBLE (child)) - { - if (GTK_WIDGET_MAPPED (child->parent)) - gtk_widget_map (child); - - gtk_widget_queue_resize (child); - } } static void @@ -1121,3 +1374,35 @@ gtk_scrolled_window_add_with_viewport (GtkScrolledWindow *scrolled_window, gtk_widget_show (viewport); gtk_container_add (GTK_CONTAINER (viewport), child); } + +/** + * _gtk_scrolled_window_get_spacing: + * @scrolled_window: a scrolled window + * + * Gets the spacing between the scrolled window's scrollbars and + * the scrolled widget. Used by GtkCombo + * + * Return value: the spacing, in pixels. + **/ +gint +_gtk_scrolled_window_get_scrollbar_spacing (GtkScrolledWindow *scrolled_window) +{ + GtkScrolledWindowClass *class; + + g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), 0); + + class = GTK_SCROLLED_WINDOW_GET_CLASS (scrolled_window); + + if (class->scrollbar_spacing >= 0) + return class->scrollbar_spacing; + else + { + gint scrollbar_spacing; + + gtk_widget_style_get (GTK_WIDGET (scrolled_window), + "scrollbar_spacing", &scrollbar_spacing, + NULL); + + return scrollbar_spacing; + } +}