USE SURF WITHOUT A WELDING HELMET

Who here has lived to use `surf' in a darkened room and lived to tell
the tale? I have, though my eyes are worse for wear for it.

I'd been told it was a character building exercise: that momentary
flash of white while `surf' loads a webpage will put hair on your
chest, turn your automatic Subaru into a manual Honda Civic, and get
your wife pregnant. Sure, the character of my cataracts was developing
at a positively accelerated rate.

I'd considered getting out the welding helmet, or else timing my
blinks to coincide with that momentary blast of #FFFFFF just to avoid
shock. I'd also done my customary web search to learn how to enable
darkmode in `surf'. I found halfway answers: stylesheets would make
the loaded page show in a darkmode. But still: a blinding whitescreen
between when `surf' launches and when WebKit has finished loading the
page persists.

,----
|     /* Place these styles inside ~/.surf/styles/default.css to get
|        darkmode on every website. Code adapted from:
|        https://surf.suckless.org/stylesheets/darkmode_css/ */
|     *,div,pre,textarea,body,input,td,tr,p {
|         background-color: #000000 !important;
|         background-image: none !important;
|         color: #bbbbbb !important;
|     }
|     h1,h2,h3,h4 {
|         background-color: #000000 !important;
|         color: #b8ddea !important;
|     }
|     img {
|         opacity: .5;
|     }
|     img:hover {
|         opacity: 1;
|     }
`----

I decided to clone the repo and dig around the code for opportunities
to extinguish the flame. To get things building properly on Void I had
to install two new dependencies: `webkit2gtk-devel' and `gcr-devel'.

I started my playing around by commenting out some code and adding
print statements to see what runs where. Towards the bottom of
`surf.c' I found that if I only invoked `showview' I could preserve
that blinding whitescreen forever as long as the program is running
(nice!).

,----
|   c = newclient(NULL);
|   showview(NULL, c);
|   /* loaduri(c, &arg); */
|   /* updatetitle(c); */
|   /* gtk_main(); */
|   /* cleanup(); */
`----

That lead me to look into `showview'. Immediately I noticed the
`bgcolor' variable. I tried changing it from `GdkRGBA bgcolor = { 0
};' to `GdkRGBA bgcolor = { 1,0,0,1 };', using full-on red just as a
test so I could see it. It made no difference. From here I went to the
`createwindow' function, which is called from inside `showview'. I
noticed that this function creates the GTK window which eventually
contains the WebKit view. I found a place to set the default
background color of the GTK window to black. After a `make', I found
that this eliminated most of the white screen. `surf' launched in
black, momentarily showed white, and then loaded the page.

,----
|   GtkWidget *
|   createwindow(Client *c)
|   {
Happy helping ☃ here: You tried to output a spurious TAB character. This will break gopher. Please review your scripts. Have a nice day!
Happy helping ☃ here: You tried to output a spurious TAB character. This will break gopher. Please review your scripts. Have a nice day!
Happy helping ☃ here: You tried to output a spurious TAB character. This will break gopher. Please review your scripts. Have a nice day!
Happy helping ☃ here: You tried to output a spurious TAB character. This will break gopher. Please review your scripts. Have a nice day!
Happy helping ☃ here: You tried to output a spurious TAB character. This will break gopher. Please review your scripts. Have a nice day!
Happy helping ☃ here: You tried to output a spurious TAB character. This will break gopher. Please review your scripts. Have a nice day!
Happy helping ☃ here: You tried to output a spurious TAB character. This will break gopher. Please review your scripts. Have a nice day!
Happy helping ☃ here: You tried to output a spurious TAB character. This will break gopher. Please review your scripts. Have a nice day!
Happy helping ☃ here: You tried to output a spurious TAB character. This will break gopher. Please review your scripts. Have a nice day!
Happy helping ☃ here: You tried to output a spurious TAB character. This will break gopher. Please review your scripts. Have a nice day!
Happy helping ☃ here: You tried to output a spurious TAB character. This will break gopher. Please review your scripts. Have a nice day!
Happy helping ☃ here: You tried to output a spurious TAB character. This will break gopher. Please review your scripts. Have a nice day!
Happy helping ☃ here: You tried to output a spurious TAB character. This will break gopher. Please review your scripts. Have a nice day!
Happy helping ☃ here: You tried to output a spurious TAB character. This will break gopher. Please review your scripts. Have a nice day!
Happy helping ☃ here: You tried to output a spurious TAB character. This will break gopher. Please review your scripts. Have a nice day!
Happy helping ☃ here: You tried to output a spurious TAB character. This will break gopher. Please review your scripts. Have a nice day!
`----

From here, I went back to the `main' function and manually traced the
function invokations below `showview'. This lead me to a few functions
of interest: `loaduri', `loadchanged', and `newview)'.

I soon understood the order of the presentation: the GTK window was
created first, then it was filled with the WebKit view. WebKit loads
the uri with `webkit_web_view_load_uri(c->view, url);' and then there
are various loading signals from `WEBKIT_LOAD_STARTED' to
`WEBKIT_LOAD_FINISHED'. I'd taken care of setting the GTK window
background to black, thus achieving an amount of success. But the
WebKit view stayed white while the page loaded. My quest to be fully
enveloped by darkmode continued.

For a while, my hypothesis was that I needed to adjust something
around the WebKit load signals or maybe introduce my darkmode CSS
stylesheet earlier, somehow, to get rid of the white flash that
remained between the GTK window and the WebKit view. Maybe, I thought,
the WebKit view allowed CSS styles even before the page loaded.

I peeked back into the `newview' function and noticed therein how settings were applied to the WebKit view. I added `setstyle(c, getstyle(geturi(c)));' just before the return statement, thinking this stylesheet would avoid the whitescreen in the WebKit view. That didn't work, but I noticed this nearby: `setparameter(c, 0, DarkMode, &curconfig[DarkMode].val);' I found that this value could be set from `config.h'. I set the value to `1' and recompile under bated breath. Still no full darkmode.

Now I'm a bit hazy about what happened next. I was in a frenzy!
(Family and friends be damned that I didn't answer the phone for I was
`hacking'!) But it seems that in the moment of despair that followed
failure I dragged myself back to `showview'. I played with the
`bgcolor' variable again, then looked more closely at the `showview'
function's logic. The prize that I sought stood out like a toad in a
hole:

,----
| if (curconfig[HideBackground].val.i)
Happy helping ☃ here: You tried to output a spurious TAB character. This will break gopher. Please review your scripts. Have a nice day!
`----

I moved briskly over to `config.h' and set `HideBackground' to `1'. I
`make''d and ... voila! No blinding whitescreen of fire! I had found
my full darkmode. It seems that setting the WebKit view background to
a `GdkRGBA bgcolor = { 0 }' (as happens when the statement above
evaluates) causes the view to have a black background. Combined this
with the GTK window set with a black background and the whitescreen is
entirely avoided.


Summary
----------------------------------------------------------------------
To effect pretty good darkmode in `surf' (it will show a gray fill
while the GTK window is built and the WebKit view loads), do the
following:

1. Clone the repo. Install dependencies and get a successful `make'.
2. Modify `config.h' so `HideBackground' and `DarkMode' are both set to
   `{ .i = 1 }'
3. Create a default stylesheet at `~/.surf/styles/default.css' including
   the aforementioned darkmode styles.
4. Build surf.
5. Put away your welding helmet.

To effect an even better darkmode in `surf' (it will show a black fill
from launch up until page load), do the above *and* add the following
snippet to line 1464, just before `createwindow' returns.

,----
|   gtk_widget_modify_bg(GTK_WINDOW(w), GTK_STATE_NORMAL, &(GdkColor){0});
`----


