The attached patch sucks too much for mainline, but some may find it useful. I do.
The concept is a simple session system inspired by the one found in Firefox, where you can easily suspend surf and later continue from where you left off (across system boots). It also means you can easily continue when (not if) surf crashes. Because the system is so simple, only the visited URL is stored, not the deeper context (like history). This may be worth fixing, and would not be excessively hard.
diff -r f94ad8014e32 surf.c --- a/surf.c Wed May 12 16:40:00 2010 +0200 +++ b/surf.c Sun May 16 16:50:14 2010 +0200 @@ -37,6 +37,8 @@ WebKitDownload *download; char *title, *linkhover; const char *uri, *needle; + gchar *prevuri; + gboolean savesession; gint progress; struct Client *next; gboolean zoomed; @@ -113,6 +115,7 @@ static void runscript(Client *c, const Arg *arg); static void eval(Client *c, const Arg *arg); static void stop(Client *c, const Arg *arg); +static void suspend(Client *c, const Arg *arg); static void titlechange(WebKitWebView *v, WebKitWebFrame* frame, const char* title, Client *c); static void update(Client *c); static void updatedownload(WebKitDownload *o, GParamSpec *pspec, Client *c); @@ -156,6 +159,15 @@ } void +sessionupd(Client* c, char* cmd, char* uri) { + char* pid = malloc(20); + sprintf(pid, "%d", getpid()); + Arg arg = { .v = (const char *[]){ "surfsession", cmd, pid, uri, NULL } }; + spawn(c, &arg); + free(pid); +} + +void evalscript(WebKitWebFrame *frame, JSContextRef js, char *script, char* scriptname) { JSStringRef jsscript, jsscriptname; JSValueRef exception = NULL; @@ -264,6 +276,7 @@ p->next = c->next; else clients = c->next; + g_free(c->prevuri); free(c); if(clients == NULL) gtk_main_quit(); @@ -271,6 +284,9 @@ void destroywin(GtkWidget* w, Client *c) { + if (!c->savesession) { + sessionupd(c, "remove", geturi(c)); + } destroyclient(c); } @@ -452,11 +468,18 @@ void loadstatuschange(WebKitWebView *view, GParamSpec *pspec, Client *c) { + char* uri = geturi(c); switch(webkit_web_view_get_load_status (c->view)) { case WEBKIT_LOAD_COMMITTED: if(c->download) stop(c, NULL); setatom(c, uriprop, geturi(c)); + if(c->prevuri) { + sessionupd(c, "remove", c->prevuri); + g_free(c->prevuri); + } + sessionupd(c, "add", uri); + c->prevuri = g_strdup(uri); break; case WEBKIT_LOAD_FINISHED: c->progress = 0; @@ -609,6 +632,8 @@ c->download = NULL; c->title = NULL; c->next = clients; + c->prevuri = NULL; + c->savesession = FALSE; clients = c; if(showxid) { gdk_display_sync(gtk_widget_get_display(c->win)); @@ -867,6 +892,12 @@ } void +suspend(Client *c, const Arg *arg) { + c->savesession = TRUE; + gtk_widget_destroy(c->win); +} + +void titlechange(WebKitWebView *v, WebKitWebFrame *f, const char *t, Client *c) { c->title = copystr(&c->title, t); update(c);
The patch depends on the following rc shell script, which does the actual session handling.
#!/usr/bin/env rc # Simplistic session management for `surf`. # # Only URLs are remembered, no cookie, HTTP session, or browsing # history is stored. The script is supposed to be called # automatically by `surf` to update URL data, and by user commands to # resume them. File locking via `flock` is used to ensure atomicity # of modifications to `.surf/sessions`. # # An URL is considered an "orphan" if its listed PID no longer # refers to a live process. # # The first argument to `surfsession` indicates the action to be # taken, with the following actions being supported: # # * `add _pid_ _url_`: store `_url_` as being browsed by the process # `_pid_`. # # * `remove _pid_ _url_`: remove any `_url_` being browsed by `_pid_`. # # * `purge _url_`: remove any `_url_` being browse by any process. # # * `restore`: start `surf` for all orphan URLs. # # * `resume`: use `dmenu` to select an orphan URL, which will be # opened in `surf`. # Uses 9base/plan9port commands. 9base=$PLAN9 path=($9base/bin $path) # dmenu setup shamelessly cribbed from surf.sh. font='-*-terminus-medium-*-*-*-*-*-*-*-*-*-*-*' normbgcolor='#181818' normfgcolor='#e9e9e9' selbgcolor='#dd6003' selfgcolor='#e9e9e9' dmenu=(dmenu -fn $font -nb $normbgcolor -nf $normfgcolor \ -sb $selbgcolor -sf $selfgcolor -l 10 -b) fn escape { # Make URL safe as target for sed. echo $1 | sed 's,\[|\]|\?|\+|\*|\.|\(|\)|\\|\|\||/,\\&,g' } fn orphans { awk '{ if (system("test -d /proc/"$1)) { print $2 }}' $sessionfile } sessionfile=$home/.surf/sessions if (touch $sessionfile) { # We translate command foo to foo-locked surrounded by locking of # $sessionfile. switch ($1) { case add-locked echo $2 $3 >> $sessionfile case remove-locked {echo 'g/'^$2^' '^`{escape $3}^'/d'; echo 'w '^$sessionfile} | ed $sessionfile case purge-locked {echo 'g/'`{escape $2}^'/d'; echo 'w '^$sessionfile} | ed $sessionfile case restore-locked echo `{orphans} for (url in `{orphans}) { surf $url & } rm $sessionfile case resume-locked res=`{orphans|$dmenu} if (! ~ $status '') exit 1 $0 purge-locked $res && surf $res & # Don't deadlock on unknown commands... case *-locked exit 1 # Wrap a command in file locking and rerun the script. case * cmd=$1-locked shift flock -o $sessionfile -c $0^' '^$cmd^' '^$"* } } if not { echo 'Cannot write to '$sessionfile >[1=2] exit 1 }
-- \ Troels /\ Henriksen