diff -up surf-0.2/config.def.h surf-0.2-mouse/config.def.h
--- surf-0.2/config.def.h	2009-10-17 03:00:22.000000000 -0400
+++ surf-0.2-mouse/config.def.h	2009-10-24 22:01:47.797670719 -0400
@@ -35,6 +35,17 @@ static Key keys[] = {
     { 0,                    GDK_Return, hideuri,    { 0 },          UriBar },
 };
 
+static Button buttons[] = {
+  /* modifier             keyval      function    arg */
+  { GDK_BUTTON3_MASK,     3,          context,    { 0 } },
+  { 0,                    8,          navigate,   { .i = -1 } },
+  { 0,                    9,          navigate,   { .i = +1 } },
+  /* Example of chording.  Press right mouse while holding left mouse to nav forward */
+  { GDK_BUTTON1_MASK,     3,          navigate,   { .i = +1 } },
+  /* Press left mouse while holding right mouse to nav backward. */
+  { GDK_BUTTON3_MASK,     1,          navigate,   { .i = -1 } },
+};
+
 static Item items[] = {
     { "New Window",     newwindow, { .v = NULL } },
     { "Reload",         reload,    { .b = FALSE } },
diff -up surf-0.2/surf.c surf-0.2-mouse/surf.c
--- surf-0.2/surf.c	2009-10-17 03:00:22.000000000 -0400
+++ surf-0.2-mouse/surf.c	2009-10-24 22:04:44.682236188 -0400
@@ -30,7 +30,7 @@ union Arg {
 };
 
 typedef struct Client {
-	GtkWidget *win, *scroll, *vbox, *uribar, *searchbar, *indicator;
+        GtkWidget *win, *scroll, *vbox, *uribar, *searchbar, *indicator, *contextmenu;
 	GtkWidget **items;
 	WebKitWebView *view;
 	WebKitDownload *download;
@@ -60,6 +60,13 @@ typedef struct {
 	KeyFocus focus;
 } Key;
 
+typedef struct {
+  guint mod;
+  guint button;
+  void (*func)(Client *c, const Arg *arg);
+  const Arg arg;
+} Button;
+
 static Display *dpy;
 static Atom uriprop;
 static SoupCookieJar *cookiejar;
@@ -73,9 +80,10 @@ static char *progname;
 
 static const char *autouri(Client *c);
 static char *buildpath(const char *path);
+static gboolean buttonevent(WebKitWebView *v, GdkEventButton *ev, Client *c);
 static void cleanup(void);
 static void clipboard(Client *c, const Arg *arg);
-static void context(WebKitWebView *v, GtkMenu *m, Client *c);
+static void context(Client *c, const Arg *arg);
 static char *copystr(char **str, const char *src);
 static gboolean decidewindow(WebKitWebView *v, WebKitWebFrame *f, WebKitNetworkRequest *r, WebKitWebNavigationAction *n, WebKitWebPolicyDecision *p, Client *c);
 static void destroyclient(Client *c);
@@ -100,6 +108,7 @@ static Client *newclient(void);
 static void newwindow(Client *c, const Arg *arg);
 static WebKitWebView *createwindow(WebKitWebView *v, WebKitWebFrame *f, Client *c);
 static void pasteuri(GtkClipboard *clipboard, const char *text, gpointer d);
+static void populatepopup(WebKitWebView *v, GtkMenu *m, Client *c);
 static GdkFilterReturn processx(GdkXEvent *xevent, GdkEvent *event, gpointer d);
 static void print(Client *c, const Arg *arg);
 static void progresschange(WebKitWebView *v, gint p, Client *c);
@@ -155,6 +164,43 @@ buildpath(const char *path) {
 	return apath;
 }
 
+gboolean
+buttonevent(WebKitWebView *v, GdkEventButton *ev, Client *c) {
+  guint i;
+  gboolean processed = FALSE;
+  static guint maxpressed = 0;
+  static guint buttonspressed = 0;
+  updatewinid(c);
+  if(ev->type == GDK_BUTTON_PRESS) {
+    maxpressed++;
+    buttonspressed++;
+    for(i = 0; i < LENGTH(buttons); i++) {
+      if(ev->button == buttons[i].button &&
+	 CLEANMASK(ev->state) == buttons[i].mod &&
+	 buttons[i].func) {
+	buttons[i].func(c, &(buttons[i].arg));
+	processed = TRUE;
+      }
+    }
+  }
+  else { /* GDK_BUTTON_RELEASE */
+    buttonspressed--;
+      for(i = 0; i < LENGTH(buttons); i++) {
+	if(ev->button == buttons[i].button &&
+	   buttons[i].mod == CLEANMASK(ev->state) &&
+	   /* Prevents unintended release triggers while chording */
+	   (maxpressed == 1 || buttonspressed == 1) &&
+	   buttons[i].func) {
+	  buttons[i].func(c, &(buttons[i].arg));
+	  processed = TRUE;
+	}
+      }
+    if(buttonspressed == 0)
+      maxpressed = 0;
+  }
+  return processed;
+}
+
 void
 cleanup(void) {
 	while(clients)
@@ -176,19 +222,10 @@ clipboard(Client *c, const Arg *arg) {
 }
 
 void
-context(WebKitWebView *v, GtkMenu *m, Client *c) {
-	int i;
-	GtkContainer *parent;
-
-	gtk_widget_hide_all(GTK_WIDGET(m));
-	gtk_widget_show(GTK_WIDGET(m));
-	for(i = 0; i < LENGTH(items); i++) {
-		parent = GTK_CONTAINER(gtk_widget_get_parent(c->items[i]));
-		if(parent)
-			gtk_container_remove(parent, c->items[i]);
-		gtk_menu_shell_append(GTK_MENU_SHELL(m), c->items[i]);
-		gtk_widget_show(c->items[i]);
-	}
+context(Client *c, const Arg *arg) {
+  gtk_widget_show_all(c->contextmenu);
+  gtk_menu_popup(GTK_MENU(c->contextmenu), NULL, NULL, NULL,
+		 NULL, 0, gtk_get_current_event_time());
 }
 
 char *
@@ -205,17 +242,15 @@ copystr(char **str, const char *src) {
 
 void
 destroyclient(Client *c) {
-	int i;
 	Client *p;
 
 	gtk_widget_destroy(GTK_WIDGET(c->view));
+	gtk_widget_destroy(c->contextmenu);
 	gtk_widget_destroy(c->scroll);
 	gtk_widget_destroy(c->uribar);
 	gtk_widget_destroy(c->searchbar);
 	gtk_widget_destroy(c->vbox);
 	gtk_widget_destroy(c->win);
-	for(i = 0; i < LENGTH(items); i++)
-		gtk_widget_destroy(c->items[i]);
 	free(c->items);
 
 	for(p = clients; p && p->next != c; p = p->next);
@@ -457,10 +492,12 @@ newclient(void) {
 		die("Cannot malloc!\n");
 
 	/* contextmenu */
+	c->contextmenu = gtk_menu_new();
 	for(i = 0; i < LENGTH(items); i++) {
 		c->items[i] = gtk_menu_item_new_with_label(items[i].label);
 		g_signal_connect(G_OBJECT(c->items[i]), "activate",
 				G_CALLBACK(itemclick), c);
+		gtk_menu_shell_append(GTK_MENU_SHELL(c->contextmenu), c->items[i]);
 	}
 
 
@@ -485,7 +522,9 @@ newclient(void) {
 	g_signal_connect(G_OBJECT(c->view), "download-requested", G_CALLBACK(initdownload), c);
 	g_signal_connect(G_OBJECT(c->view), "window-object-cleared", G_CALLBACK(windowobjectcleared), c);
 	g_signal_connect(G_OBJECT(c->view), "focus-in-event", G_CALLBACK(focusview), c);
-	g_signal_connect(G_OBJECT(c->view), "populate-popup", G_CALLBACK(context), c);
+	g_signal_connect(G_OBJECT(c->view), "populate-popup", G_CALLBACK(populatepopup), c);
+	g_signal_connect(G_OBJECT(c->view), "button-press-event", G_CALLBACK(buttonevent), c);
+	g_signal_connect(G_OBJECT(c->view), "button-release-event", G_CALLBACK(buttonevent), c);
 
 	/* uribar */
 	c->uribar = gtk_entry_new();
@@ -580,6 +619,11 @@ pasteuri(GtkClipboard *clipboard, const 
 		loaduri((Client *) d, &arg);
 }
 
+void
+populatepopup(WebKitWebView *v, GtkMenu *m, Client *c) {
+  gtk_widget_destroy(GTK_WIDGET(m));
+}
+
 GdkFilterReturn
 processx(GdkXEvent *e, GdkEvent *event, gpointer d) {
 	Client *c = (Client *)d;
