Reduced the fade delay of the pannable widget.
[hildon] / hildon / hildon-pannable-area.c
index 41cb124..8cd7fcd 100644 (file)
@@ -56,7 +56,7 @@
 #define RATIO_TOLERANCE 0.000001
 #define SCROLL_FADE_TIMEOUT 100
 #define MOTION_EVENTS_PER_SECOND 25
-#define CURSOR_STOPPED_TIMEOUT 80
+#define CURSOR_STOPPED_TIMEOUT 200
 #define MAX_SPEED_THRESHOLD 250
 #define PANNABLE_MAX_WIDTH 788
 #define PANNABLE_MAX_HEIGHT 378
@@ -78,6 +78,7 @@ 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;
@@ -97,6 +98,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 +201,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);
@@ -411,7 +415,7 @@ hildon_pannable_area_class_init (HildonPannableAreaClass * klass)
                                                        "Maximum scroll velocity when overshooting",
                                                        "Maximum distance the child widget should scroll "
                                                        "per 'frame', in pixels per frame when it overshoots after hitting the edge.",
-                                                       0, G_MAXDOUBLE, 20,
+                                                       0, G_MAXDOUBLE, 130,
                                                        G_PARAM_READWRITE |
                                                        G_PARAM_CONSTRUCT));
 
@@ -472,7 +476,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 +714,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;
@@ -721,6 +726,8 @@ hildon_pannable_area_init (HildonPannableArea * area)
   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 +990,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 +1085,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 +1115,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 +1241,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);
@@ -1602,9 +1622,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 +1888,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 +1955,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 +1984,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 +2004,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;
@@ -2165,7 +2192,7 @@ hildon_pannable_axis_scroll (HildonPannableArea *area,
           *vel *= -1;
         } else if ((*overshooting > 1) && (*vel < 0)) {
           /* we add the MIN in order to avoid very small speeds */
-          *vel = MIN ((((gdouble)*overshot_dist)*0.4) * -1, -2.0);
+          *vel = MIN (((((gdouble)*overshot_dist)*0.8) * -1), -10.0);
         }
 
         *overshot_dist = CLAMP (*overshot_dist + *vel, 0, overshoot_max);
@@ -2181,7 +2208,7 @@ hildon_pannable_axis_scroll (HildonPannableArea *area,
           *vel *= -1;
         } else if ((*overshooting > 1) && (*vel > 0)) {
           /* we add the MAX in order to avoid very small speeds */
-          *vel = MAX ((((gdouble)*overshot_dist)*0.4) * -1, 2.0);
+          *vel = MAX (((((gdouble)*overshot_dist)*0.8) * -1), 10.0);
         }
 
         *overshot_dist = CLAMP (*overshot_dist + (*vel), -overshoot_max, 0);
@@ -2333,6 +2360,8 @@ hildon_pannable_area_timeout (HildonPannableArea * area)
 
   hildon_pannable_area_scroll (area, priv->vel_x, priv->vel_y);
 
+  gdk_window_process_updates (GTK_WIDGET (area)->window, FALSE);
+
   return TRUE;
 }
 
@@ -2388,9 +2417,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);
   }
 }
 
@@ -2495,10 +2525,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);
     }
   }
 }
@@ -2636,6 +2667,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);
@@ -2674,6 +2707,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)
@@ -2713,16 +2747,40 @@ hildon_pannable_area_button_release_cb (GtkWidget * widget,
   /* If overshoot has been initiated with a finger down, on release set max speed */
   if (priv->overshot_dist_y != 0) {
     priv->overshooting_y = priv->bounce_steps; /* Hack to stop a bounce in the finger down case */
-    priv->vel_y = priv->vmax_overshooting;
+    priv->vel_y = priv->overshot_dist_y * 0.9;
   }
 
   if (priv->overshot_dist_x != 0) {
     priv->overshooting_x = priv->bounce_steps; /* Hack to stop a bounce in the finger down case */
-    priv->vel_x = priv->vmax_overshooting;
+    priv->vel_x = priv->overshot_dist_x * 0.9;
   }
 
   priv->button_pressed = FALSE;
 
+  /* if widget was moving fast in the panning, increase speed even more */
+  if ((event->time - priv->last_press_time < 200) &&
+      ((ABS (priv->old_vel_x) > priv->vmin) ||
+       (ABS (priv->old_vel_y) > priv->vmin)))
+    {
+      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->vmax : -priv->vmax));
+
+      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->vmax : -priv->vmax));
+
+      force_fast = FALSE;
+    }
+
   if  ((ABS (priv->vel_y) >= priv->vmin) ||
        (ABS (priv->vel_x) >= priv->vmin)) {
 
@@ -2737,16 +2795,19 @@ 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->vel_x = (priv->vel_x > 0) ? priv->vmax : -priv->vmax;
 
-    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->vel_y = (priv->vel_y > 0) ? priv->vmax : -priv->vmax;
+    }
 
     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);
@@ -2777,6 +2838,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;
 
@@ -3161,7 +3224,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;
@@ -3173,7 +3238,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;
@@ -3184,16 +3251,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);
 }
 
 /**