Skip to content

Latest commit

 

History

History
318 lines (238 loc) · 7.6 KB

surf.org

File metadata and controls

318 lines (238 loc) · 7.6 KB

Surf, the suckless browser

Surf and surf, surf’s up!

This is the entry point to surf on which gurf is built.

(def (surf (uri "about:blank") (rclient (current-surf-client)))
  (start-surfing!)
  (let (client (newclient rclient))
    (showview client)
    (loaduri client uri)
    (updatetitle client)
    (current-surf-client client)
    client))

start-surfing! and the driver green thread.

We only run if not yet running.

First we setup, a C function.

(define-c-lambda setup () void "setup")
(def current-surf-driver (make-parameter #f))
(def (start-surfing!)
  (cond ((current-surf-driver) => values)
        (else
         (setup)
         (let (drv (spawn surf-driver!))
                (current-surf-driver drv)
                drv))))

surf-driver!: CPU time

There are probably better ways to go about this.

Essentially, GTK wants/needs to know when to iterate. If there’s a context-pending we need to iterate. Otherwise we wait.

(define-c-lambda gtk_surf_iteration
    () bool "gboolean res = g_main_context_pending(NULL);
    while (g_main_context_pending(NULL)) {
      g_main_context_iteration(NULL, FALSE);
   }; ___return(res);")

Now we play with time and sleep, trying to not use that much CPU while still being responsive.

(def (surf-driver!)
  (def min-sleep 0.00001)
  (def max-sleep 0.05)
  (def sleep-incr 0.00000001)
  (def sleep min-sleep)
  (def (sleepy)
    (thread-sleep! (max sleep max-sleep))
    (when (< sleep max-sleep)
      (+ sleep sleep-incr)))
  (let lp ()
    (def events? (gtk_surf_iteration))
    (if events?
      (set! sleep min-sleep)
      (sleepy))
    (lp)))

newclient, showview, loaduri, updatetitle: All C functions

These are what gives us what we need to surf!

(define-c-lambda newclient (Client*) Client* "newclient")
(define-c-lambda showview (Client*) void
  "showview(NULL, ___arg1); ___return;")
(define-c-lambda loaduri (Client* char-string) void
    "Arg arg; arg.v = ___arg2 ; loaduri(___arg1, &arg); ___return;")
(define-c-lambda updatetitle (Client*) void "updatetitle")

Client, current-surf-client and friends.

A Client is the “window” that contains a WebKitWebView among other things.

Here’s the C.

typedef struct Client {
	GtkWidget *win;
	WebKitWebView *view;
	WebKitWebInspector *inspector;
	WebKitFindController *finder;
	WebKitHitTestResult *mousepos;
	GTlsCertificate *cert, *failedcert;
	GTlsCertificateFlags tlserr;
	Window xid;
	guint64 pageid;
	int progress, fullscreen, https, insecure, errorpage;
	const char *title, *overtitle, *targeturi;
	const char *needle;
	struct Client *next;
} Client;

We’ll make it into Gerbil. A big deal here is that we do not want to free a client. That’s handled elsewhere.

But Gerbil’s define-c-struct does have some nice setters and getters.

(c-declare "int ____nofreeclient(Client *c){ return 0;}")
(define-c-struct Client
  ((title . char-string)
   (targeturi . char-string)
   (next . Client-borrowed-ptr*))
  "____nofreeclient")

Using that we can export the following.

Client Client* Client-next
Client-title Client-targeturi

current-surf-client, because I like dynamic scope

A lot of functions expect a client. A lot of the time we have a master client or something. Regardless, having a current-surf-client mixes in a lot of scheme.

Surf has a global, clients, which has all the current clients in this process, starting with the most recent one and ->next‘ing the rest.

(define-c-lambda clients () Client* "___return(clients);")

We’ll call that surf-client and use it + Client-next to return a list.

(defalias surf-client clients)
(def (surf-clients)
  (let lp ((c (surf-client)))
    (if (not c)
      []
      (cons c (lp (Client-next c))))))

Then there’s current-surf-client which

(def current-surf-client (make-parameter #f))

The eval-script procedure.

Surf has it, we just need to make it scheme-y.

Here’s the C.

void evalscript(Client *c, const char *jsstr, ...);

Here’s schemeifying the C.

(define-c-lambda evalscript (Client-borrowed-ptr* char-string) void
  "evalscript(___arg1, \"%s\", ___arg2); ___return;")

And here’s the scheme.

Add Download Patch

Surf calls curl. I don’t want that. This patch makes it work using

cd ~/me/src
cd ~/me/src/gurf/bootstrap/drewc/gurf/surf/
wget https://surf.suckless.org/patches/dlconsole/surf-dlconsole-20190919-d068a38.diff

Because we have other modifications it took some diff/patching, but now we have that

New Window

Surf ships with a fork and relaunch of itself when a new window is opened.

When using it from the REPL such things do not exist.

So we’ll use our own.

void
newsurf(Client *rc, const Arg *a)
{
  Client* c = newclient(rc);
  
  showview(NULL, c);
  loaduri(c, a);
  updatetitle(c);
}

Now rename newwindow to spawnnewwindow and redo newindow.

void
newwindow(Client *c, const Arg *a, int noembed)
{
	if (argv0 != NULL) {
		spawnnewwindow(c, a, noembed);
	} else {
		newsurf(c, a);
	}
}

This is all in the surf code, so push the subtree.

git subtree push --prefix=bootstrap/drewc/gurf/surf ./ surf

The FFI to surf.c

This is so simple that it’s a brilliant start! It’s this easy to get a working browser? The future looks bright.

~/me/src/gurf
gxpkg link github.com/drewc/gurf $(pwd)
gxpkg build github.com/drewc/gurf
(export #t setup surf  newclient showview current-surf-driver start-surfing! gtk_surf_iteration
        <<Client-exports>>
       <<surf-client-exports>>
        )
(import :std/foreign
        :gerbil/gambit/foreign
        :gerbil/gambit/threads)

<<surf-driver!>>

<<start-surfing!>>

<<surf>>

<<surf-clients>>




(begin-ffi (setup
            newclient clients loaduri showview
            gtk_surf_iteration updatetitle
            <<Client-exports>>
            evalscript)
  (c-declare "#include \"surf/surf.c\"")
  <<setup>>
  <<Client-struct>>
  <<surf-c-functions>>
  <<evalscript>>
  <<clients>>
  <<gtk_surf_iteration>>
  )

Surf Branch and Subtree

surf is a simple web browser based on WebKit2/GTK+. It is able to display websites and follow links. It supports the XEmbed protocol which makes it possible to embed it in another application. Furthermore, one can point surf to another URI by setting its XProperties. – https://surf.suckless.org

Surf is a wonderful barebones browser that is the ideal starting point.

We want to start with it and go from there.

cd ~/me/src/gurf
git remote add surf https://git.suckless.org/surf
git fetch surf
git branch surf --track surf/surf-webkit2
git subtree add --prefix=bootstrap/drewc/gurf/surf ./ surf

mkdir doc
cd doc
wget http://www.troubleshooters.com/linux/surf.htm
pandoc -o Surf.org surf.htm
rm surf.htm