Hi,

modal browsing hasn't been first class citizen in surf. but given the
recent activity in adding features and webkit2 may be there is a
slightly better chance now.

attached is another rewrite of the modal browsing patch.

I find particularly appealing the fact that when implemented in the
browser code, it is independent of the JS loading policy. (AFAIR there
are alternative implementations as plug-ins which can be adapted and used
in .surf/script.js.) 

what the patch provides:

- command line switch to enable modes
- the default behaviour is unchanged
- when enabled, modes resemble 2 vi inspired modes: "insert mode" and "normal 
mode"
  - insert mode is equivalent to the default behaviour
  - in normal mode, the MODKEY is assumed pressed, i.e. the bindings are
    active without pressing MODKEY.

in addition:

- the patch shifts around some default bindings in config.def.h to make
  the new functionality more consistent.

cheers
--s
>From 043bdf0730f9acc6044b1876155a4b42563852e6 Mon Sep 17 00:00:00 2001
From: ssd <[email protected]>
Date: Sun, 3 Sep 2017 01:30:18 +0200
Subject: [surf] optional modal browsing
To: [email protected]

---
 config.def.h | 14 +++++++----
 surf.c       | 76 ++++++++++++++++++++++++++++++++++++++++++++----------------
 2 files changed, 65 insertions(+), 25 deletions(-)

diff --git a/config.def.h b/config.def.h
index 2e735bf..51c09a0 100644
--- a/config.def.h
+++ b/config.def.h
@@ -6,6 +6,8 @@ static char *styledir       = "~/.surf/styles/";
 static char *certdir        = "~/.surf/certificates/";
 static char *cachedir       = "~/.surf/cache/";
 static char *cookiefile     = "~/.surf/cookies.txt";
+static int modal            = 0;
+static int insert_mode      = 1;
 
 /* Webkit default features */
 /* Highest priority value will be used.
@@ -129,18 +131,20 @@ static SiteSpecific certs[] = {
  */
 static Key keys[] = {
 	/* modifier              keyval          function    arg */
+	{ 0,                     GDK_KEY_i,      insertmode, { .b = 1 } },
+	{ 0,                     GDK_KEY_Escape, insertmode, { .b = 0 } },
 	{ MODKEY,                GDK_KEY_g,      spawn,      SETPROP("_SURF_URI", "_SURF_GO", PROMPT_GO) },
 	{ MODKEY,                GDK_KEY_f,      spawn,      SETPROP("_SURF_FIND", "_SURF_FIND", PROMPT_FIND) },
 	{ MODKEY,                GDK_KEY_slash,  spawn,      SETPROP("_SURF_FIND", "_SURF_FIND", PROMPT_FIND) },
 
-	{ 0,                     GDK_KEY_Escape, stop,       { 0 } },
+	{ 0|GDK_SHIFT_MASK,      GDK_KEY_Escape, stop,       { 0 } },
 	{ MODKEY,                GDK_KEY_c,      stop,       { 0 } },
 
 	{ MODKEY|GDK_SHIFT_MASK, GDK_KEY_r,      reload,     { .i = 1 } },
 	{ MODKEY,                GDK_KEY_r,      reload,     { .i = 0 } },
 
-	{ MODKEY,                GDK_KEY_l,      navigate,   { .i = +1 } },
-	{ MODKEY,                GDK_KEY_h,      navigate,   { .i = -1 } },
+	{ MODKEY|GDK_SHIFT_MASK,   GDK_KEY_l,      navigate,   { .i = +1 } },
+	{ MODKEY|GDK_SHIFT_MASK,   GDK_KEY_h,      navigate,   { .i = -1 } },
 
 	/* Currently we have to use scrolling steps that WebKit2GTK+ gives us
 	 * d: step down, u: step up, r: step right, l:step left
@@ -149,8 +153,8 @@ static Key keys[] = {
 	{ MODKEY,                GDK_KEY_k,      scroll,     { .i = 'u' } },
 	{ MODKEY,                GDK_KEY_b,      scroll,     { .i = 'U' } },
 	{ MODKEY,                GDK_KEY_space,  scroll,     { .i = 'D' } },
-	{ MODKEY,                GDK_KEY_i,      scroll,     { .i = 'r' } },
-	{ MODKEY,                GDK_KEY_u,      scroll,     { .i = 'l' } },
+	{ MODKEY,                GDK_KEY_l,      scroll,     { .i = 'r' } },
+	{ MODKEY,                GDK_KEY_h,      scroll,     { .i = 'l' } },
 
 
 	{ MODKEY|GDK_SHIFT_MASK, GDK_KEY_j,      zoom,       { .i = -1 } },
diff --git a/surf.c b/surf.c
index 0f8b9c9..201d91f 100644
--- a/surf.c
+++ b/surf.c
@@ -222,6 +222,7 @@ static void togglefullscreen(Client *c, const Arg *a);
 static void togglecookiepolicy(Client *c, const Arg *a);
 static void toggleinspector(Client *c, const Arg *a);
 static void find(Client *c, const Arg *a);
+static void insertmode(Client *c, const Arg *a);
 
 /* Buttons */
 static void clicknavigate(Client *c, const Arg *a, WebKitHitTestResult *h);
@@ -294,7 +295,7 @@ static ParamName loadfinished[] = {
 void
 usage(void)
 {
-	die("usage: surf [-bBdDfFgGiIkKmMnNpPsStTvwxX]\n"
+	die("usage: surf [-bBdDfFgGiIkKmMnNpPsStTvVwxX]\n"
 	    "[-a cookiepolicies ] [-c cookiefile] [-C stylefile] [-e xid]\n"
 	    "[-r scriptfile] [-u useragent] [-z zoomlevel] [uri]\n");
 }
@@ -597,17 +598,18 @@ updatetitle(Client *c)
 	char *title;
 	const char *name = c->overtitle ? c->overtitle :
 	                   c->title ? c->title : "";
+	const char *mode = modal ? (insert_mode ? "+" : "_") : " ";
 
 	if (curconfig[ShowIndicators].val.i) {
 		gettogglestats(c);
 		getpagestats(c);
 
 		if (c->progress != 100)
-			title = g_strdup_printf("[%i%%] %s:%s | %s",
-			        c->progress, togglestats, pagestats, name);
+			title = g_strdup_printf("[%i%%] %s%s:%s | %s",
+			        c->progress, mode, togglestats, pagestats, name);
 		else
-			title = g_strdup_printf("%s:%s | %s",
-			        togglestats, pagestats, name);
+			title = g_strdup_printf("%s%s:%s | %s",
+			        mode, togglestats, pagestats, name);
 
 		gtk_window_set_title(GTK_WINDOW(c->win), title);
 		g_free(title);
@@ -903,9 +905,9 @@ setstyle(Client *c, const char *file)
 	webkit_user_content_manager_add_style_sheet(
 	    webkit_web_view_get_user_content_manager(c->view),
 	    webkit_user_style_sheet_new(style,
-	    WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES,
-	    WEBKIT_USER_STYLE_LEVEL_USER,
-	    NULL, NULL));
+	        WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES,
+	        WEBKIT_USER_STYLE_LEVEL_USER,
+	        NULL, NULL));
 
 	g_free(style);
 }
@@ -1249,6 +1251,45 @@ processx(GdkXEvent *e, GdkEvent *event, gpointer d)
 	return GDK_FILTER_CONTINUE;
 }
 
