about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorStevan Andjelkovic <stevan.andjelkovic@strath.ac.uk>2012-01-03 23:02:20 +0100
committerStevan Andjelkovic <stevan.andjelkovic@strath.ac.uk>2012-01-03 23:02:20 +0100
commitcfd919ea2eb2fcfca2f2759cde43b1aeec539d84 (patch)
tree8e8ff7b721c362c7bd5408bdf0cb9c381bea4e47
parent70d1199aecf94acc6658f95884db5d64bcb3a443 (diff)
downloadxombrero-cfd919ea2eb2fcfca2f2759cde43b1aeec539d84.tar.gz
Favicons for compact tab + autoscroll
FS#214 and #144.

Thanks to Stefan Bolte (dwb browser) for relicensing his
javascript code for autoscroll!

ok marco@
-rw-r--r--autoscroll.js129
-rw-r--r--js-merge-helper.pl2
-rw-r--r--linux/Makefile4
-rw-r--r--settings.c30
-rw-r--r--xxxterm.118
-rw-r--r--xxxterm.c164
-rw-r--r--xxxterm.conf3
-rw-r--r--xxxterm.h4
8 files changed, 243 insertions, 111 deletions
diff --git a/autoscroll.js b/autoscroll.js
new file mode 100644
index 0000000..126b2e8
--- /dev/null
+++ b/autoscroll.js
@@ -0,0 +1,129 @@
+/* MIT/X Consortium License
+ *
+ * Copyright (c) 2011-2012 Stefan Bolte <portix@gmx.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+MouseAutoScroll = (function() {
+  const SCROLL_ICON="transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAi5QTFRFAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEAAAEAAAAAAAAAAAAAAAAAAAAAAAAA////PMNlIQAAAKR0Uk5TAAAAD2p/JQqN+74iBn34sRkDbvT+ohIBX+78kwxQ5/mEB0Pf9XMEM9XwYgCLxhBc1tvc9f7Uu756BgQZHSXC/WIFCQMJu/1cCbv9XAm7/VwJu/1eB7f+YQa1/mEGtf5hBrX+YQgpLzTC/m4RFAhm5+vr+f/i0NOQCILHECPD6lUw0PBmAj3a9nUESuP6hQgAWOv8lA0CZ/H/pBIFdvWxGghQZRvM0CN6AAAAAWJLR0S5OrgWYAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAUJJREFUOMuV0FNzREEQhuET27ZtOxvbtm3btm10bOfnBV0bnJ3Zqv1u3+diphlGsImIionz6xKSUiAtQ++ycvIAJwqKtK6krAJweqaqpk7MQhqaWgBwfnGpraNLAsJ6+p8drq5vbg0MjQjA2AS+d3f/8GhqZs7TLSyBu6fnFytrGzaw/enw+vYOdvZs4ODo5OyCwNXN3cPTiw28fXz9/BFwAgKDgkn/CAlFEBZOOVREJIKoaAqIiUUQF08BCYkIkpIpICUVQVo6BWRkIsjKpoCcXAR5+RRQUIigqJhUS0rLyisQVFZV19TygLr6hsYmBM0trW3tHWzQCf/W1c0GPb1/e18/7yMGBn/70PAI4ZmjY9w+PjFJ/ObUNPaZ2TnyHeYXFr/60vIK5VDM6to6wMbmFkPd9s4u7O0zfHZweHTMCLYPkhas1aCqNgQAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTEtMDQtMDdUMTE6Mjk6MzcrMDI6MDB8AZWGAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDExLTA0LTA3VDExOjI5OjM3KzAyOjAwDVwtOgAAAABJRU5ErkJggg==) no-repeat scroll center";
+  const SIZE = 32;
+  const OFFSET = 5;
+  var doc;
+  Math.sign = function(x) { return x >=0 ? 1  : -1; };
+  var span = null;
+  var x = 0;
+  var y = 0;
+  var ev = null;
+  var timerId = 0;
+  var cursorStyle = null;
+  function startTimer() {
+    timerId = window.setInterval(timer, 40);
+  }
+  function stopTimer () {
+    window.clearInterval(timerId);
+    timerId = 0;
+  }
+  function timer () {
+    if (ev) {
+      var scrollY = (ev.y - y);
+      var scrollX = (ev.x - x);
+      var b = scrollY > 0
+        && doc.documentElement.scrollHeight == (window.innerHeight + window.pageYOffset);
+      var r = scrollX > 0
+        && doc.documentElement.scrollWidth == (window.innerWidth + window.pageXOffset);
+      var l = scrollX < 0 && window.pageXOffset == 0;
+      var t = scrollY < 0 && window.pageYOffset == 0;
+      var offX = Math.abs(scrollX) < OFFSET;
+      var offY = Math.abs(scrollY) < OFFSET;
+      if ( timerId != 0
+          && (( b && r ) || ( b && l) || ( b && offX )
+            || ( t && r ) || ( t && l) || ( t && offX )
+            || (offY && r) || (offY && l) )) {
+              stopTimer();
+              return;
+            }
+      window.scrollBy(scrollX - Math.sign(scrollX) * OFFSET,
+          scrollY - Math.sign(scrollY) * OFFSET);
+    }
+  }
+  function mouseMove (e) {
+    if (timerId == 0) {
+      startTimer();
+    }
+    ev = e;
+  }
+  function init (e) {
+    doc = e.target.ownerDocument;
+    if (window.innerHeight >= doc.documentElement.scrollHeight
+        && window.innerWidth >= doc.documentElement.scrollWidth) {
+          return;
+        }
+    span = doc.createElement("div");
+    span.style.width = SIZE + "px";
+    span.style.height = SIZE + "px";
+    span.style.background = SCROLL_ICON;
+    span.style.left = e.x - (SIZE / 2) + "px";
+    span.style.top  = e.y - (SIZE / 2) + "px";
+    span.style.position = "fixed";
+    span.style.fontSize = SIZE + "px";
+    span.style.opacity = 0.6;
+    cursorStyle = doc.defaultView.getComputedStyle(doc.body, null).cursor;
+    doc.body.style.cursor = "move";
+    doc.body.appendChild(span);
+    doc.addEventListener('mousemove', mouseMove, false);
+    span = span;
+  }
+  function clear (e) {
+    doc.body.style.cursor = cursorStyle;
+    span.parentNode.removeChild(span);
+    doc.removeEventListener('mousemove', mouseMove, false);
+    stopTimer();
+    if (span)
+      span =  null;
+    if (ev)
+      ev = null;
+  }
+  function mouseUp (e) { /* Simulate click, click event does not work during scrolling */
+    if (Math.abs(e.x - x) < 5 && Math.abs(e.y - y) < 5) {
+      init(e);
+      window.removeEventListener('mouseup', mouseUp, false);
+    }
+  }
+  function mouseDown (e) {
+    var t = e.target;
+    if (ev.button == 0) {
+      if (_span) {
+        clear();
+      }
+    } else if (ev.button == 1) {
+      if (span) {
+        clear();
+      }
+      else if (!t.hasAttribute("href")
+          && !t.hasAttribute("onmousedown")
+          && !(t.hasAttribute("onclick"))) {
+        x = e.x;
+        y = e.y;
+        window.addEventListener('mouseup', mouseUp, false);
+      }
+    }
+  }
+  window.addEventListener('mousedown', mouseDown, false);
+})();
diff --git a/js-merge-helper.pl b/js-merge-helper.pl
index eb7e660..34216c5 100644
--- a/js-merge-helper.pl
+++ b/js-merge-helper.pl
@@ -50,7 +50,7 @@ while (@ARGV) {
 	my @fn = split /\//, $jsfile;
 	my $fn = pop @fn;
 	$fn =~ /^(.*)\.js$/;
-	
+
 	$define = "JS_".uc($1);
 	$define =~ s/\-/_/;
 
diff --git a/linux/Makefile b/linux/Makefile
index 077c8a1..d258507 100644
--- a/linux/Makefile
+++ b/linux/Makefile
@@ -19,8 +19,8 @@ CC?= gcc
 all: javascript.h xxxterm
 
 javascript.h: ../js-merge-helper.pl ../hinting.js
-	perl ../js-merge-helper.pl ../hinting.js ../input-focus.js > \
-	javascript.h
+	perl ../js-merge-helper.pl ../hinting.js ../input-focus.js \
+	../autoscroll.js > javascript.h
 
 xxxterm: $(OBJS)
 	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(LDADD)
diff --git a/settings.c b/settings.c
index cf6b59d..fd70b80 100644
--- a/settings.c
+++ b/settings.c
@@ -92,6 +92,9 @@ int		js_autorun_enabled = 1;
 int		edit_mode = XT_EM_HYBRID;
 int		userstyle_global = 0;
 int		auto_load_images = 1;
+int		enable_autoscroll = 0;
+int		enable_favicon_entry = 1;
+int		enable_favicon_tabs = 0;
 
 char		*cmd_font_name = NULL;
 char		*oops_font_name = NULL;
@@ -120,6 +123,9 @@ int		set_tab_style(struct settings *, char *);
 int		set_edit_mode(struct settings *, char *);
 int		set_work_dir(struct settings *, char *);
 int		set_auto_load_images(char *value);
+int		set_enable_autoscroll(char *value);
+int		set_enable_favicon_entry(char *value);
+int		set_enable_favicon_tabs(char *value);
 
 void		walk_mime_type(struct settings *, void (*)(struct settings *,
 		    char *, void *), void *);
@@ -315,6 +321,9 @@ struct settings		rs[] = {
 	{ "work_dir",			XT_S_STR, 0, NULL, NULL,&s_work_dir },
 	{ "xterm_workaround",		XT_S_INT, 0,		&xterm_workaround, NULL, NULL },
 	{ "auto_load_images",		XT_S_INT, 0, 		&auto_load_images, NULL, NULL, NULL, set_auto_load_images },
+	{ "enable_autoscroll",		XT_S_INT, 0, 		&enable_autoscroll, NULL, NULL, NULL, set_enable_autoscroll },
+	{ "enable_favicon_entry",	XT_S_INT, 0, 		&enable_favicon_entry, NULL, NULL, NULL, set_enable_favicon_entry },
+	{ "enable_favicon_tabs",	XT_S_INT, 0, 		&enable_favicon_tabs, NULL, NULL, NULL, set_enable_favicon_tabs },
 
 	/* font settings */
 	{ "cmd_font",			XT_S_STR, 0, NULL, &cmd_font_name, NULL },
@@ -1030,6 +1039,27 @@ set_auto_load_images(char *value)
 	return (0);
 }
 
+int
+set_enable_autoscroll(char *value)
+{
+	enable_autoscroll = atoi(value);
+	return (0);
+}
+
+int
+set_enable_favicon_entry(char *value)
+{
+	enable_favicon_entry = atoi(value);
+	return (0);
+}
+
+int
+set_enable_favicon_tabs(char *value)
+{
+	enable_favicon_tabs = atoi(value);
+	return (0);
+}
+
 void
 setup_proxy(char *uri)
 {
diff --git a/xxxterm.1 b/xxxterm.1
index 71486c4..c44d17b 100644
--- a/xxxterm.1
+++ b/xxxterm.1
@@ -995,10 +995,28 @@ Locations where files are downloaded to.
 This directory must exist and
 .Nm
 validates that during startup.
+.It Cm enable_autoscroll
+When enabled clicking MB3 will spawn the autoscroll ball, scrolling can
+then proceed by dragging the mouse away from the ball.
 .It Cm enable_cookie_whitelist
 When enabled all cookies must be in the whitelist or they are rejected.
 Additionally whitelisted cookies also enable HTML5 local storage for the
 domain.
+.It Cm enable_favicon_entry
+When enabled (the default)
+.Nm
+displays the favicon of the web page at the URI entry. This setting
+affects both
+.Cm normal
+and
+.Cm compact
+tabs.
+.It Cm enable_favicon_tabs
+When enabled (disabled by default)
+.Nm
+displays favicons at each tab. This setting only affects
+.Cm compact
+tabs.
 .It Cm enable_js_whitelist
 When enabled all domains must be in the js whitelist in order to run Java
 Script.
diff --git a/xxxterm.c b/xxxterm.c
index ba1773e..b5098b4 100644
--- a/xxxterm.c
+++ b/xxxterm.c
@@ -956,28 +956,6 @@ js_ref_to_string(JSContextRef context, JSValueRef ref)
 	return (s);
 }
 
-void
-disable_hints(struct tab *t)
-{
-	DNPRINTF(XT_D_JS, "%s: tab %d\n", __func__, t->tab_id);
-
-	run_script(t, "hints.clearHints();");
-	t->mode = XT_MODE_COMMAND;
-	t->new_tab = 0;
-}
-
-void
-enable_hints(struct tab *t)
-{
-	DNPRINTF(XT_D_JS, "%s: tab %d\n", __func__, t->tab_id);
-
-	if (t->new_tab)
-		run_script(t, "hints.createHints('', 'F');");
-	else
-		run_script(t, "hints.createHints('', 'f');");
-	t->mode = XT_MODE_HINT;
-}
-
 #define XT_JS_DONE		("done;")
 #define XT_JS_DONE_LEN		(strlen(XT_JS_DONE))
 #define XT_JS_INSERT		("insert;")
@@ -992,7 +970,7 @@ run_script(struct tab *t, char *s)
 	JSValueRef		val, exception;
 	char			*es;
 
-	DNPRINTF(XT_D_JS, "run_script: tab %d %s\n",
+	DNPRINTF(XT_D_JS, "%s: tab %d %s\n", __func__,
 	    t->tab_id, s == (char *)JS_HINTING ? "JS_HINTING" : s);
 
 	frame = webkit_web_view_get_main_frame(t->wv);
@@ -1003,12 +981,11 @@ run_script(struct tab *t, char *s)
 	    NULL, 0, &exception);
 	JSStringRelease(str);
 
-	DNPRINTF(XT_D_JS, "run_script: val %p\n", val);
+	DNPRINTF(XT_D_JS, "%s: val %p\n", __func__, val);
 	if (val == NULL) {
 		es = js_ref_to_string(ctx, exception);
 		if (es) {
-			/* show_oops(t, "script exception: %s", es); */
-			DNPRINTF(XT_D_JS, "run_script: exception %s\n", es);
+			DNPRINTF(XT_D_JS, "%s: exception %s\n", __func__, es);
 			g_free(es);
 		}
 		return (1);
@@ -1022,7 +999,7 @@ run_script(struct tab *t, char *s)
 			; /* do nothing */
 #endif
 		if (es) {
-			DNPRINTF(XT_D_JS, "run_script: val %s\n", es);
+			DNPRINTF(XT_D_JS, "%s: val %s\n", __func__, es);
 			g_free(es);
 		}
 	}
@@ -1030,6 +1007,28 @@ run_script(struct tab *t, char *s)
 	return (0);
 }
 
