changeset 19:145bd87089e7

Implemented a new scheme of scroll-position remembering. This is one per visited page intead of one per url (this is more standard).
author jcid
date Wed, 24 Oct 2007 22:24:01 +0200
parents 0139bbc19df3
children 818792c8e2e0
files ChangeLog src/bw.c src/bw.h src/cache.c src/capi.c src/html.cc src/msg.h src/nav.c src/nav.h src/plain.cc src/uicmd.cc src/uicmd.hh src/web.cc
diffstat 13 files changed, 193 insertions(+), 96 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sun Oct 21 21:47:45 2007 +0200
+++ b/ChangeLog	Wed Oct 24 22:24:01 2007 +0200
@@ -31,6 +31,8 @@
  - Rewrote the DNS API and the Dpid start code inside Dillo.
  - Implemented Stop button to not only stop rendering but also networking.
  - Fixed the problem of scrolling position (remember position in a page).
+ - Implemented a new scheme of scroll-position remembering. This is one per
+   visited page intead of one per url (this is more standard).
    Patches: Jorge Arellano
 +- Connected signals to <li> elements (fixes links within lists).
  - Enabled text, background-color and geometry in preferences.
--- a/src/bw.c	Sun Oct 21 21:47:45 2007 +0200
+++ b/src/bw.c	Wed Oct 24 22:24:01 2007 +0200
@@ -50,10 +50,10 @@
    bws[num_bws++] = bw;
 
    /* Initialize nav_stack */
-   bw->nav_stack_size = 0;
-   bw->nav_stack_size_max = 16;
-   bw->nav_stack = NULL;
+   bw->nav_stack = dList_new(8);
    bw->nav_stack_ptr = -1;
+
+   /* Init expect */
    bw->nav_expecting = FALSE;
    bw->nav_expect_url = NULL;
 
@@ -101,7 +101,10 @@
             a_Url_free(dList_nth_data(bw->PageUrls, j));
          dList_free(bw->PageUrls);
 
-         dFree(bw->nav_stack);
+         for (j = 0; j < dList_length(bw->nav_stack); ++j)
+            dFree(dList_nth_data(bw->nav_stack, j));
+         dList_free(bw->nav_stack);
+
          dStr_free(bw->page_bugs, 1);
          dFree(bw);
          break;
--- a/src/bw.h	Sun Oct 21 21:47:45 2007 +0200
+++ b/src/bw.h	Wed Oct 24 22:24:01 2007 +0200
@@ -39,14 +39,12 @@
    Dlist *PageUrls;
 
    /* The navigation stack (holds indexes to history list) */
-   int *nav_stack;
-   int nav_stack_size;       /* [1 based] */
-   int nav_stack_size_max;
+   Dlist *nav_stack;
    /* 'nav_stack_ptr' refers to what's being displayed */
-   int nav_stack_ptr;        /* [0 based] */
+   int nav_stack_ptr;        /* [0 based; -1 = empty] */
    /* When the user clicks a link, the URL isn't pushed directly to history;
     * nav_expect_url holds it until the first answer-bytes are got. Only then
-    * it is sent to history and referenced in 'nav_stack[++nav_stack_ptr]' */
+    * it is sent to history and referenced at the top of nav_stack */
    DilloUrl *nav_expect_url;
    /* 'nav_expecting' is true if the last URL is being loaded for
     * the first time and has not gotten the dw yet. */
--- a/src/cache.c	Sun Oct 21 21:47:45 2007 +0200
+++ b/src/cache.c	Wed Oct 24 22:24:01 2007 +0200
@@ -831,7 +831,7 @@
 
    /* Trigger cleanup when there're no cache clients */
    if (dList_length(ClientQueue) == 0) {
-      MSG("  a_Dicache_cleanup()\n");
+      _MSG("  a_Dicache_cleanup()\n");
       a_Dicache_cleanup();
    }
 
