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

Reply via email to