+void
+insertmode(Client *c, const Arg *a)
+{
+	if (modal) {
+		insert_mode = (a->i);
+		updatetitle(c);
+	}
+}
+
+gboolean
+processkeypress(GdkEvent *e, Client *c)
+{
+	int i, statematches, isstartinsert, keymatches;
+	guint simulatemod, ismodbinding;
+
+	for (i = 0; i < LENGTH(keys); ++i) {
+		/* if not in insert mode, pretend MODKEY was pressed */
+		ismodbinding = (MODKEY & keys[i].mod);
+		simulatemod = (!insert_mode && ismodbinding) ? MODKEY : 0;
+		statematches = keys[i].mod == (e->key.state | simulatemod);
+
+		keymatches = gdk_keyval_to_lower(e->key.keyval)
+			  == gdk_keyval_to_lower(keys[i].keyval);
+
+		if (keymatches && statematches && keys[i].func) {
+			updatewinid(c);
+
+			/* ignore starting insert mode if already in */
+			isstartinsert = (keys[i].func == insertmode)
+				&& (keys[i].arg.i == 1);
+			if (insert_mode && isstartinsert) return FALSE;
+
+			keys[i].func(c, &(keys[i].arg));
+			return TRUE;
+		}
+	}
+	return FALSE;
+}
+
 gboolean
 winevent(GtkWidget *w, GdkEvent *e, Client *c)
 {
@@ -1260,18 +1301,9 @@ winevent(GtkWidget *w, GdkEvent *e, Client *c)
 		updatetitle(c);
 		break;
 	case GDK_KEY_PRESS:
-		if (!curconfig[KioskMode].val.i) {
-			for (i = 0; i < LENGTH(keys); ++i) {
-				if (gdk_keyval_to_lower(e->key.keyval) ==
-				    keys[i].keyval &&
-				    CLEANMASK(e->key.state) == keys[i].mod &&
-				    keys[i].func) {
-					updatewinid(c);
-					keys[i].func(c, &(keys[i].arg));
-					return TRUE;
-				}
-			}
-		}
+		if (!curconfig[KioskMode].val.i)
+			if (processkeypress(e, c)) return TRUE;
+		break;
 	case GDK_LEAVE_NOTIFY:
 		c->overtitle = NULL;
 		updatetitle(c);
@@ -2012,6 +2044,10 @@ main(int argc, char *argv[])
 		break;
 	case 'v':
 		die("surf-"VERSION", see LICENSE for © details\n");
+	case 'V':
+		modal = 1;
+		insert_mode = 0;
+		break;
 	case 'w':
 		showxid = 1;
 		break;
-- 
2.13.2

Reply via email to