--- a/src/capi.c	Sun Oct 21 21:47:45 2007 +0200
+++ b/src/capi.c	Wed Oct 24 22:24:01 2007 +0200
@@ -216,7 +216,7 @@
        (strchr(URL_STR(web->url), '?') || URL_DATA_(web->url))) {
       /* only allow dpi requests from dpi-generated urls */
       if (a_Nav_stack_size(web->bw)) {
-         referer = a_History_get_url(NAV_TOP(web->bw));
+         referer = a_History_get_url(NAV_TOP_UIDX(web->bw));
          if (dStrcasecmp(URL_SCHEME(referer), "dpi") == 0) {
             allow = TRUE;
          }
--- a/src/html.cc	Sun Oct 21 21:47:45 2007 +0200
+++ b/src/html.cc	Wed Oct 24 22:24:01 2007 +0200
@@ -231,7 +231,7 @@
 {
    BrowserWindow *bw = this->lb->bw;
 
-   MSG(" ** ");
+   _MSG(" ** ");
    if (link == -1 && x == -1 && y == -1) {
       _MSG(" Link  LEAVE  notify...\n");
       a_UIcmd_set_msg(bw, "");
@@ -537,7 +537,8 @@
  * Evaluates the ALIGN attribute (left|center|right|justify) and
  * sets the style at the top of the stack.
  */
-static void Html_tag_set_align_attr(DilloHtml *html, const char *tag, int tagsize)
+static void Html_tag_set_align_attr(DilloHtml *html, const char *tag, 
+                                    int tagsize)
 {
    const char *align, *charattr;
 
@@ -1034,7 +1035,8 @@
 /*
  * Parse spaces
  */
-static void Html_process_space(DilloHtml *html, const char *space, int spacesize)
+static void Html_process_space(DilloHtml *html, const char *space, 
+                               int spacesize)
 {
    int i, offset;
    DilloHtmlParseMode parse_mode = S_TOP(html)->parse_mode;
@@ -1592,7 +1594,7 @@
    if (html->InFlags & IN_HEAD) {
       /* title is only valid inside HEAD */
       a_UIcmd_set_page_title(html->linkblock->bw, html->Stash->str);
-      a_History_set_title(NAV_TOP(html->linkblock->bw), html->Stash->str);
+      a_History_set_title(NAV_TOP_UIDX(html->linkblock->bw),html->Stash->str);
    } else {
       MSG_HTML("the TITLE element must be inside the HEAD section\n");
    }
@@ -1829,7 +1831,8 @@
 /*
  * used by <TD> and <TH>
  */
-static void Html_tag_open_table_cell(DilloHtml *html, const char *tag, int tagsize,
+static void Html_tag_open_table_cell(DilloHtml *html,
+                                     const char *tag, int tagsize,
                                      TextAlignType text_align)
 {
 #ifdef USE_TABLES
@@ -2091,7 +2094,8 @@
  * todo: This is just a temporary fix while real frame support
  *       isn't finished. Imitates lynx/w3m's frames.
  */
-static void Html_tag_open_frameset (DilloHtml *html, const char *tag, int tagsize)
+static void Html_tag_open_frameset (DilloHtml *html,
+                                    const char *tag, int tagsize)
 {
    DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style);
    DW2TB(html->dw)->addText(dStrdup("--FRAME--"),
@@ -2134,7 +2138,8 @@
 /*
  * <BIG> | <SMALL>
  */
-static void Html_tag_open_big_small(DilloHtml *html, const char *tag, int tagsize)
+static void Html_tag_open_big_small(DilloHtml *html,
+                                    const char *tag, int tagsize)
 {
    int level;
 
@@ -2343,7 +2348,8 @@
 /*
  * <ADDRESS>
  */
-static void Html_tag_open_address(DilloHtml *html, const char *tag, int tagsize)
+static void Html_tag_open_address(DilloHtml *html,
+                                  const char *tag, int tagsize)
 {
    DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style);
    Html_set_top_font(html, NULL, 0, 2, 2);
@@ -2768,7 +2774,8 @@
 /*
  * <BLOCKQUOTE>
  */
-static void Html_tag_open_blockquote(DilloHtml *html, const char *tag, int tagsize)
+static void Html_tag_open_blockquote(DilloHtml *html, 
+                                     const char *tag, int tagsize)
 {
    DW2TB(html->dw)->addParbreak (9, S_TOP(html)->style);
    Html_add_indented(html, 40, 40, 9);
@@ -3074,8 +3081,8 @@
  */
 static int Html_tag_pre_excludes(int tag_idx)
 {
-   const char *es_set[] = {"img", "object", "applet", "big", "small", "sub", "sup",
-                     "font", "basefont", NULL};
+   const char *es_set[] = {"img", "object", "applet", "big", "small", "sub",
+                           "sup", "font", "basefont", NULL};
    static int ei_set[10], i;
 
    /* initialize array */
@@ -3826,7 +3833,8 @@
  * The ISINDEX tag is just a deprecated form of <INPUT type=text> with
  * implied FORM, afaics.
  */
-static void Html_tag_open_isindex(DilloHtml *html, const char *tag, int tagsize)
+static void Html_tag_open_isindex(DilloHtml *html,
+                                  const char *tag, int tagsize)
 {
 // // AL
 // DilloHtmlForm *form;
@@ -3920,7 +3928,8 @@
  * The textarea tag
  * (todo: It doesn't support wrapping).
  */
-static void Html_tag_open_textarea(DilloHtml *html, const char *tag, int tagsize)
+static void Html_tag_open_textarea(DilloHtml *html,
+                                   const char *tag, int tagsize)
 {
 // // AL
 // DilloHtmlLB *html_lb;
--- a/src/msg.h	Sun Oct 21 21:47:45 2007 +0200
+++ b/src/msg.h	Wed Oct 24 22:24:01 2007 +0200
@@ -15,8 +15,10 @@
 
 #define MSG(...)                                   \
    D_STMT_START {                                  \
-      if (prefs.show_msg)                          \
+      if (prefs.show_msg){                         \
          printf(__VA_ARGS__);                      \
+         fflush (stdout);                          \
+      }                                            \
    } D_STMT_END
 
 #define MSG_WARN(...)                              \
--- a/src/nav.c	Sun Oct 21 21:47:45 2007 +0200
+++ b/src/nav.c	Wed Oct 24 22:24:01 2007 +0200
@@ -34,6 +34,8 @@
 
 /*
  * Free memory used by this module
+ * TODO: this may be removed or called by a_Bw_free().
+  *      Currently is not called from anywhere.
  */
 void a_Nav_free(BrowserWindow *bw)
 {
@@ -53,6 +55,26 @@
 }
 
 /*
+ * Return the url index of i-th element in the stack. [-1 = Error]
+ */
+int a_Nav_get_uidx(BrowserWindow *bw, int i)
+{
+   nav_stack_item *nsi = dList_nth_data (bw->nav_stack, i);
+   return (nsi) ? nsi->url_idx : -1;
+}
+
+/*
+ * Return the url index of the top element in the stack.
+ */
+int a_Nav_get_top_uidx(BrowserWindow *bw)
+{
+   nav_stack_item *nsi;
+
+   nsi = dList_nth_data (bw->nav_stack, a_Nav_stack_size(bw) - 1);
+   return (nsi) ? nsi->url_idx : -1;
+}
+
+/*
  * Move the nav_stack pointer
  */
 static void Nav_stack_move_ptr(BrowserWindow *bw, int offset)
@@ -62,7 +84,7 @@
    dReturn_if_fail (bw != NULL);
    if (offset != 0) {
       nptr = bw->nav_stack_ptr + offset;
-      dReturn_if_fail (nptr >= 0 && nptr < bw->nav_stack_size);
+      dReturn_if_fail (nptr >= 0 && nptr < a_Nav_stack_size(bw));
       bw->nav_stack_ptr = nptr;
    }
 }
@@ -72,39 +94,59 @@
  */
 int a_Nav_stack_size(BrowserWindow *bw)
 {
-   return bw->nav_stack_size;
+   return dList_length(bw->nav_stack);
 }
 
 /*
- * Add an URL-index in the navigation stack.
+ * Add a nav_stack_item into the stack.
+ * If idx is not at the top, the stack is truncated at idx before adding.
  */
-static void Nav_stack_add(BrowserWindow *bw, int idx)
+static void Nav_stack_add(BrowserWindow *bw, int url_idx, int posx, int posy)
 {
+   int j;
+   void *data;
+   nav_stack_item *nsi;
+
    dReturn_if_fail (bw != NULL);
 
-   ++bw->nav_stack_ptr;
-   if (bw->nav_stack_ptr == bw->nav_stack_size) {
-      a_List_add(bw->nav_stack, bw->nav_stack_size, bw->nav_stack_size_max);
-      ++bw->nav_stack_size;
-   } else {
-      bw->nav_stack_size = bw->nav_stack_ptr + 1;
+   j = ++bw->nav_stack_ptr;
+   while (j < dList_length(bw->nav_stack)) {
+      data = dList_nth_data(bw->nav_stack, j);
+      dList_remove_fast (bw->nav_stack, data);
    }
-   bw->nav_stack[bw->nav_stack_ptr] = idx;
+   nsi = dNew(nav_stack_item, 1);
+   nsi->url_idx = url_idx;
+   nsi->posx = posx;
+   nsi->posy = posy;
+   dList_append (bw->nav_stack, nsi);
 }
 
 /*
- * Remove an URL-index from the navigation stack.
+ * Get the scrolling position of the current page.
  */
-static void Nav_stack_remove(BrowserWindow *bw, int idx)
+static void Nav_get_scroll_pos(BrowserWindow *bw, int *posx, int *posy)
 {
-   int sz = a_Nav_stack_size(bw);
+   nav_stack_item *nsi;
 
-   dReturn_if_fail (bw != NULL && idx >=0 && idx < sz);
+   if ((nsi = dList_nth_data (bw->nav_stack, a_Nav_stack_ptr(bw)))) {
+      *posx = nsi->posx;
+      *posy = nsi->posy;
+   } else {
+      *posx = *posy = 0;
+   }
+}
 
-   for (  ; idx < sz - 1; ++idx)
-      bw->nav_stack[idx] = bw->nav_stack[idx + 1];
-   if (bw->nav_stack_ptr == --bw->nav_stack_size)
-      --bw->nav_stack_ptr;
+/*
+ * Set the scrolling position of the current page.
+ */
+static void Nav_set_scroll_pos(BrowserWindow *bw, int idx, int posx, int posy)
+{
+   nav_stack_item *nsi;
+
+   if ((nsi = dList_nth_data (bw->nav_stack, idx))) {
+      nsi->posx = posx;
+      nsi->posy = posy;
+   }
 }
 
 /*
@@ -118,8 +160,11 @@
    dReturn_if_fail (bw != NULL);
 
    if ((i = a_Nav_stack_size(bw)) >= 2 &&
-       bw->nav_stack[i-2] == bw->nav_stack[i-1])
-         Nav_stack_remove(bw, i - 1);
+       NAV_UIDX(bw,i - 2) == NAV_UIDX(bw,i -1)) {
+      void *data = dList_nth_data (bw->nav_stack, i - 1);
+      dList_remove_fast (bw->nav_stack, data);
+      dFree(data);
+   }
 }
 
 
@@ -133,26 +178,23 @@
  */
 static void Nav_open_url(BrowserWindow *bw, const DilloUrl *url, int offset)
 {
-   DilloUrl *old_url = NULL;
+   DilloUrl *old_url;
    bool_t MustLoad;
-   int x, y, ClientKey;
+   int x, y, idx, ClientKey;
    DilloWeb *Web;
-   char *loc_text;
    bool_t ForceReload = (URL_FLAGS(url) & URL_E2EReload);
 
-   MSG("Nav_open_url: Url=>%s<\n", URL_STR_(url));
+   MSG("Nav_open_url: new url='%s'\n", URL_STR_(url));
 
    /* Get the url of the current page */
-   if (a_Nav_stack_ptr(bw) != -1)
-      old_url = a_History_get_url(NAV_TOP(bw));
-
-   /* Record current scrolling position
-    * (the strcmp check is necessary because of redirections) */
-   loc_text = a_UIcmd_get_location_text(bw);
-   if (old_url && !strcmp(URL_STR(old_url), loc_text)) {
+   idx = a_Nav_stack_ptr(bw);
+   old_url = a_History_get_url(idx);
+   /* Record current scrolling position */
+   if (old_url) {
       a_UIcmd_get_scroll_xy(bw, &x, &y);
-      _MSG("NAV: ScrollPosXY: x=%d y=%d\n",x,y);
-      a_Url_set_pos(old_url, x, y);
+      Nav_set_scroll_pos(bw, idx, x, y);
+      MSG("Nav_open_url: set scroll of '%s' to x=%d y=%d\n",
+          URL_STR(old_url), x, y);
    }
 
    /* Update navigation-stack-pointer (offset may be zero) */
@@ -164,7 +206,6 @@
       MustLoad |= (a_Url_cmp(old_url, url) != 0);
       MustLoad |= strcmp(URL_STR(old_url), a_UIcmd_get_location_text(bw));
    }
-   dFree(loc_text);
 
    if (MustLoad) {
       a_Bw_stop_clients(bw, BW_Root + BW_Img);
@@ -181,13 +222,13 @@
       }
    }
 
-   /* Jump to #anchor position */
-   if (URL_FRAGMENT_(url)) {
-      /* todo: push on stack */
-      char *pf = a_Url_decode_hex_str(URL_FRAGMENT_(url));
-      //a_Dw_render_layout_set_anchor(bw->render_layout, pf);
-      dFree(pf);
-   }
+   // /* Jump to #anchor position */
+   // if (URL_FRAGMENT_(url)) {
+   //    /* todo: push on stack */
+   //    char *pf = a_Url_decode_hex_str(URL_FRAGMENT_(url));
+   //    //a_Dw_render_layout_set_anchor(bw->render_layout, pf);
+   //    dFree(pf);
+   // }
 }
 
 /*
@@ -210,8 +251,9 @@
  */
 void a_Nav_expect_done(BrowserWindow *bw)
 {
-   int idx;
+   int url_idx, posx, posy;
    DilloUrl *url;
+   char *f;
 
    dReturn_if_fail(bw != NULL);
 
@@ -219,15 +261,28 @@
       url = bw->nav_expect_url;
       /* unset E2EReload before adding this url to history */
       a_Url_set_flags(url, URL_FLAGS(url) & ~URL_E2EReload);
-      idx = a_History_add_url(url);
-      Nav_stack_add(bw, idx);
-
+      url_idx = a_History_add_url(url);
+      Nav_stack_add(bw, url_idx, 0, 0);
+      /* Scroll to the origin unless there's a fragment part */
+      f = a_Url_decode_hex_str(URL_FRAGMENT_(url));
+      if (!f) {
+         a_UIcmd_set_scroll_xy(bw, 0, 0);
+      } else {
+         a_UIcmd_set_scroll_by_fragment(bw, f);
+         dFree(f);
+      }
       a_Url_free(url);
       bw->nav_expect_url = NULL;
       bw->nav_expecting = FALSE;
+   } else {
+      /* Scroll to were we were in this page */
+      Nav_get_scroll_pos(bw, &posx, &posy);
+      a_UIcmd_set_scroll_xy(bw, posx, posy);
+      MSG("Nav: expect_done scrolling to x=%d y=%d\n", posx, posy);
    }
    Nav_stack_clean(bw);
    a_UIcmd_set_buttons_sens(bw);
+   _MSG("Nav: a_Nav_expect_done\n");
 }
 
 /*
@@ -281,7 +336,7 @@
    a_Nav_cancel_expect(bw);
    if (--idx >= 0){
       a_UIcmd_set_msg(bw, "");
-      Nav_open_url(bw, a_History_get_url(NAV_IDX(bw,idx)), -1);
+      Nav_open_url(bw, a_History_get_url(NAV_UIDX(bw,idx)), -1);
    }
 }
 
@@ -295,7 +350,7 @@
    a_Nav_cancel_expect(bw);
    if (++idx < a_Nav_stack_size(bw)) {
       a_UIcmd_set_msg(bw, "");
-      Nav_open_url(bw, a_History_get_url(NAV_IDX(bw,idx)), +1);
+      Nav_open_url(bw, a_History_get_url(NAV_UIDX(bw,idx)), +1);
    }
 }
 
@@ -316,8 +371,8 @@
 
    a_Nav_cancel_expect(bw);
    if (a_Nav_stack_size(bw)) {
-      url = a_History_get_url(NAV_TOP(bw));
-      ReqURL = a_Url_dup(a_History_get_url(NAV_TOP(bw)));
+      url = a_History_get_url(NAV_TOP_UIDX(bw));
+      ReqURL = a_Url_dup(a_History_get_url(NAV_TOP_UIDX(bw)));
       /* Let's make reload be end-to-end */
       a_Url_set_flags(ReqURL, URL_FLAGS(ReqURL) | URL_E2EReload);
       /* This is an explicit reload, so clear the SpamSafe flag */
@@ -338,7 +393,7 @@
 
    a_Nav_cancel_expect(bw);
    if (a_Nav_stack_size(bw)) {
-      url = a_History_get_url(NAV_TOP(bw));
+      url = a_History_get_url(NAV_TOP_UIDX(bw));
       if (URL_FLAGS(url) & URL_Post) {
          /* Attempt to repost data, let's confirm... */
          choice = a_Dialog_choice3("Repost form data?",
@@ -362,10 +417,10 @@
    int idx = a_Nav_stack_ptr(bw) + offset;
 
    if (new_bw) {
-      a_Nav_push_nw(bw, a_History_get_url(NAV_IDX(bw,idx)));
+      a_Nav_push_nw(bw, a_History_get_url(NAV_UIDX(bw,idx)));
    } else {
       a_Nav_cancel_expect(bw);
-      Nav_open_url(bw, a_History_get_url(NAV_IDX(bw,idx)), offset);
+      Nav_open_url(bw, a_History_get_url(NAV_UIDX(bw,idx)), offset);
       a_UIcmd_set_buttons_sens(bw);
    }
 }
--- a/src/nav.h	Sun Oct 21 21:47:45 2007 +0200
+++ b/src/nav.h	Wed Oct 24 22:24:01 2007 +0200
@@ -3,10 +3,22 @@
 
 #include "bw.h"
 
+/*
+ * useful macros for the navigation stack
+ */
+#define NAV_UIDX(bw, i)       a_Nav_get_uidx(bw, i)
+#define NAV_TOP_UIDX(bw)      a_Nav_get_top_uidx(bw)
 
-/* useful macros for the navigation stack */
-#define NAV_IDX(bw, i)   (bw)->nav_stack[i]
-#define NAV_TOP(bw)      (bw)->nav_stack[(bw)->nav_stack_ptr]
+/*
+ * For back and forward navigation, each bw keeps an url index,
+ * and its scroll position.
+ */
+typedef struct _nav_stack_item nav_stack_item;
+struct _nav_stack_item
+{
+   int url_idx;
+   int posx, posy;
+};
 
 
 #ifdef __cplusplus
@@ -26,6 +38,8 @@
 void a_Nav_expect_done(BrowserWindow *bw);
 int a_Nav_stack_ptr(BrowserWindow *bw);
 int a_Nav_stack_size(BrowserWindow *bw);
+int a_Nav_get_uidx(BrowserWindow *bw, int i);
+int a_Nav_get_top_uidx(BrowserWindow *bw);
 
 void a_Nav_save_url(BrowserWindow *bw,
                     const DilloUrl *url, const char *filename);
--- a/src/plain.cc	Sun Oct 21 21:47:45 2007 +0200
+++ b/src/plain.cc	Wed Oct 24 22:24:01 2007 +0200
@@ -73,7 +73,7 @@
 //                         BrowserWindow *bw)
 //{
 //   if (event->button == 3) {
-//      a_Menu_popup_set_url(bw, a_History_get_url(NAV_TOP(bw)));
+//      a_Menu_popup_set_url(bw, a_History_get_url(NAV_TOP_UIDX(bw)));
 //      gtk_menu_popup(GTK_MENU(bw->menu_popup.over_page), NULL, NULL,
 //                     NULL, NULL, event->button, event->time);
 //      return TRUE;
--- a/src/uicmd.cc	Sun Oct 21 21:47:45 2007 +0200
+++ b/src/uicmd.cc	Wed Oct 24 22:24:01 2007 +0200
@@ -482,7 +482,7 @@
 {
    BrowserWindow *bw = (BrowserWindow*)vbw;
 
-   a_Menu_bugmeter_popup(bw, a_History_get_url(NAV_TOP(bw)));
+   a_Menu_bugmeter_popup(bw, a_History_get_url(NAV_TOP_UIDX(bw)));
 }
 
 /*
@@ -503,7 +503,7 @@
    // Fill the list
    i = a_Nav_stack_ptr(bw) + direction;
    for (j = 0 ; i >= 0 && i < a_Nav_stack_size(bw); i+=direction, j += 1) {
-      hlist[j] = NAV_IDX(bw,i);
+      hlist[j] = NAV_UIDX(bw,i);
    }
    hlist[j] = -1;
 
@@ -546,6 +546,30 @@
 }
 
 /*
+ * Set the scroll position ({x, y} offset pair)
+ */
+void a_UIcmd_set_scroll_xy(BrowserWindow *bw, int x, int y)
+{
+   Layout *layout = (Layout*)bw->render_layout;
+
+   if (layout) {
+      layout->scrollTo(HPOS_LEFT, VPOS_TOP, x, y, 0, 0);
+   }
+}
+
+/*
+ * Set the scroll position by fragment (from URL)
+ */
+void a_UIcmd_set_scroll_by_fragment(BrowserWindow *bw, const char *f)
+{
+   Layout *layout = (Layout*)bw->render_layout;
+
+   if (layout && f) {
+      layout->setAnchor(f);
+   }
+}
+
+/*
  * Get location's text
  */
 char *a_UIcmd_get_location_text(BrowserWindow *bw)
--- a/src/uicmd.hh	Sun Oct 21 21:47:45 2007 +0200
+++ b/src/uicmd.hh	Wed Oct 24 22:24:01 2007 +0200
@@ -45,6 +45,8 @@
 
 void a_UIcmd_get_wh(BrowserWindow *bw, int *w, int *h);
 void a_UIcmd_get_scroll_xy(BrowserWindow *bw, int *x, int *y);
+void a_UIcmd_set_scroll_xy(BrowserWindow *bw, int x, int y);
+void a_UIcmd_set_scroll_by_fragment(BrowserWindow *bw, const char *f);
 char *a_UIcmd_get_location_text(BrowserWindow *bw);
 void a_UIcmd_set_location_text(void *vbw, const char *text);
 void a_UIcmd_set_page_prog(BrowserWindow *bw, size_t nbytes, int cmd);
--- a/src/web.cc	Sun Oct 21 21:47:45 2007 +0200
+++ b/src/web.cc	Wed Oct 24 22:24:01 2007 +0200
@@ -93,18 +93,6 @@
       /* This method frees the old dw if any */
       layout->setWidget(dw);
 
-      /* Scroll to were we were in this page */
-      layout->scrollTo(HPOS_LEFT, VPOS_TOP,
-                       URL_POSX(Web->url), URL_POSY(Web->url), 0, 0);
-      /* If we're at the origin and there's a fragment, go there instead */
-      if (URL_POSX(Web->url) == 0 && URL_POSY(Web->url) == 0) {
-         char *f = a_Url_decode_hex_str(URL_FRAGMENT_(Web->url));
-         if (f) {
-            layout->setAnchor(f);
-            dFree(f);
-         }
-      }
-
       /* Clear the title bar for pages without a <TITLE> tag */
       a_UIcmd_set_page_title(Web->bw, "");
       a_UIcmd_set_location_text(Web->bw, URL_STR(Web->url));