Patch
----------------------------------------------------------------------
Below is a patch you can apply. Note that you'll still need to
manually add a stylesheet to affect darkmode on the websites you
visit. This patch only eliminates the whitescreens during `surf''s
launch and load procedures.

,----
|   From 25fedb98bc24067ce04d6b9daa49b4950ea4d3a2 Mon Sep 17 00:00:00 2001
|   From: Scarlett McAllister 
|   Date: Thu, 28 Dec 2023 13:44:21 -0400
|   Subject: [PATCH] Add darkmode to GTK window
|   ---
|    config.def.h | 4 ++--
|    surf.c       | 1 +
|    2 files changed, 3 insertions(+), 2 deletions(-)
|   diff --git a/config.def.h b/config.def.h
|   index 93cfeeb..0214d6e 100644
|   --- a/config.def.h
|   +++ b/config.def.h
|   @@ -20,7 +20,7 @@ static Parameter defconfig[ParameterLast] = {
|           [Certificate]         =       { { .i = 0 },     },
|           [CaretBrowsing]       =       { { .i = 0 },     },
|           [CookiePolicies]      =       { { .v = "@Aa" }, },
|   -       [DarkMode]            =       { { .i = 0 },     },
|   +       [DarkMode]            =       { { .i = 1 },     },
|           [DefaultCharset]      =       { { .v = "UTF-8" }, },
|           [DiskCache]           =       { { .i = 1 },     },
|           [DNSPrefetch]         =       { { .i = 0 },     },
|   @@ -29,7 +29,7 @@ static Parameter defconfig[ParameterLast] = {
|           [FontSize]            =       { { .i = 12 },    },
|           [FrameFlattening]     =       { { .i = 0 },     },
|           [Geolocation]         =       { { .i = 0 },     },
|   -       [HideBackground]      =       { { .i = 0 },     },
|   +       [HideBackground]      =       { { .i = 1 },     },
|           [Inspector]           =       { { .i = 0 },     },
|           [Java]                =       { { .i = 1 },     },
|           [JavaScript]          =       { { .i = 1 },     },
|   diff --git a/surf.c b/surf.c
|   index f8c8dec..a6cb224 100644
|   --- a/surf.c
|   +++ b/surf.c
|   @@ -1461,6 +1461,7 @@ createwindow(Client *c)
|           g_signal_connect(G_OBJECT(w), "window-state-event",
|                            G_CALLBACK(winevent), c);
|    
|   +       gtk_widget_modify_bg(GTK_WINDOW(w), GTK_STATE_NORMAL, &(GdkColor){0});
|           return w;
|    }
|    
|   -- 
|   2.42.0
`----