commit 0d237d63a804116d6a6155e8125d35137c5840c9
parent e4b120452ac0427a83ed05b7de14299f7b09618d
Author: Zach Rice <bynxmusic@gmail.com>
Date: Mon, 18 May 2026 19:48:58 -0400
Add scroll-to-top/bottom (Ctrl+,/.), fix empty URI download crash
Diffstat:
5 files changed, 157 insertions(+), 1 deletion(-)
diff --git a/config.def.h b/config.def.h
@@ -183,6 +183,9 @@ static Key keys[] = {
{ MODKEY, GDK_KEY_i, scrollh, { .i = +10 } },
{ MODKEY, GDK_KEY_u, scrollh, { .i = -10 } },
+ /* scroll to top/bottom of page (vim gg / G) */
+ { MODKEY, GDK_KEY_comma, scrolltop, { 0 } },
+ { MODKEY, GDK_KEY_period, scrollbottom, { 0 } },
{ MODKEY|GDK_SHIFT_MASK, GDK_KEY_j, zoom, { .i = -1 } },
{ MODKEY|GDK_SHIFT_MASK, GDK_KEY_k, zoom, { .i = +1 } },
diff --git a/patches/surf-download-emptyuri.patch b/patches/surf-download-emptyuri.patch
@@ -0,0 +1,23 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Zach Rice <bynxmusic@gmail.com>
+Date: Sun, 18 May 2026 00:00:00 +0000
+Subject: [PATCH] Skip download when URI is empty
+
+WebKit sometimes fires a download response with an empty URI (e.g.
+on YouTube). This passes an empty string to curl which errors out.
+Guard against it by returning early.
+
+diff --git a/surf.c b/surf.c
+--- a/surf.c
++++ b/surf.c
+@@ -1819,6 +1819,10 @@ void
+ download(Client *c, WebKitURIResponse *r)
+ {
+ const char *dluri = webkit_uri_response_get_uri(r);
++
++ if (!dluri || !dluri[0])
++ return;
++
+ Arg a = (Arg)DOWNLOAD(dluri, geturi(c));
+ spawn(c, &a);
+ }
diff --git a/patches/surf-hardwareaccel.patch b/patches/surf-hardwareaccel.patch
@@ -0,0 +1,62 @@
+diff --git a/config.def.h b/config.def.h
+index ea29f8c..545351a 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -30,6 +30,7 @@ static Parameter defconfig[ParameterLast] = {
+ [FileURLsCrossAccess] = { { .i = 0 }, },
+ [FontSize] = { { .i = 12 }, },
+ [Geolocation] = { { .i = 0 }, },
++ [HardwareAcceleration] = { { .i = 1 }, },
+ [HideBackground] = { { .i = 0 }, },
+ [Inspector] = { { .i = 1 }, },
+ [JavaScript] = { { .i = 1 }, },
+diff --git a/surf.c b/surf.c
+index 39ed548..11af08d 100644
+--- a/surf.c
++++ b/surf.c
+@@ -65,6 +65,7 @@ typedef enum {
+ FileURLsCrossAccess,
+ FontSize,
+ Geolocation,
++ HardwareAcceleration,
+ HideBackground,
+ Inspector,
+ JavaScript,
+@@ -288,6 +289,7 @@ static ParamName loadcommitted[] = {
+ DefaultCharset,
+ FontSize,
+ Geolocation,
++ HardwareAcceleration,
+ HideBackground,
+ Inspector,
+ // KioskMode,
+@@ -685,6 +687,7 @@ gettogglestats(Client *c)
+ togglestats[4] = curconfig[LoadImages].val.i ? 'I' : 'i';
+ togglestats[5] = curconfig[JavaScript].val.i ? 'S' : 's';
+ togglestats[6] = curconfig[Style].val.i ? 'M' : 'm';
++ togglestats[7] = curconfig[HardwareAcceleration].val.i ? 'A' : 'a';
+ togglestats[8] = curconfig[Certificate].val.i ? 'X' : 'x';
+ togglestats[9] = curconfig[StrictTLS].val.i ? 'T' : 't';
+ }
+@@ -810,6 +813,11 @@ setparameter(Client *c, int refresh, ParamName p, const Arg *a)
+ case Geolocation:
+ refresh = 0;
+ break;
++ case HardwareAcceleration:
++ webkit_settings_set_hardware_acceleration_policy(c->settings, a->i ?
++ WEBKIT_HARDWARE_ACCELERATION_POLICY_ON_DEMAND :
++ WEBKIT_HARDWARE_ACCELERATION_POLICY_NEVER);
++ break;
+ case HideBackground:
+ if (a->i)
+ webkit_web_view_set_background_color(c->view, &bgcolor);
+@@ -1177,6 +1185,9 @@ newview(Client *c, WebKitWebView *rv)
+ "enable-site-specific-quirks", curconfig[SiteQuirks].val.i,
+ "enable-smooth-scrolling", curconfig[SmoothScrolling].val.i,
+ "enable-webgl", curconfig[WebGL].val.i,
++ "hardware-acceleration-policy", curconfig[HardwareAcceleration].val.i ?
++ WEBKIT_HARDWARE_ACCELERATION_POLICY_ON_DEMAND :
++ WEBKIT_HARDWARE_ACCELERATION_POLICY_NEVER,
+ "media-playback-requires-user-gesture", curconfig[MediaManualPlay].val.i,
+ NULL);
+ /* For more interesting settings, have a look at
diff --git a/patches/surf-scrolltobounds.patch b/patches/surf-scrolltobounds.patch
@@ -0,0 +1,49 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Zach Rice <bynxmusic@gmail.com>
+Date: Sun, 18 May 2026 00:00:00 +0000
+Subject: [PATCH] Add scroll-to-top and scroll-to-bottom (gg/G)
+
+Adds scrolltop() and scrollbottom() functions using evalscript()
+to run window.scrollTo() directly. Bound to MODKEY+comma and
+MODKEY+period by default.
+
+diff --git a/config.def.h b/config.def.h
+--- a/config.def.h
++++ b/config.def.h
+@@ -183,6 +183,9 @@ static Key keys[] = {
+ { MODKEY, GDK_KEY_i, scrollh, { .i = +10 } },
+ { MODKEY, GDK_KEY_u, scrollh, { .i = -10 } },
+
++ /* scroll to top/bottom of page (vim gg / G) */
++ { MODKEY, GDK_KEY_comma, scrolltop, { 0 } },
++ { MODKEY, GDK_KEY_period, scrollbottom, { 0 } },
+
+ { MODKEY|GDK_SHIFT_MASK, GDK_KEY_j, zoom, { .i = -1 } },
+diff --git a/surf.c b/surf.c
+--- a/surf.c
++++ b/surf.c
+@@ -236,6 +236,8 @@ static void zoom(Client *c, const Arg *a);
+ static void scrollv(Client *c, const Arg *a);
+ static void scrollh(Client *c, const Arg *a);
++static void scrolltop(Client *c, const Arg *a);
++static void scrollbottom(Client *c, const Arg *a);
+ static void navigate(Client *c, const Arg *a);
+ static void stop(Client *c, const Arg *a);
+@@ -1953,6 +1955,16 @@ scrollh(Client *c, const Arg *a)
+ msgext(c, 'h', a);
+ }
+
++void
++scrolltop(Client *c, const Arg *a)
++{
++ evalscript(c, "window.scrollTo(0,0);");
++}
++
++void
++scrollbottom(Client *c, const Arg *a)
++{
++ evalscript(c, "window.scrollTo(0,document.body.scrollHeight);");
++}
++
+ void
+ navigate(Client *c, const Arg *a)
diff --git a/surf.c b/surf.c
@@ -235,6 +235,8 @@ static void clipboard(Client *c, const Arg *a);
static void zoom(Client *c, const Arg *a);
static void scrollv(Client *c, const Arg *a);
static void scrollh(Client *c, const Arg *a);
+static void scrolltop(Client *c, const Arg *a);
+static void scrollbottom(Client *c, const Arg *a);
static void navigate(Client *c, const Arg *a);
static void stop(Client *c, const Arg *a);
static void toggle(Client *c, const Arg *a);
@@ -1816,7 +1818,12 @@ responsereceived(WebKitDownload *d, GParamSpec *ps, Client *c)
void
download(Client *c, WebKitURIResponse *r)
{
- Arg a = (Arg)DOWNLOAD(webkit_uri_response_get_uri(r), geturi(c));
+ const char *dluri = webkit_uri_response_get_uri(r);
+
+ if (!dluri || !dluri[0])
+ return;
+
+ Arg a = (Arg)DOWNLOAD(dluri, geturi(c));
spawn(c, &a);
}
@@ -1954,6 +1961,18 @@ scrollh(Client *c, const Arg *a)
}
void
+scrolltop(Client *c, const Arg *a)
+{
+ evalscript(c, "window.scrollTo(0,0);");
+}
+
+void
+scrollbottom(Client *c, const Arg *a)
+{
+ evalscript(c, "window.scrollTo(0,document.body.scrollHeight);");
+}
+
+void
navigate(Client *c, const Arg *a)
{
if (a->i < 0)