/*
* File: dw_gtk_scrolled_frame.c
*
* Copyright (C) 2001 Sebastian Geerken <S.Geerken@ping.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
/*
* GtkDwScrolledFrame is a container for the GtkDwViewport, it adds
* a focus around the child and is responsible for focus, keys and the
* button 2 dragging.
*/
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include "dw_gtk_scrolled_frame.h"
static GtkBinClass *parent_class = NULL;
/* object/class initialisation */
static void Dw_gtk_scrolled_frame_init (GtkDwScrolledFrame *frame);
static void Dw_gtk_scrolled_frame_class_init (GtkDwScrolledFrameClass
*klass);
/* GtkObject methods */
static void Dw_gtk_scrolled_frame_destroy (GtkObject *object);
/* GtkWidget methods */
static void Dw_gtk_scrolled_frame_realize (GtkWidget *widget);
static void Dw_gtk_scrolled_frame_unrealize (GtkWidget *widget);
static void Dw_gtk_scrolled_frame_size_request (GtkWidget *widget,
GtkRequisition *requisition);
static void Dw_gtk_scrolled_frame_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static void Dw_gtk_scrolled_frame_draw (GtkWidget *widget,
GdkRectangle *area);
static void Dw_gtk_scrolled_frame_draw_focus (GtkWidget *widget);
static gint Dw_gtk_scrolled_frame_expose (GtkWidget *widget,
GdkEventExpose *event);
static gint Dw_gtk_scrolled_frame_key_press (GtkWidget *widget,
GdkEventKey *event);
static gint Dw_gtk_scrolled_frame_focus_in (GtkWidget *widget,
GdkEventFocus *event);
static gint Dw_gtk_scrolled_frame_focus_out (GtkWidget *widget,
GdkEventFocus *event);
static gint Dw_gtk_scrolled_frame_button_press (GtkWidget *widget,
GdkEventButton *event);
static gint Dw_gtk_scrolled_frame_button_release(GtkWidget *widget,
GdkEventButton *event);
static gint Dw_gtk_scrolled_frame_motion_notify (GtkWidget *widget,
GdkEventMotion *event);
/* GtkContainer methods */
static void Dw_gtk_scrolled_frame_add (GtkContainer *container,
GtkWidget *widget);
static gint Dw_gtk_scrolled_frame_focus (GtkContainer *container,
GtkDirectionType direction);
/* GtkDwScrolledFrame methods */
static void Dw_gtk_scrolled_frame_set_scroll_adjustments (GtkDwScrolledFrame
*frame,
GtkAdjustment
*hadjustment,
GtkAdjustment
*vadjustment);
static void Dw_gtk_scrolled_frame_move_x_to (GtkDwScrolledFrame *frame,
gfloat x);
static void Dw_gtk_scrolled_frame_move_y_to (GtkDwScrolledFrame *frame,
gfloat y);
static void Dw_gtk_scrolled_frame_move_by (GtkDwScrolledFrame *frame,
gfloat dx,
gfloat dy);
static gfloat Dw_gtk_scrolled_frame_correct_adj (GtkAdjustment *adj,
gfloat pos);
enum
{
SET_SCROLL_ADJUSTMENTS,
USER_HCHANGED,
USER_VCHANGED,
LAST_SIGNAL
};
static guint frame_signals[LAST_SIGNAL] = { 0 };
/*
* Standard Gtk+ function
*/
GtkType a_Dw_gtk_scrolled_frame_get_type (void)
{
static GtkType type = 0;
if (!type) {
GtkTypeInfo info = {
"GtkDwScrolledFrame",
sizeof (GtkDwScrolledFrame),
sizeof (GtkDwScrolledFrameClass),
(GtkClassInitFunc) Dw_gtk_scrolled_frame_class_init,
(GtkObjectInitFunc) Dw_gtk_scrolled_frame_init,
(GtkArgSetFunc) NULL,
(GtkArgGetFunc) NULL,
(GtkClassInitFunc) NULL
};
type = gtk_type_unique (GTK_TYPE_BIN, &info);
}
return type;
}
/*
* Standard Gtk+ function
*/
GtkWidget* a_Dw_gtk_scrolled_frame_new (GtkAdjustment *hadjustment,
GtkAdjustment *vadjustment)
{
GtkWidget *widget;
GtkDwScrolledFrame *frame;
widget = gtk_widget_new (GTK_TYPE_DW_SCROLLED_FRAME, NULL);
frame = GTK_DW_SCROLLED_FRAME (widget);
frame->hadjustment = hadjustment;
frame->vadjustment = vadjustment;
return widget;
}
/*********************************
* *
* object/class initialisation *
* *
*********************************/
/*
* Standard Gtk+ function
*/
static void Dw_gtk_scrolled_frame_init (GtkDwScrolledFrame *frame)
{
GTK_WIDGET_SET_FLAGS (frame, GTK_CAN_FOCUS);
GTK_WIDGET_UNSET_FLAGS (frame, GTK_NO_WINDOW);
frame->hadjustment = NULL;
frame->vadjustment = NULL;
frame->button2_pressed = FALSE;
frame->move_idle_id = 0;
}
/*
* Standard Gtk+ function
*/
static void Dw_gtk_scrolled_frame_class_init (GtkDwScrolledFrameClass *klass)
{
GtkObjectClass *object_class;
GtkWidgetClass *widget_class;
GtkContainerClass *container_class;
parent_class = gtk_type_class (gtk_bin_get_type ());
object_class = (GtkObjectClass*) klass;
widget_class = (GtkWidgetClass*) klass;
container_class = (GtkContainerClass*) klass;
frame_signals[SET_SCROLL_ADJUSTMENTS] =
gtk_signal_new ("set_scroll_adjustments",
GTK_RUN_LAST,
object_class->type,
GTK_SIGNAL_OFFSET (GtkDwScrolledFrameClass,
set_scroll_adjustments),
gtk_marshal_NONE__POINTER_POINTER,
GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT,
GTK_TYPE_ADJUSTMENT);
widget_class->set_scroll_adjustments_signal =
frame_signals[SET_SCROLL_ADJUSTMENTS];
frame_signals[USER_HCHANGED] =
gtk_signal_new ("user_hchanged",
GTK_RUN_LAST | GTK_RUN_ACTION,
object_class->type,
GTK_SIGNAL_OFFSET (GtkDwScrolledFrameClass,
user_hchanged),
gtk_marshal_NONE__NONE,
GTK_TYPE_NONE, 0);
frame_signals[USER_VCHANGED] =
gtk_signal_new ("user_vchanged",
GTK_RUN_LAST | GTK_RUN_ACTION,
object_class->type,
GTK_SIGNAL_OFFSET (GtkDwScrolledFrameClass,
user_vchanged),
gtk_marshal_NONE__NONE,
GTK_TYPE_NONE, 0);
gtk_object_class_add_signals (object_class, frame_signals, LAST_SIGNAL);
object_class->destroy = Dw_gtk_scrolled_frame_destroy;
widget_class->realize = Dw_gtk_scrolled_frame_realize;
widget_class->unrealize = Dw_gtk_scrolled_frame_unrealize;
widget_class->size_request = Dw_gtk_scrolled_frame_size_request;
widget_class->size_allocate = Dw_gtk_scrolled_frame_size_allocate;
widget_class->draw_focus = Dw_gtk_scrolled_frame_draw_focus;
widget_class->draw = Dw_gtk_scrolled_frame_draw;
widget_class->expose_event = Dw_gtk_scrolled_frame_expose;
widget_class->key_press_event = Dw_gtk_scrolled_frame_key_press;
widget_class->focus_in_event = Dw_gtk_scrolled_frame_focus_in;
widget_class->focus_out_event = Dw_gtk_scrolled_frame_focus_out;
widget_class->button_press_event = Dw_gtk_scrolled_frame_button_press;
widget_class->button_release_event = Dw_gtk_scrolled_frame_button_release;
widget_class->motion_notify_event = Dw_gtk_scrolled_frame_motion_notify;
container_class->add = Dw_gtk_scrolled_frame_add;
container_class->focus = Dw_gtk_scrolled_frame_focus;
klass->set_scroll_adjustments =
Dw_gtk_scrolled_frame_set_scroll_adjustments;
klass->user_hchanged = NULL;
klass->user_vchanged = NULL;
}
/***********************
* *
* GtkObject methods *
* *
***********************/
/*
* Standard Gtk+ function
*/
static void Dw_gtk_scrolled_frame_destroy (GtkObject *object)
{
GtkDwScrolledFrame *frame;
frame = GTK_DW_SCROLLED_FRAME (object);
if (frame->move_idle_id != 0)
gtk_idle_remove (frame->move_idle_id);
GTK_OBJECT_CLASS(parent_class)->destroy (object);
}
/***********************
* *
* GtkWidget methods *
* *
***********************/
/*
* Standard Gtk+ function
*/
static void Dw_gtk_scrolled_frame_realize (GtkWidget *widget)
{
GdkWindowAttr attributes;
GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
attributes.window_type = GDK_WINDOW_CHILD;
attributes.x = widget->allocation.x;
attributes.y = widget->allocation.y;
attributes.width = widget->allocation.width;
attributes.height = widget->allocation.height;
attributes.wclass = GDK_INPUT_OUTPUT;
attributes.visual = gtk_widget_get_visual (widget);
attributes.colormap = gtk_widget_get_colormap (widget);
attributes.event_mask = (gtk_widget_get_events (widget)
| GDK_EXPOSURE_MASK
| GDK_KEY_PRESS_MASK
| GDK_BUTTON_PRESS_MASK);
widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
&attributes,
GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL |
GDK_WA_COLORMAP);
gdk_window_set_user_data (widget->window, widget);
widget->style = gtk_style_attach (widget->style, widget->window);
gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
GTK_DW_SCROLLED_FRAME(widget)->drag_cursor = gdk_cursor_new (GDK_FLEUR);
}
/*
* Standard Gtk+ function
*/
static void Dw_gtk_scrolled_frame_unrealize (GtkWidget *widget)
{
gdk_cursor_destroy (GTK_DW_SCROLLED_FRAME(widget)->drag_cursor);
GTK_WIDGET_CLASS(parent_class)->unrealize (widget);
}
/*
* Standard Gtk+ function
*/
static void Dw_gtk_scrolled_frame_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
GtkBin *bin;
gint border_width;
GtkAllocation child_allocation;
widget->allocation = *allocation;
bin = GTK_BIN (widget);
if (GTK_WIDGET_REALIZED (widget))
gdk_window_move_resize (widget->window,
allocation->x, allocation->y,
allocation->width, allocation->height);
if (bin->child) {
border_width = GTK_CONTAINER(widget)->border_width;
child_allocation.width =
MAX (allocation->width - 2 * (widget->style->klass->xthickness +
border_width),
1);
child_allocation.height =
MAX (allocation->height - 2 * (widget->style->klass->ythickness +
border_width),
1);
child_allocation.x = (allocation->width - child_allocation.width) / 2;
child_allocation.y = (allocation->height - child_allocation.height) / 2;
gtk_widget_size_allocate (bin->child, &child_allocation);
}
}
/*
* Standard Gtk+ function
*/
static void Dw_gtk_scrolled_frame_size_request (GtkWidget *widget,
GtkRequisition *requisition)
{
GtkBin *bin;
gint border_width;
GtkRequisition child_requisition;
bin = GTK_BIN (widget);
if (bin->child) {
border_width = GTK_CONTAINER(widget)->border_width;
gtk_widget_size_request (bin->child, &child_requisition);
requisition->width =
child_requisition.width + 2 * (widget->style->klass->xthickness +
border_width);
requisition->height =
child_requisition.height + 2 * (widget->style->klass->ythickness +
border_width);
} else {
requisition->width = 100;
requisition->height = 100;
}
}
/*
* Draw the frame, eventually with a focus border
*/
static void Dw_gtk_scrolled_frame_paint_shadow (GtkWidget *widget,
GdkRectangle *area)
{
gint border_width;
if (GTK_WIDGET_DRAWABLE (widget)) {
border_width = GTK_CONTAINER(widget)->border_width;
if (GTK_WIDGET_HAS_FOCUS (widget)) {
gtk_draw_shadow (widget->style, widget->window,
GTK_STATE_NORMAL, GTK_SHADOW_IN,
border_width + 1, border_width + 1,
widget->allocation.width - 2 * (border_width + 1),
widget->allocation.height - 2 * (border_width + 1));
/* "text" is probably next to what we need */
gtk_paint_focus (widget->style, widget->window,
area, widget, "text",
border_width, border_width,
widget->allocation.width - 2 * border_width - 1,
widget->allocation.height - 2 * border_width - 1);
} else {
gtk_draw_shadow (widget->style, widget->window,
GTK_STATE_NORMAL, GTK_SHADOW_IN,
border_width, border_width,
widget->allocation.width - 2 * border_width,
widget->allocation.height - 2 * border_width);
}
}
}
/*
* Standard Gtk+ function
*/
static void Dw_gtk_scrolled_frame_draw_focus (GtkWidget *widget)
{
Dw_gtk_scrolled_frame_paint_shadow (widget, NULL);
}
/*
* Standard Gtk+ function
*/
static void Dw_gtk_scrolled_frame_draw (GtkWidget *widget,
GdkRectangle *area)
{
GTK_WIDGET_CLASS(parent_class)->draw (widget, area);
Dw_gtk_scrolled_frame_paint_shadow (widget, area);
}
/*
* Standard Gtk+ function
*/
static gint Dw_gtk_scrolled_frame_expose (GtkWidget *widget,
GdkEventExpose *event)
{
gint ret_val;
ret_val = GTK_WIDGET_CLASS(parent_class)->expose_event (widget, event);
Dw_gtk_scrolled_frame_paint_shadow (widget, &(event->area));
return ret_val;
}
/*
* Standard Gtk+ function
*/
static gint Dw_gtk_scrolled_frame_key_press (GtkWidget *widget,
GdkEventKey *event)
{
GtkContainer *container;
GtkDwScrolledFrame *frame;
container = GTK_CONTAINER (widget);
frame = GTK_DW_SCROLLED_FRAME (widget);
switch (event->keyval) {
case GDK_Up:
case GDK_KP_Up:
Dw_gtk_scrolled_frame_move_by (frame, 0,
- frame->vadjustment->step_increment);
return TRUE;
case GDK_Down:
case GDK_KP_Down:
Dw_gtk_scrolled_frame_move_by (frame, 0,
+ frame->vadjustment->step_increment);
return TRUE;
case GDK_Left:
case GDK_KP_Left:
Dw_gtk_scrolled_frame_move_by (frame,
- frame->hadjustment->step_increment, 0);
return TRUE;
case GDK_Right:
case GDK_KP_Right:
Dw_gtk_scrolled_frame_move_by (frame,
+ frame->hadjustment->step_increment, 0);
return TRUE;
case GDK_Tab:
if (event->state & GDK_SHIFT_MASK)
return gtk_container_focus (container, GTK_DIR_TAB_BACKWARD);
else
return gtk_container_focus (container, GTK_DIR_TAB_FORWARD);
case GDK_b: case GDK_B:
if (event->state & GDK_CONTROL_MASK)
return FALSE;
/* continues */
case GDK_Page_Up:
case GDK_KP_Page_Up:
if (event->state & GDK_CONTROL_MASK)
Dw_gtk_scrolled_frame_move_by (frame,
- frame->hadjustment->page_increment,
0);
else
Dw_gtk_scrolled_frame_move_by (frame, 0,
- frame->vadjustment->page_increment);
return TRUE;
case GDK_Page_Down:
case GDK_KP_Page_Down:
case GDK_space:
if (event->state & GDK_CONTROL_MASK)
Dw_gtk_scrolled_frame_move_by (frame,
+ frame->hadjustment->page_increment,
0);
else
Dw_gtk_scrolled_frame_move_by (frame, 0,
+ frame->vadjustment->page_increment);
return TRUE;
case GDK_Home:
case GDK_KP_Home:
if (event->state & GDK_CONTROL_MASK)
Dw_gtk_scrolled_frame_move_x_to (frame, 0);
else
Dw_gtk_scrolled_frame_move_y_to (frame, 0);
return TRUE;
case GDK_End:
case GDK_KP_End:
if (event->state & GDK_CONTROL_MASK)
Dw_gtk_scrolled_frame_move_x_to (frame, G_MAXFLOAT);
else
Dw_gtk_scrolled_frame_move_y_to (frame, G_MAXFLOAT);
return TRUE;
default:
return FALSE;
}
}
/*
* Standard Gtk+ function
*/
static gint Dw_gtk_scrolled_frame_focus_in (GtkWidget *widget,
GdkEventFocus *event)
{
GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
gtk_widget_draw_focus (widget);
return FALSE;
}
/*
* Standard Gtk+ function
*/
static gint Dw_gtk_scrolled_frame_focus_out (GtkWidget *widget,
GdkEventFocus *event)
{
GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
gtk_widget_draw_focus (widget);
return FALSE;
}
/*
* Standard Gtk+ function
*/
static gint Dw_gtk_scrolled_frame_button_press (GtkWidget *widget,
GdkEventButton *event)
{
GtkDwScrolledFrame *frame;
if (!GTK_WIDGET_HAS_FOCUS (widget))
gtk_widget_grab_focus (widget);
if (event->button == 2) {
frame = GTK_DW_SCROLLED_FRAME (widget);
frame->button2_pressed = TRUE;
frame->start_lmx = event->x;
frame->start_lmy = event->y;
gdk_pointer_grab (widget->window, FALSE,
GDK_BUTTON_RELEASE_MASK | GDK_BUTTON2_MOTION_MASK,
NULL, frame->drag_cursor, event->time);
}
return TRUE;
}
/*
* Standard Gtk+ function
*/
static gint Dw_gtk_scrolled_frame_button_release (GtkWidget *widget,
GdkEventButton *event)
{
GTK_DW_SCROLLED_FRAME(widget)->button2_pressed = FALSE;
gdk_pointer_ungrab (event->time);
return TRUE;
}
/*
* Standard Gtk+ function
*/
static gint Dw_gtk_scrolled_frame_motion_notify (GtkWidget *widget,
GdkEventMotion *event)
{
GtkDwScrolledFrame *frame = GTK_DW_SCROLLED_FRAME (widget);
/* frame->button2_pressed makes sure that the button was pressed
in the GtkDwScrolledFrame */
if ((event->state & GDK_BUTTON2_MASK) && frame->button2_pressed) {
Dw_gtk_scrolled_frame_move_by (frame,
frame->start_lmx - event->x,
frame->start_lmy - event->y);
frame->start_lmx = event->x;
frame->start_lmy = event->y;
}
return TRUE;
}
/**************************
* *
* GtkContainer methods *
* *
**************************/
/*
* Standard Gtk+ function
*/
static void Dw_gtk_scrolled_frame_add (GtkContainer *container,
GtkWidget *widget)
{
GtkDwScrolledFrame *frame;
GTK_CONTAINER_CLASS(parent_class)->add (container, widget);
frame = GTK_DW_SCROLLED_FRAME (container);
if ( !gtk_widget_set_scroll_adjustments (
GTK_WIDGET (container), frame->hadjustment, frame->vadjustment) )
g_warning ("Dw_gtk_scrolled_frame_set_scroll_adjustments(): "
"child is non scrollable");
}
/*
* Standard Gtk+ function
*/
static gint Dw_gtk_scrolled_frame_focus (GtkContainer *container,
GtkDirectionType direction)
{
/* todo:
* This crashed if the child is not a container (what will never happen
* in dillo, where GtkDwScrolledFrame always contains a GtkDwViewport).
*/
GtkDwScrolledFrame *frame;
frame = GTK_DW_SCROLLED_FRAME (container);
if (!GTK_WIDGET_HAS_FOCUS (container) && container->focus_child == NULL){
/* no focus on the GtkDwScrolledFrame or any child widget => grab focus!
*/
gtk_widget_grab_focus (GTK_WIDGET (container));
return TRUE;
}
switch (direction) {
case GTK_DIR_TAB_FORWARD:
/* deliver to child */
if (!gtk_container_focus (GTK_CONTAINER (GTK_BIN(container)->child),
direction)) {
/* todo: it would be nice to keep focus on this last child widget,
* instead of the container... Anyway this may change with GTK2 */
gtk_widget_grab_focus (GTK_WIDGET (container));
}
return TRUE;
case GTK_DIR_TAB_BACKWARD:
if (GTK_WIDGET_HAS_FOCUS (container)) {
/* will focus the widget "before" */
return FALSE;
} else {
if (!gtk_container_focus (GTK_CONTAINER (GTK_BIN(container)->child),
GTK_DIR_TAB_BACKWARD))
/* first child of the child unfocussed */
gtk_widget_grab_focus (GTK_WIDGET (container));
return TRUE;
}
break;
/*
case GTK_DIR_LEFT:
case GTK_DIR_RIGHT:
case GTK_DIR_UP:
case GTK_DIR_DOWN:
*/
default:
/* focus the GtkDwScrolledFrame */
gtk_widget_grab_focus (GTK_WIDGET (container));
return TRUE;
}
/* make compiler happy */
return FALSE;
}
/********************************
* *
* GtkDwScrolledFrame methods *
* *
********************************/
/*
* Standard Gtk+ function
*/
static void
Dw_gtk_scrolled_frame_set_scroll_adjustments (GtkDwScrolledFrame *frame,
GtkAdjustment *hadjustment,
GtkAdjustment *vadjustment)
{
GtkBin *bin;
frame->hadjustment = hadjustment;
frame->vadjustment = vadjustment;
bin = GTK_BIN (frame);
if (bin->child) {
if (!gtk_widget_set_scroll_adjustments (bin->child,
hadjustment,
vadjustment))
g_warning ("Dw_gtk_scrolled_frame_set_scroll_adjustments(): "
"child is non scrollable");
}
}
/*
* Functions for moving the viewport. This is queued and done in an
* idle function, to prevent locks by too frequent keypresses, or too
* fast mouse movements. (How to reproduce: start dillo on a slow,
* overloaded system with nice priority.)
*/
/*
* The idle function.
*/
static gint Dw_gtk_scrolled_frame_move_idle (gpointer data)
{
GtkDwScrolledFrame *frame;
frame = GTK_DW_SCROLLED_FRAME (data);
g_return_val_if_fail (frame->hadjustment != NULL, FALSE);
g_return_val_if_fail (frame->vadjustment != NULL, FALSE);
if (frame->moveto_x != frame->hadjustment->value) {
gtk_adjustment_set_value (frame->hadjustment, frame->moveto_x);
gtk_signal_emit (GTK_OBJECT (frame), frame_signals[USER_HCHANGED]);
}
if (frame->moveto_y != frame->vadjustment->value) {
gtk_adjustment_set_value (frame->vadjustment, frame->moveto_y);
gtk_signal_emit (GTK_OBJECT (frame), frame_signals[USER_VCHANGED]);
}
frame->move_idle_id = 0;
return FALSE;
}
/*
* Change horizontall position to x.
*/
static void Dw_gtk_scrolled_frame_move_x_to (GtkDwScrolledFrame *frame,
gfloat x)
{
frame->moveto_x =
Dw_gtk_scrolled_frame_correct_adj (frame->hadjustment, x);
if (frame->move_idle_id == 0)
frame->move_idle_id = gtk_idle_add (Dw_gtk_scrolled_frame_move_idle,
(gpointer) frame);
}
/*
* Change vertical position to y.
*/
static void Dw_gtk_scrolled_frame_move_y_to (GtkDwScrolledFrame *frame,
gfloat y)
{
frame->moveto_y =
Dw_gtk_scrolled_frame_correct_adj (frame->vadjustment, y);
if (frame->move_idle_id == 0)
frame->move_idle_id = gtk_idle_add (Dw_gtk_scrolled_frame_move_idle,
(gpointer) frame);
}
/*
* Move viewport by dx and dy.
*/
static void Dw_gtk_scrolled_frame_move_by (GtkDwScrolledFrame *frame,
gfloat dx,
gfloat dy)
{
if (frame->move_idle_id == 0) {
/*
* Initialization: if the idle function is not active, set
* moveto_x and moveto_y to adjustments values, which may
* already have been changed by the scrollbars. This code does
* not work when a user uses scrollbars and keys at the same
* time. ;-)
*/
frame->moveto_x = frame->hadjustment->value;
frame->moveto_y = frame->vadjustment->value;
}
frame->moveto_x =
Dw_gtk_scrolled_frame_correct_adj (frame->hadjustment,
frame->moveto_x + dx);
frame->moveto_y =
Dw_gtk_scrolled_frame_correct_adj (frame->vadjustment,
frame->moveto_y + dy);
if (frame->move_idle_id == 0)
frame->move_idle_id = gtk_idle_add (Dw_gtk_scrolled_frame_move_idle,
(gpointer) frame);
}
/*
* Helper function: Corrects pos to fit into the boundaries of adj.
*/
static gfloat Dw_gtk_scrolled_frame_correct_adj (GtkAdjustment *adj,
gfloat pos)
{
if (pos < adj->lower)
return adj->lower;
else if (pos > adj->upper - adj->page_size)
return adj->upper - adj->page_size;
else
return pos;
}