+void
+enable_hints(struct tab *t)
+{
+	DNPRINTF(XT_D_JS, "%s: tab %d\n", __func__, t->tab_id);
+
+	if (t->new_tab)
+		run_script(t, "hints.createHints('', 'F');");
+	else
+		run_script(t, "hints.createHints('', 'f');");
+	t->mode = XT_MODE_HINT;
+}
+
+void
+disable_hints(struct tab *t)
+{
+	DNPRINTF(XT_D_JS, "%s: tab %d\n", __func__, t->tab_id);
+
+	run_script(t, "hints.clearHints();");
+	t->mode = XT_MODE_COMMAND;
+	t->new_tab = 0;
+}
+
 int
 hint(struct tab *t, struct karg *args)
 {
@@ -2755,11 +2754,6 @@ done:
 int
 script_cmd(struct tab *t, struct karg *args)
 {
-	JSGlobalContextRef	ctx;
-	WebKitWebFrame		*frame;
-	JSStringRef		str;
-	JSValueRef		val, exception;
-	char			*es;
 	struct stat		sb;
 	FILE			*f = NULL;
 	char			*buf = NULL;
@@ -2783,38 +2777,8 @@ script_cmd(struct tab *t, struct karg *args)
 		goto done;
 	}
 
-	/* this code needs to be redone */
-	frame = webkit_web_view_get_main_frame(t->wv);
-	ctx = webkit_web_frame_get_global_context(frame);
-
-	str = JSStringCreateWithUTF8CString(buf);
-	val = JSEvaluateScript(ctx, str, JSContextGetGlobalObject(ctx),
-	    NULL, 0, &exception);
-	JSStringRelease(str);
-
-	DNPRINTF(XT_D_JS, "%s: val %p\n", __func__, val);
-	if (val == NULL) {
-		es = js_ref_to_string(ctx, exception);
-		if (es) {
-			show_oops(t, "script exception: %s", es);
-			g_free(es);
-		}
-		goto done;
-	} else {
-		es = js_ref_to_string(ctx, val);
-#if 0
-		/* return values */
-		if (!strncmp(es, XT_JS_DONE, XT_JS_DONE_LEN))
-			; /* do nothing */
-		if (!strncmp(es, XT_JS_INSERT, XT_JS_INSERT_LEN))
-			; /* do nothing */
-#endif
-		if (es) {
-			show_oops(t, "script complete return value: '%s'", es);
-			g_free(es);
-		} else
-			show_oops(t, "script complete: without a return value");
-	}
+	DNPRINTF(XT_D_JS, "%s: about to run script\n", __func__);
+	run_script(t, buf);
 
 done:
 	if (f)
@@ -3505,6 +3469,9 @@ free_favicon(struct tab *t)
 void
 xt_icon_from_name(struct tab *t, gchar *name)
 {
+	if (!enable_favicon_entry)
+		return;
+
 	gtk_entry_set_icon_from_icon_name(GTK_ENTRY(t->uri_entry),
 	    GTK_ENTRY_ICON_PRIMARY, "text-html");
 	if (show_url == 0)
@@ -3526,14 +3493,25 @@ xt_icon_from_pixbuf(struct tab *t, GdkPixbuf *pb)
 	else
 		pb_scaled = pb;
 
-	gtk_entry_set_icon_from_pixbuf(GTK_ENTRY(t->uri_entry),
-	    GTK_ENTRY_ICON_PRIMARY, pb_scaled);
-	if (show_url == 0)
-		gtk_entry_set_icon_from_pixbuf(GTK_ENTRY(t->sbe.statusbar),
+	if (enable_favicon_entry) {
+
+		/* Classic tabs. */
+		gtk_entry_set_icon_from_pixbuf(GTK_ENTRY(t->uri_entry),
 		    GTK_ENTRY_ICON_PRIMARY, pb_scaled);
-	else
-		gtk_entry_set_icon_from_icon_name(GTK_ENTRY(t->sbe.statusbar),
-		    GTK_ENTRY_ICON_PRIMARY, NULL);
+
+		/* Minimal tabs. */
+		if (show_url == 0) {
+			gtk_entry_set_icon_from_pixbuf(GTK_ENTRY(t->sbe.statusbar),
+			    GTK_ENTRY_ICON_PRIMARY, pb_scaled);
+		} else
+			gtk_entry_set_icon_from_icon_name(GTK_ENTRY(t->sbe.statusbar),
+			    GTK_ENTRY_ICON_PRIMARY, NULL);
+	}
+
+	/* XXX: Only supports the minimal tabs atm. */
+	if (enable_favicon_tabs)
+		gtk_image_set_from_pixbuf(GTK_IMAGE(t->tab_elems.favicon),
+		    pb_scaled);
 
 	if (pb_scaled != pb)
 		g_object_unref(pb_scaled);
@@ -3836,6 +3814,8 @@ notify_load_status_cb(WebKitWebView* wview, GParamSpec* pspec, struct tab *t)
 
 		show_ca_status(t, uri);
 		run_script(t, JS_HINTING);
+		if (enable_autoscroll)
+			run_script(t, JS_AUTOSCROLL);
 		break;
 
 	case WEBKIT_LOAD_FIRST_VISUALLY_NON_EMPTY_LAYOUT:
@@ -3953,11 +3933,6 @@ js_autorun(struct tab *t)
 	char			deff[PATH_MAX], hostf[PATH_MAX];
 	char			*js = NULL, *jsat, *domain = NULL;
 	FILE			*deffile = NULL, *hostfile = NULL;
-	JSGlobalContextRef	ctx;
-	WebKitWebFrame		*frame;
-	JSStringRef		str;
-	JSValueRef		val, exception;
-	char			*es;
 
 	if (js_autorun_enabled == 0)
 		return;
@@ -4025,39 +4000,9 @@ nofile:
 		}
 	}
 
-	/* this code needs to be redone */
-	frame = webkit_web_view_get_main_frame(t->wv);
-	ctx = webkit_web_frame_get_global_context(frame);
+	DNPRINTF(XT_D_JS, "%s: about to run script\n", __func__);
+	run_script(t, js);
 
-	str = JSStringCreateWithUTF8CString(js);
-	val = JSEvaluateScript(ctx, str, JSContextGetGlobalObject(ctx),
-	    NULL, 0, &exception);
-	JSStringRelease(str);
-
-	DNPRINTF(XT_D_JS, "%s: val %p\n", __func__, val);
-	if (val == NULL) {
-		es = js_ref_to_string(ctx, exception);
-		if (es) {
-			show_oops(t, "script exception: %s", es);
-			g_free(es);
-		}
-		goto done;
-	} else {
-		es = js_ref_to_string(ctx, val);
-		g_free(es);
-#if 0
-		/* return values */
-		if (!strncmp(es, XT_JS_DONE, XT_JS_DONE_LEN))
-			; /* do nothing */
-		if (!strncmp(es, XT_JS_INSERT, XT_JS_INSERT_LEN))
-			; /* do nothing */
-		if (es) {
-			show_oops(t, "script complete return value: '%s'", es);
-			g_free(es);
-		} else
-			show_oops(t, "script complete: without a return value");
-#endif
-	}
 done:
 	if (su)
 		soup_uri_free(su);
@@ -6518,6 +6463,7 @@ create_new_tab(char *title, struct undo *u, int focus, int position)
 
 	/* compact tab bar */
 	t->tab_elems.label = gtk_label_new(title);
+	t->tab_elems.favicon = gtk_image_new();
 	gtk_label_set_width_chars(GTK_LABEL(t->tab_elems.label), 1.0);
 	gtk_misc_set_alignment(GTK_MISC(t->tab_elems.label), 0.0, 0.0);
 	gtk_misc_set_padding(GTK_MISC(t->tab_elems.label), 4.0, 4.0);
@@ -6534,6 +6480,8 @@ create_new_tab(char *title, struct undo *u, int focus, int position)
 	gdk_color_parse(XT_COLOR_CT_SEPARATOR, &color);
 	gtk_widget_modify_bg(t->tab_elems.sep, GTK_STATE_NORMAL, &color);
 
+	gtk_box_pack_start(GTK_BOX(t->tab_elems.box), t->tab_elems.favicon, FALSE,
+	    FALSE, 0);
 	gtk_box_pack_start(GTK_BOX(t->tab_elems.box), t->tab_elems.label, TRUE,
 	    TRUE, 0);
 	gtk_box_pack_start(GTK_BOX(t->tab_elems.box), t->tab_elems.sep, FALSE,
diff --git a/xxxterm.conf b/xxxterm.conf
index 1958bee..9d566b5 100644
--- a/xxxterm.conf
+++ b/xxxterm.conf
@@ -35,6 +35,7 @@
 # save_global_history	= 1
 # color_visited_uris	= 0
 # guess_search		= 1
+# enable_autoscroll	= 1
 # session_autosave	= 1
 # history_autosave	= 1
 # autofocus_onload	= 1
@@ -45,6 +46,8 @@
 # auto_load_images	= 0
 # enable_localstorage	= 0
 # userstyle_global	= 1
+# enable_favicon_entry	= 0
+# enable_favicon_tabs	= 1
 
 # See http://www.xroxy.com/proxylist.php for a good list of open
 # proxies.
diff --git a/xxxterm.h b/xxxterm.h
index d30d986..d048cfd 100644
--- a/xxxterm.h
+++ b/xxxterm.h
@@ -152,6 +152,7 @@ struct tab {
 	GtkWidget		*tab_content;
 	struct {
 		GtkWidget	*label;
+		GtkWidget	*favicon;
 		GtkWidget	*eventbox;
 		GtkWidget	*box;
 		GtkWidget	*sep;
@@ -567,6 +568,9 @@ extern char	*tabbar_font_name;
 extern int	edit_mode;
 extern int	userstyle_global;
 extern int	auto_load_images;
+extern int	enable_autoscroll;
+extern int	enable_favicon_entry;
+extern int	enable_favicon_tabs;
 
 /* globals */
 extern char		*version;