diff --git a/apps/gui/bitmap/list.c b/apps/gui/bitmap/list.c
index 0da67c7..0e3651c 100644
--- a/apps/gui/bitmap/list.c
+++ b/apps/gui/bitmap/list.c
@@ -40,6 +40,7 @@
 #include "misc.h"
 #include "viewport.h"
 #include "statusbar-skinned.h"
+#include "appevents.h"
 
 #define ICON_PADDING 1
 
@@ -342,6 +343,31 @@ static int gui_synclist_touchscreen_scrollbar(struct gui_synclist * gui_list,
     return ACTION_NONE;
 }
 
+static typeof(current_tick) last_tick;
+static int last_y;
+static int delta_y;
+static int velocity;
+static struct timeout kinetic_scrolling_timeout;
+#define KINETIC_STEP (10)
+#define SIGN(x) (x > 0 ? 1 : -1)
+
+static int kinetic_scrolling_callback(struct timeout *tmo)
+{
+    struct gui_synclist *gui_list = (struct gui_synclist*) tmo->data;
+    int new_item = gui_list->selected_item + velocity;
+
+    if (velocity == 0)
+        return 0;
+
+    gui_synclist_select_item(gui_list, new_item);
+    send_event(GUI_EVENT_ACTIONUPDATE, NULL);
+
+    /* This isn't really kinetic.. */
+    velocity -= SIGN(velocity);
+
+    return velocity == 0 ? 0 : KINETIC_STEP;
+}
+
 unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list)
 {
     short x, y;
@@ -351,6 +377,7 @@ unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list)
     const int screen = display->screen_type;
     const int list_start_item = gui_list->start_item[screen];
     const struct viewport *list_text_vp = &list_text[screen];
+    const int nb_lines = viewport_get_nb_lines(&list_text[screen]);
 
     if (button == BUTTON_NONE)
         return ACTION_NONE;
@@ -359,10 +386,10 @@ unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list)
     {
         if (global_settings.scrollbar == SCROLLBAR_RIGHT &&
             x > list_text_vp->x + list_text_vp->width + SCROLLBAR_WIDTH)
-	{
+       {
             /* wider than the list's viewport, ignore it */
             return ACTION_NONE;
-	}
+       }
     }
 
     if (x < list_text_vp->x)
@@ -402,30 +429,68 @@ unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list)
         if (y > list_text_vp->y || button & BUTTON_REPEAT)
         {
             int line_height, actual_y;
-            
+
             actual_y = y - list_text_vp->y;
             line_height = font_get(gui_list->parent[screen]->font)->height;
             line = actual_y / line_height;
-            
-            /* Pressed below the list*/
+
+            /* Pressed below the list */
             if (list_start_item + line >= gui_list->nb_items)
                 return ACTION_NONE;
-            
-            /* Pressed a border */
-            if(UNLIKELY(actual_y % line_height == 0))
-                return ACTION_NONE;
-            
-            if (line != (gui_list->selected_item - list_start_item)
-                && button ^ BUTTON_REL)
+
+            /* Behaviour depends on whether there are more items on the screen
+               than it can show */
+            if(gui_list->nb_items > LCD_HEIGHT / line_height &&
+               button & BUTTON_REPEAT)
             {
-                if(button & BUTTON_REPEAT)
+                int move;
+
+                timeout_cancel(&kinetic_scrolling_timeout);
+
+                delta_y += last_y - actual_y;
+                move = delta_y / line_height;
+                delta_y -= move * line_height;
+
+                velocity = (last_y - actual_y) / (current_tick - last_tick);
+                move *= abs(velocity);
+                //printf("%ld %d %d\n", last_tick - current_tick, velocity, (last_y - actual_y) / line_height);
+
+                last_y = actual_y;
+                last_tick = current_tick;
+                if(move)
+                {
                     scrolling = true;
-                
-                gui_synclist_select_item(gui_list, list_start_item + line);
-                
-                return ACTION_REDRAW;
+                    int new_item = list_start_item + move;
+                    if (move > 0)
+                        new_item += nb_lines;
+                    if(new_item > 0 && new_item < gui_list->nb_items)
+                    {
+                        timeout_register(&kinetic_scrolling_timeout, kinetic_scrolling_callback, KINETIC_STEP, (intptr_t)gui_list);
+                        gui_synclist_select_item(gui_list, new_item);
+                        return ACTION_REDRAW;
+                    }
+                }
             }
-            
+            else
+            {
+                last_y = actual_y;
+
+                /* Pressed a border */
+                if(UNLIKELY(actual_y % line_height == 0))
+                    return ACTION_NONE;
+
+                if (line != (gui_list->selected_item - list_start_item)
+                    && button ^ BUTTON_REL)
+                {
+                    if(button & BUTTON_REPEAT)
+                        scrolling = true;
+
+                    gui_synclist_select_item(gui_list, list_start_item + line);
+
+                    return ACTION_REDRAW;
+                }
+            }
+
             /* This has the same effect as the icons do when the scrollbar
                is on the left (ie eliminate the chances an user enters/starts
                an item when he wanted to use the scrollbar, due to touchscreen
@@ -435,9 +500,10 @@ unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list)
                x > list_text_vp->x + list_text_vp->width -
                    get_icon_width(SCREEN_MAIN))
                 return ACTION_NONE;
-            
+
             if (button == (BUTTON_REPEAT|BUTTON_REL))
             {
+                delta_y = 0;
                 if(!scrolling)
                 {
                     /* Pen was hold on the same line as the 
diff --git a/firmware/export/config.h b/firmware/export/config.h
index a2ba3f9..38b77c2 100644
--- a/firmware/export/config.h
+++ b/firmware/export/config.h
@@ -880,6 +880,11 @@ Lyre prototype 1 */
 #endif
 #endif /* HAVE_USB_CHARGING_ENABLE && HAVE_USBSTACK */
 
+#if defined(HAVE_TOUCHSCREEN) && !defined(INCLUDE_TIMEOUT_API)
+/* Kinetic scrolling needs timeout API */
+#define INCLUDE_TIMEOUT_API
+#endif
+
 #if defined(HAVE_USBSTACK) || (CONFIG_STORAGE & STORAGE_NAND)
 #define STORAGE_GET_INFO
 #endif
