Make sure that all timeouts in HildonBanner are removed
[hildon] / hildon / hildon-pannable-area.c
index 86342e4..c05edb0 100644 (file)
 #define RATIO_TOLERANCE 0.000001
 #define SCROLL_FADE_TIMEOUT 100
 #define MOTION_EVENTS_PER_SECOND 25
 #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 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)
 
 
 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 */
   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;
   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;
   gdouble vfast_factor;
   gdouble decel;
   gdouble drag_inertia;
@@ -97,6 +103,8 @@ struct _HildonPannableAreaPrivate {
   guint direction_error_margin;
   gdouble vel_x;
   gdouble vel_y;
   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;
   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);
                                                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);
 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.",
                                                        "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));
 
                                                        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.",
                                                        "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));
 
                                                        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.",
                                                        "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));
 
                                                        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",
                                                      "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));
 
                                                      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->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;
   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->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->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;
   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));
 
   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,
 
   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]);
 }
 
   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)
 {
 static void
 hildon_pannable_area_unrealize (GtkWidget * widget)
 {
@@ -1099,6 +1122,8 @@ hildon_pannable_area_unrealize (GtkWidget * widget)
 
   priv = HILDON_PANNABLE_AREA (widget)->priv;
 
 
   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);
   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)) {
 
 
   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);
     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);
     }
 
       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;
 
     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 =
 
   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
 }
 
 static void
@@ -1866,9 +1902,9 @@ hildon_pannable_area_get_topmost (GdkWindow * window,
                                                             tx, ty, mask);
         if (!selected_window) {
           if (tx)
                                                             tx, ty, mask);
         if (!selected_window) {
           if (tx)
-            *tx = x;
+            *tx = x-wx;
           if (ty)
           if (ty)
-            *ty = y;
+            *ty = y-wy;
           selected_window = child;
         }
       } else {
           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->scroll_indicator_alpha);
 
   priv->last_time = event->time;
+  priv->last_press_time = event->time;
   priv->last_type = 1;
 
   priv->scroll_to_x = -1;
   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->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) {
   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);
                               (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;
     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;
         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;
       }
     } 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;
         gtk_widget_queue_resize (GTK_WIDGET (area));
       } else {
         *vel = 0.0;
+        *scroll_to = -1;
       }
     } else {
       if ((*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->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) {
   }
 
   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->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)
   }
 
   if (hv != priv->hadjust->value)
@@ -2287,6 +2332,10 @@ hildon_pannable_area_timeout (HildonPannableArea * area)
     return FALSE;
   }
 
     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) &&
   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;
   }
 
     return FALSE;
   }
 
-  hildon_pannable_area_scroll (area, priv->vel_x, priv->vel_y);
-
-  gdk_window_process_updates (GTK_WIDGET (area)->window, FALSE);
-
   return TRUE;
 }
 
   return TRUE;
 }
 
@@ -2390,9 +2435,10 @@ hildon_pannable_area_motion_event_scroll (HildonPannableArea *area,
     priv->motion_x = 0;
     priv->motion_y = 0;
 
     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->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);
   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);
     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;
   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)
 
   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;
 
 
   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)) {
 
   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;
 
 
     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)
 
     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);
   } 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);
                                      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;
 
   event->x = x;
   event->y = y;
 
@@ -2996,7 +3081,7 @@ hildon_pannable_calculate_vel_factor (HildonPannableArea * self)
     fct += fct_i;
   }
 
     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)) {
   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;
     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)) {
   }
 
   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;
     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;
   }
 
     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)
     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);
 }
 
 /**
 }
 
 /**