Page about new GtkScrollable interface that would replace current pre-GTK+-2.0 workaround.

Background

Implementing scrollable widget currently requires one to register signal named set-scroll-adjustments and place it's ID into widget_class->set_scroll_adjustments_signal field. Registering this signal also requires a custom marshal of type VOID__OBJECT_OBJECT, which adds additional complexity. Last thing that is needed is default handler for this signal which establishes the connection between scrollable widget and it's child.

When scrollable widget is added to it's parent, parent widget calls gtk_widget_set_scroll_adjustments() (passing horizontal and vertical GtkAdjustment as parameters), which in turn emits ::set-scroll-adjustments signal on scrollable widget. Default handler for this signal then populates both adjustments with proper values. Link between scrollable widget and it's parent is now established.

To keep both parent and child in sync, parent listens to GtkAdjustment::changed signal and only updates GtkAdjustment:value property while child listens to GtkAdjustment::value-changed signal and modifies lower, upper, step-increment, page-increment and page-size properties.

Proposal

Replace current method with new GtkScrollable interface.

Requirements for GtkScrollable interface

New scrollable interface should be as simple as possible. It's design should only require minor changes to existing code and should be able to work in parallel with old method of scrolling widgets.

Design

GtkScrollable interface only defines two properties of type GtkAdjustment: hadjustment and vadjustment. There are also convenience wrappers available for getting and setting those properties.

Parent widget now only sets both properties and connection is established. Scrolled widget populates GtkAdjustment inside it's property setter.

Example

Only relevant sections are displayed here.

/* myscrollablewidget.c */

#include <gtk/gtk.h>

/* Properties */
enum
{
  P_0,
  /* More properties here (optional) */
  P_HADJUSTMENT,
  P_VADJUSTMENT,
  /* More properties here (optional) */
};

/* Signals, declarations, global variables ... */

/* Not interface init function is needed here, because GtkScrollable interface
 * is implemeted by overriding hadjustment and vadjustment properties. */
G_DEFINE_TYPE_WITH_CODE (MyScrollableWidget,
                         my_scrollable_widget,
                         GTK_TYPE_DRAWING_AREA,
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL));

static void
my_scrollable_widget_class_init (MyScrollableWidgetClass *klass)
{
  GObjectClass *g_class = G_OBJECT_CLASS (klass);

  /* Do your stuff here */

  /* Override properties */
  g_object_class_override_property (g_class, P_HADJUSTMENT, "hadjustment");
  g_object_class_override_property (g_class, P_VADJUSTMENT, "vadjustment");

  /* More stuff here */
}

static void
my_scrollable_widget_set_property (GObject      *object,
                                   guint         prop_id,
                                   const GValue *value,
                                   GParamSpec   *pspec)
{
  MyScrollableWidget *myscroll = MY_SCROLLABLE_WIDGET (object);

  switch (prop_id)
    {
    /* More here */
    case P_HADJUSTMENT:
      my_scrollable_widget_set_hadjustment (my_scroll,
                                            g_value_get_object (value));
      break;
    case P_VADJUSTMENT:
      my_scrollable_widget_set_vadjustment (my_scroll,
                                            g_value_get_object (value));
      break;
    /* More here */
    }
}

static void
my_scrollable_widget_get_property (GObject    *object,
                                   guint       prop_id,
                                   GValue     *value,
                                   GParamSpec *pspec)
{
  MyScrollableWidgetPriv *priv = MY_SCROLLABLE_WIDGET (object)->priv;

  switch (prop_id)
    {
    /* More here */
    case P_HADJUSTMENT:
      g_value_set_object (value, priv->hadjustment);
      break;
    case P_VADJUSTMENT:
      g_value_set_object (value, priv->vadjustment);
      break;
    /* More here */
    }
}

void
my_scrollable_widget_set_hadjustment (MyScrollableWidget *myscroll,
                                      GtkAdjustment      *hadjustment)
{
  /* Implementation of this function will vary greatly from widget to widget,
   * but these are the common steps each widget will need to take care of:
   *  - store adjustment inside a widget (probably inside private data)
   *  - populate adjustment with values (value property should be left alone
   *    unless clamping is needed to fit within valid interval)
   *  - connect handler to ::value-changed signal (this function is responsible
   *    for actual scrolling).
   */
}

Projects affected

GTK+

Widget

Status

GtkViewport

Already has [hv]adjustment properties; minimal effort required to port.

GtkLayout

Already has [hv]adjustment properties; minimal effort required to port.

GtkTextView

[hv]adjustment properties need to be installed.

GtkIconView

[hv]adjustment properties need to be installed.

GtkTreeView

Already has [hv]adjustment properties; minimal effort required to port.

GtkToolPalette

[hv]adjustment properties need to be installed.

Note

Only GtkViewport widget currently properly updates it's adjustments. All other widgets rely on size allocation to happen and trigger adjustments' updates. This should probably be fixed when porting to new interface.

Other applications/widgets

This is by no means complete list. Feel free to add additional applications/libraries to this list.

Application/Library

Widget

Status

Evince

EvView

Derived from GtkLayout. No work needed.

Exo

ExoIconView

[hv]adjustment properties need to be installed.

GooCanvas

GooCanvas

[hv]adjustment properties need to be installed.

VTE

VteTerminal

[hv]adjustment properties need to be installed.

GtkSourceView

GtkSourceView

Derived from GtkTextView. No work needed.

GtkImageView

GtkImageview

[hv]adjustment properties need to be installed.

GPicView

ImageView

[hv]adjustment properties need to be installed.

!WebKitGTK+

WebKitWebview

[hv]adjustment properties need to be installed.

Sample Implementation

See bug #468689 for sample implementation (API docs are omitted currently to reduce attachment size).

Projects/GTK+/GtkScrollable (last edited 2013-11-22 15:37:04 by WilliamJonMcCann)