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