X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=hildon%2Fhildon-pannable-area.c;h=c05edb0baf74022d7d9e6f5cd36b8d76f5c45402;hb=refs%2Fheads%2Fmaster;hp=86342e42235478257405dc71c5323c2af86b5535;hpb=8391dac264c19a729949cf4c8e9acb2109b85742;p=hildon diff --git a/hildon/hildon-pannable-area.c b/hildon/hildon-pannable-area.c index 86342e4..c05edb0 100644 --- a/hildon/hildon-pannable-area.c +++ b/hildon/hildon-pannable-area.c @@ -56,10 +56,13 @@ #define RATIO_TOLERANCE 0.000001 #define SCROLL_FADE_TIMEOUT 100 #define MOTION_EVENTS_PER_SECOND 25 -#define CURSOR_STOPPED_TIMEOUT 80 -#define MAX_SPEED_THRESHOLD 250 +#define CURSOR_STOPPED_TIMEOUT 200 +#define MAX_SPEED_THRESHOLD 280 #define PANNABLE_MAX_WIDTH 788 #define PANNABLE_MAX_HEIGHT 378 +#define ACCEL_FACTOR 27 +#define MIN_ACCEL_THRESHOLD 40 +#define FAST_CLICK 125 G_DEFINE_TYPE (HildonPannableArea, hildon_pannable_area, GTK_TYPE_BIN) @@ -78,12 +81,15 @@ struct _HildonPannableAreaPrivate { gboolean enabled; gboolean button_pressed; guint32 last_time; /* Last event time, to stop infinite loops */ + guint32 last_press_time; gint last_type; gboolean last_in; gboolean moved; gdouble vmin; gdouble vmax; gdouble vmax_overshooting; + gdouble accel_vel_x; + gdouble accel_vel_y; gdouble vfast_factor; gdouble decel; gdouble drag_inertia; @@ -97,6 +103,8 @@ struct _HildonPannableAreaPrivate { guint direction_error_margin; gdouble vel_x; gdouble vel_y; + gdouble old_vel_x; + gdouble old_vel_y; GdkWindow *child; gint child_width; gint child_height; @@ -198,6 +206,7 @@ static void hildon_pannable_area_set_property (GObject * object, guint property_id, const GValue * value, GParamSpec * pspec); +static void hildon_pannable_area_remove_timeouts (GtkWidget * widget); static void hildon_pannable_area_dispose (GObject * object); static void hildon_pannable_area_realize (GtkWidget * widget); static void hildon_pannable_area_unrealize (GtkWidget * widget); @@ -401,7 +410,7 @@ hildon_pannable_area_class_init (HildonPannableAreaClass * klass) "Maximum scroll velocity", "Maximum distance the child widget should scroll " "per 'frame', in pixels per frame.", - 0, G_MAXDOUBLE, 500, + 0, G_MAXDOUBLE, 3500, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); @@ -422,7 +431,7 @@ hildon_pannable_area_class_init (HildonPannableAreaClass * klass) "Minimum velocity that is considered 'fast': " "children widgets won't receive button presses. " "Expressed as a fraction of the maximum velocity.", - 0, 1, 0.02, + 0, 1, 0.01, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); @@ -432,7 +441,7 @@ hildon_pannable_area_class_init (HildonPannableAreaClass * klass) "Deceleration multiplier", "The multiplier used when decelerating when in " "acceleration scrolling mode.", - 0, 1.0, 0.93, + 0, 1.0, 0.85, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); @@ -472,7 +481,7 @@ hildon_pannable_area_class_init (HildonPannableAreaClass * klass) "Time before starting to fade the scrollbar", "Time the scrollbar is going to be visible if the widget is not in" "action in miliseconds", - 0, G_MAXUINT, 3000, + 0, G_MAXUINT, 1000, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); @@ -710,6 +719,7 @@ hildon_pannable_area_init (HildonPannableArea * area) priv->moved = FALSE; priv->button_pressed = FALSE; priv->last_time = 0; + priv->last_press_time = 0; priv->last_type = 0; priv->vscroll_visible = TRUE; priv->hscroll_visible = TRUE; @@ -718,9 +728,13 @@ hildon_pannable_area_init (HildonPannableArea * area) priv->overshot_dist_y = 0; priv->overshooting_y = 0; priv->overshooting_x = 0; + priv->accel_vel_x = 0; + priv->accel_vel_y = 0; priv->idle_id = 0; priv->vel_x = 0; priv->vel_y = 0; + priv->old_vel_x = 0; + priv->old_vel_y = 0; priv->scroll_indicator_alpha = 0.0; priv->scroll_indicator_timeout = 0; priv->motion_event_scroll_timeout = 0; @@ -983,21 +997,7 @@ hildon_pannable_area_dispose (GObject * object) HildonPannableAreaPrivate *priv = HILDON_PANNABLE_AREA (object)->priv; GtkWidget *child = gtk_bin_get_child (GTK_BIN (object)); - if (priv->idle_id) { - g_signal_emit (object, pannable_area_signals[PANNING_FINISHED], 0); - g_source_remove (priv->idle_id); - priv->idle_id = 0; - } - - if (priv->scroll_indicator_timeout){ - g_source_remove (priv->scroll_indicator_timeout); - priv->scroll_indicator_timeout = 0; - } - - if (priv->motion_event_scroll_timeout){ - g_source_remove (priv->motion_event_scroll_timeout); - priv->motion_event_scroll_timeout = 0; - } + hildon_pannable_area_remove_timeouts (GTK_WIDGET (object)); if (child) { g_signal_handlers_disconnect_by_func (child, @@ -1092,6 +1092,29 @@ hildon_pannable_area_realize (GtkWidget * widget) gdk_gc_copy (priv->scrollbars_gc, widget->style->fg_gc[GTK_STATE_INSENSITIVE]); } + +static void +hildon_pannable_area_remove_timeouts (GtkWidget * widget) +{ + HildonPannableAreaPrivate *priv = HILDON_PANNABLE_AREA (widget)->priv; + + if (priv->idle_id) { + g_signal_emit (widget, pannable_area_signals[PANNING_FINISHED], 0); + g_source_remove (priv->idle_id); + priv->idle_id = 0; + } + + if (priv->scroll_indicator_timeout){ + g_source_remove (priv->scroll_indicator_timeout); + priv->scroll_indicator_timeout = 0; + } + + if (priv->motion_event_scroll_timeout){ + g_source_remove (priv->motion_event_scroll_timeout); + priv->motion_event_scroll_timeout = 0; + } +} + static void hildon_pannable_area_unrealize (GtkWidget * widget) { @@ -1099,6 +1122,8 @@ hildon_pannable_area_unrealize (GtkWidget * widget) priv = HILDON_PANNABLE_AREA (widget)->priv; + hildon_pannable_area_remove_timeouts (widget); + if (priv->event_window != NULL) { gdk_window_set_user_data (priv->event_window, NULL); gdk_window_destroy (priv->event_window); @@ -1223,6 +1248,8 @@ hildon_pannable_area_size_allocate (GtkWidget * widget, if (child && GTK_WIDGET_VISIBLE (child)) { + hildon_pannable_area_check_scrollbars (HILDON_PANNABLE_AREA (widget)); + hildon_pannable_area_child_allocate_calculate (widget, allocation, &child_allocation); @@ -1237,6 +1264,13 @@ hildon_pannable_area_size_allocate (GtkWidget * widget, gtk_widget_size_allocate (child, &child_allocation); } + if (priv->vadjust->page_size >= 0) { + priv->accel_vel_y = MIN (priv->vmax, + priv->vadjust->upper/priv->vadjust->page_size*ACCEL_FACTOR); + priv->accel_vel_x = MIN (priv->vmax, + priv->hadjust->upper/priv->hadjust->page_size*ACCEL_FACTOR); + } + hv = priv->hadjust->value; vv = priv->vadjust->value; @@ -1602,9 +1636,11 @@ hildon_pannable_area_launch_fade_timeout (HildonPannableArea * area, if (!priv->scroll_indicator_timeout) priv->scroll_indicator_timeout = - gdk_threads_add_timeout (SCROLL_FADE_TIMEOUT, - (GSourceFunc) hildon_pannable_area_scroll_indicator_fade, - area); + gdk_threads_add_timeout_full (G_PRIORITY_HIGH_IDLE + 20, + SCROLL_FADE_TIMEOUT, + (GSourceFunc) hildon_pannable_area_scroll_indicator_fade, + area, + NULL); } static void @@ -1866,9 +1902,9 @@ hildon_pannable_area_get_topmost (GdkWindow * window, tx, ty, mask); if (!selected_window) { if (tx) - *tx = x; + *tx = x-wx; if (ty) - *ty = y; + *ty = y-wy; selected_window = child; } } else { @@ -1933,6 +1969,7 @@ hildon_pannable_area_button_press_cb (GtkWidget * widget, priv->scroll_indicator_alpha); priv->last_time = event->time; + priv->last_press_time = event->time; priv->last_type = 1; priv->scroll_to_x = -1; @@ -1961,6 +1998,8 @@ hildon_pannable_area_button_press_cb (GtkWidget * widget, priv->button_pressed = TRUE; /* Stop scrolling on mouse-down (so you can flick, then hold to stop) */ + priv->old_vel_x = priv->vel_x; + priv->old_vel_y = priv->vel_y; priv->vel_x = 0; priv->vel_y = 0; if (priv->idle_id) { @@ -1979,6 +2018,8 @@ hildon_pannable_area_button_press_cb (GtkWidget * widget, (gpointer) & priv->child); event = (GdkEventButton *) gdk_event_copy ((GdkEvent *) event); + /* remove the reference we added with the copy */ + g_object_unref (priv->event_window); event->x = x; event->y = y; priv->cx = x; @@ -2119,6 +2160,7 @@ hildon_pannable_axis_scroll (HildonPannableArea *area, gtk_widget_queue_resize (GTK_WIDGET (area)); } else { *vel = 0.0; + *scroll_to = -1; } } else if (dist > adjust->upper - adjust->page_size) { if (s) *s = FALSE; @@ -2133,6 +2175,7 @@ hildon_pannable_axis_scroll (HildonPannableArea *area, gtk_widget_queue_resize (GTK_WIDGET (area)); } else { *vel = 0.0; + *scroll_to = -1; } } else { if ((*scroll_to) != -1) { @@ -2243,7 +2286,8 @@ hildon_pannable_area_scroll (HildonPannableArea *area, &priv->overshooting_y, &priv->overshot_dist_y, &priv->scroll_to_y, priv->vovershoot_max, &sy); } else { - priv->vel_y = 0; + priv->vel_y = 0.0; + priv->scroll_to_y = -1; } if (hscroll_visible) { @@ -2251,7 +2295,8 @@ hildon_pannable_area_scroll (HildonPannableArea *area, &priv->overshooting_x, &priv->overshot_dist_x, &priv->scroll_to_x, priv->hovershoot_max, &sx); } else { - priv->vel_x = 0; + priv->vel_x = 0.0; + priv->scroll_to_x = -1; } if (hv != priv->hadjust->value) @@ -2287,6 +2332,10 @@ hildon_pannable_area_timeout (HildonPannableArea * area) return FALSE; } + hildon_pannable_area_scroll (area, priv->vel_x, priv->vel_y); + + gdk_window_process_updates (GTK_WIDGET (area)->window, FALSE); + if (!priv->button_pressed) { /* Decelerate gradually when pointer is raised */ if ((!priv->overshot_dist_y) && @@ -2331,10 +2380,6 @@ hildon_pannable_area_timeout (HildonPannableArea * area) return FALSE; } - hildon_pannable_area_scroll (area, priv->vel_x, priv->vel_y); - - gdk_window_process_updates (GTK_WIDGET (area)->window, FALSE); - return TRUE; } @@ -2390,9 +2435,10 @@ hildon_pannable_area_motion_event_scroll (HildonPannableArea *area, priv->motion_x = 0; priv->motion_y = 0; - priv->motion_event_scroll_timeout = gdk_threads_add_timeout - ((gint) (1000.0 / (gdouble) MOTION_EVENTS_PER_SECOND), - (GSourceFunc) hildon_pannable_area_motion_event_scroll_timeout, area); + priv->motion_event_scroll_timeout = gdk_threads_add_timeout_full + (G_PRIORITY_HIGH_IDLE + 20, + (gint) (1000.0 / (gdouble) MOTION_EVENTS_PER_SECOND), + (GSourceFunc) hildon_pannable_area_motion_event_scroll_timeout, area, NULL); } } @@ -2497,10 +2543,11 @@ hildon_pannable_area_check_move (HildonPannableArea *area, (priv->mode != HILDON_PANNABLE_AREA_MODE_AUTO)) { if (!priv->idle_id) - priv->idle_id = gdk_threads_add_timeout ((gint) - (1000.0 / (gdouble) priv->sps), - (GSourceFunc) - hildon_pannable_area_timeout, area); + priv->idle_id = gdk_threads_add_timeout_full + (G_PRIORITY_HIGH_IDLE + 20, + (gint)(1000.0 / (gdouble) priv->sps), + (GSourceFunc) + hildon_pannable_area_timeout, area, NULL); } } } @@ -2638,6 +2685,8 @@ hildon_pannable_area_motion_notify_cb (GtkWidget * widget, if (priv->child) { /* Send motion notify to child */ event = (GdkEventMotion *) gdk_event_copy ((GdkEvent *) event); + /* remove the reference we added with the copy */ + g_object_unref (priv->event_window); event->x = priv->cx + (event->x - priv->ix); event->y = priv->cy + (event->y - priv->iy); event->window = g_object_ref (priv->child); @@ -2676,6 +2725,7 @@ hildon_pannable_area_button_release_cb (GtkWidget * widget, gint x, y; gdouble dx, dy; GdkWindow *child; + gboolean force_fast = TRUE; if (((event->time == priv->last_time) && (priv->last_type == 3)) || (gtk_bin_get_child (GTK_BIN (widget)) == NULL) @@ -2725,6 +2775,34 @@ hildon_pannable_area_button_release_cb (GtkWidget * widget, priv->button_pressed = FALSE; + /* if widget was moving fast in the panning, increase speed even more */ + if ((event->time - priv->last_press_time < FAST_CLICK) && + ((ABS (priv->old_vel_x) > priv->vmin) || + (ABS (priv->old_vel_y) > priv->vmin)) && + ((ABS (priv->old_vel_x) > MIN_ACCEL_THRESHOLD) || + (ABS (priv->old_vel_y) > MIN_ACCEL_THRESHOLD))) + { + gint symbol = 0; + + if (priv->vel_x != 0) + symbol = ((priv->vel_x * priv->old_vel_x) > 0) ? 1 : -1; + + priv->vel_x = symbol * + (priv->old_vel_x + ((priv->old_vel_x > 0) ? priv->accel_vel_x + : -priv->accel_vel_x)); + + symbol = 0; + + if (priv->vel_y != 0) + symbol = ((priv->vel_y * priv->old_vel_y) > 0) ? 1 : -1; + + priv->vel_y = symbol * + (priv->old_vel_y + ((priv->old_vel_y > 0) ? priv->accel_vel_y + : -priv->accel_vel_y)); + + force_fast = FALSE; + } + if ((ABS (priv->vel_y) >= priv->vmin) || (ABS (priv->vel_x) >= priv->vmin)) { @@ -2739,16 +2817,21 @@ hildon_pannable_area_button_release_cb (GtkWidget * widget, priv->scroll_indicator_alpha = 1.0; - if (ABS (priv->vel_x) > MAX_SPEED_THRESHOLD) - priv->vel_x = (priv->vel_x > 0) ? priv->vmax : -priv->vmax; + if (force_fast) { + if ((ABS (priv->vel_x) > MAX_SPEED_THRESHOLD) && + (priv->accel_vel_x > MAX_SPEED_THRESHOLD)) + priv->vel_x = (priv->vel_x > 0) ? priv->accel_vel_x : -priv->accel_vel_x; - if (ABS (priv->vel_y) > MAX_SPEED_THRESHOLD) - priv->vel_y = (priv->vel_y > 0) ? priv->vmax : -priv->vmax; + if ((ABS (priv->vel_y) > MAX_SPEED_THRESHOLD) && + (priv->accel_vel_y > MAX_SPEED_THRESHOLD)) + priv->vel_y = (priv->vel_y > 0) ? priv->accel_vel_y : -priv->accel_vel_y; + } if (!priv->idle_id) - priv->idle_id = gdk_threads_add_timeout ((gint) (1000.0 / (gdouble) priv->sps), - (GSourceFunc) - hildon_pannable_area_timeout, widget); + priv->idle_id = gdk_threads_add_timeout_full (G_PRIORITY_HIGH_IDLE + 20, + (gint) (1000.0 / (gdouble) priv->sps), + (GSourceFunc) hildon_pannable_area_timeout, + widget, NULL); } else { if (priv->center_on_child_focus_pending) { hildon_pannable_area_center_on_child_focus (area); @@ -2779,6 +2862,8 @@ hildon_pannable_area_button_release_cb (GtkWidget * widget, event->x, event->y, &x, &y, GDK_BUTTON_RELEASE_MASK); event = (GdkEventButton *) gdk_event_copy ((GdkEvent *) event); + /* remove the reference we added with the copy */ + g_object_unref (priv->event_window); event->x = x; event->y = y; @@ -2996,7 +3081,7 @@ hildon_pannable_calculate_vel_factor (HildonPannableArea * self) fct += fct_i; } - priv->vel_factor = fct; + priv->vel_factor = fct; } /** @@ -3163,7 +3248,9 @@ hildon_pannable_area_scroll_to (HildonPannableArea *area, g_return_if_fail (x < width || y < height); if ((x > -1)&&(hscroll_visible)) { - priv->scroll_to_x = x - priv->hadjust->page_size/2; + priv->scroll_to_x = CLAMP (x - priv->hadjust->page_size/2, + priv->hadjust->lower, + priv->hadjust->upper - priv->hadjust->page_size); dist_x = priv->scroll_to_x - priv->hadjust->value; if (dist_x == 0) { priv->scroll_to_x = -1; @@ -3175,7 +3262,9 @@ hildon_pannable_area_scroll_to (HildonPannableArea *area, } if ((y > -1)&&(vscroll_visible)) { - priv->scroll_to_y = y - priv->vadjust->page_size/2; + priv->scroll_to_y = CLAMP (y - priv->vadjust->page_size/2, + priv->vadjust->lower, + priv->vadjust->upper - priv->vadjust->page_size); dist_y = priv->scroll_to_y - priv->vadjust->value; if (dist_y == 0) { priv->scroll_to_y = -1; @@ -3186,16 +3275,17 @@ hildon_pannable_area_scroll_to (HildonPannableArea *area, priv->scroll_to_y = y; } - if ((priv->scroll_to_y == -1) && (priv->scroll_to_y == -1)) { + if ((priv->scroll_to_y == -1) && (priv->scroll_to_x == -1)) { return; } hildon_pannable_area_launch_fade_timeout (area, 1.0); if (!priv->idle_id) - priv->idle_id = gdk_threads_add_timeout ((gint) (1000.0 / (gdouble) priv->sps), - (GSourceFunc) - hildon_pannable_area_timeout, area); + priv->idle_id = gdk_threads_add_timeout_full (G_PRIORITY_HIGH_IDLE + 20, + (gint) (1000.0 / (gdouble) priv->sps), + (GSourceFunc) hildon_pannable_area_timeout, + area, NULL); } /**