diff --git a/ChangeLog b/ChangeLog
index d98653ae1de670c5741873ac5300de783d40f51e..d2428e91152caf4462ca24509159493b49a4b001 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -4,6 +4,7 @@ git - ?
 	- Fixed crash on browsing dirs with a small window size (#2991787)
 	- Fixed buffer overflow when some directories can't be scanned (#2981704)
 	- Improved browsing performance
+	- More intuitive multi-page browsing
 	- Various minor fixes
 
 1.6 - 2009-10-23
diff --git a/src/browser.c b/src/browser.c
index 3d43159c43b014c7b648b74de920d6001059b5b3..325d993ceb6e35728671c4c700db1eaca5c4d1eb 100644
--- a/src/browser.c
+++ b/src/browser.c
@@ -205,12 +205,10 @@ void browse_draw() {
     return;
 
   /* get start position */
-  t = dirlist_get(-1*((winrows)/2));
-  if(t == dirlist_next(NULL))
-    t = NULL;
+  t = dirlist_top(0);
 
   /* print the list to the screen */
-  for(i=0; (t=dirlist_next(t)) && i<winrows-3; i++) {
+  for(i=0; t && i<winrows-3; t=dirlist_next(t),i++) {
     browse_draw_item(t, 2+i);
     /* save the selected row number for later */
     if(t->flags & FF_BSEL)
@@ -284,28 +282,34 @@ int browse_key(int ch) {
     case KEY_UP:
     case 'k':
       dirlist_select(dirlist_get(-1));
+      dirlist_top(-1);
       info_start = 0;
       break;
     case KEY_DOWN:
     case 'j':
       dirlist_select(dirlist_get(1));
+      dirlist_top(1);
       info_start = 0;
       break;
     case KEY_HOME:
       dirlist_select(dirlist_next(NULL));
+      dirlist_top(2);
       info_start = 0;
       break;
     case KEY_LL:
     case KEY_END:
       dirlist_select(dirlist_get(1<<30));
+      dirlist_top(1);
       info_start = 0;
       break;
     case KEY_PPAGE:
       dirlist_select(dirlist_get(-1*(winrows-3)));
+      dirlist_top(-1);
       info_start = 0;
       break;
     case KEY_NPAGE:
       dirlist_select(dirlist_get(winrows-3));
+      dirlist_top(1);
       info_start = 0;
       break;
 
@@ -338,15 +342,19 @@ int browse_key(int ch) {
     case 10:
     case KEY_RIGHT:
     case 'l':
-      if(sel != NULL && sel->sub != NULL)
+      if(sel != NULL && sel->sub != NULL) {
         dirlist_open(sel->sub);
+        dirlist_top(-3);
+      }
       info_show = 0;
       break;
     case KEY_LEFT:
     case 'h':
     case '<':
-      if(sel != NULL && sel->parent->parent != NULL)
+      if(sel != NULL && sel->parent->parent != NULL) {
         dirlist_open(sel->parent);
+        dirlist_top(-3);
+      }
       info_show = 0;
       break;
 
diff --git a/src/calc.c b/src/calc.c
index 78afde0c217244060515985bdb84ae946e5724a1..7a738787c0c1ef7c450464a3acaea6121edd4ad8 100644
--- a/src/calc.c
+++ b/src/calc.c
@@ -509,6 +509,7 @@ int calc_process() {
       freedir(orig);
     }
     browse_init(root->sub);
+    dirlist_top(-3);
     return 0;
   }
 
diff --git a/src/delete.c b/src/delete.c
index b26ef54ec04091238f690715d8bff537b49be808..fdc4467978fd4349135292f1c9d416cf7db7f84e 100644
--- a/src/delete.c
+++ b/src/delete.c
@@ -236,6 +236,7 @@ void delete_process() {
   else {
     nextsel->flags |= FF_BSEL;
     browse_init(nextsel);
+    dirlist_top(-4);
   }
 }
 
diff --git a/src/dirlist.c b/src/dirlist.c
index 9e43eec3efb1b97c9a28fa554464f543085a91f6..2239914a9734d2adc4c847893fa2db526c61a867 100644
--- a/src/dirlist.c
+++ b/src/dirlist.c
@@ -40,7 +40,7 @@ int    dirlist_sort_desc   = 1,
 
 /* private state vars */
 struct dir dirlist_parent_alloc;
-struct dir *head, *head_real, *selected;
+struct dir *head, *head_real, *selected, *top = NULL;
 
 
 
@@ -282,6 +282,67 @@ void dirlist_select(struct dir *d) {
 }
 
 
+
+/* We need a hint in order to figure out which item should be on top:
+ *  0 = only get the current top, don't set anything
+ *  1 = selected has moved down
+ * -1 = selected has moved up
+ * -2 = selected = first item in the list (faster version of '1')
+ * -3 = top should be considered as invalid (after sorting or opening an other dir)
+ * -4 = an item has been deleted
+ * -5 = hidden flag has been changed
+ *
+ * Actions:
+ *  hint = -1 or -4 -> top = selected_is_visible ? top : selected
+ *  hint = -2 or -3 -> top = selected-(winrows-3)/2
+ *  hint =  1       -> top = selected_is_visible ? top : selected-(winrows-4)
+ *  hint =  0 or -5 -> top = selected_is_visible ? top : selected-(winrows-3)/2
+ *
+ * Regardless of the hint, the returned top will always be chosen such that the
+ * selected item is visible.
+ */
+struct dir *dirlist_top(int hint) {
+  struct dir *t;
+  int i = winrows-3, visible = 0;
+
+  if(hint == -2 || hint == -3)
+    top = NULL;
+
+  /* check whether the current selected item is within the visible window */
+  if(top) {
+    i = winrows-3;
+    t = dirlist_get(0);
+    while(t && i--) {
+      if(t == top) {
+        visible++;
+        break;
+      }
+      t = dirlist_prev(t);
+    }
+  }
+
+  /* otherwise, get a new top */
+  if(!visible)
+    top = hint == -1 || hint == -4 ? dirlist_get(0) :
+          hint ==  1               ? dirlist_get(-1*(winrows-4)) :
+                                     dirlist_get(-1*(winrows-3)/2);
+
+  /* also make sure that if the list is longer than the window and the last
+   * item is visible, that this last item is also the last on the window */
+  t = top;
+  i = winrows-3;
+  while(t && i--)
+    t = dirlist_next(t);
+  t = top;
+  do {
+    top = t;
+    t = dirlist_prev(t);
+  } while(t && i-- > 0);
+
+  return top;
+}
+
+
 void dirlist_set_sort(int col, int desc, int df) {
   /* update config */
   if(col != DL_NOCHANGE)
@@ -297,11 +358,13 @@ void dirlist_set_sort(int col, int desc, int df) {
     dirlist_parent->next = head_real;
   else
     head = head_real;
+  dirlist_top(-3);
 }
 
 
 void dirlist_set_hidden(int hidden) {
   dirlist_hidden = hidden;
   dirlist_fixup();
+  dirlist_top(-5);
 }
 
diff --git a/src/dirlist.h b/src/dirlist.h
index f3e7c585d1a8bc6df1a8e00c332766925b05d3a5..e8174d5f46763b029bb3f3e1efdd11f70fc3c277 100644
--- a/src/dirlist.h
+++ b/src/dirlist.h
@@ -49,6 +49,9 @@ struct dir *dirlist_next(struct dir *);
  * hidden items aren't considered */
 struct dir *dirlist_get(int i);
 
+/* Get/set the first visible item in the list on the screen */
+struct dir *dirlist_top(int hint);
+
 /* Set selected dir (must be in the currently opened directory, obviously) */
 void dirlist_select(struct dir *);