Skip to content

DisplayServerNotes.md

Noah Gibbs edited this page Oct 13, 2023 · 3 revisions

Display Server Notes

Why We Eventually Need a Display Server

Right now, Scarpe is missing some pretty major Shoes features that are all relevant to having a display server...

APIs that Don't Match Webview Run

Certain Shoes APIs create an effect that outlasts the app itself. If the app opens an alert() and then exits, the alert() is supposed to stay up. That's not really possible with our current API, but could be much easier with a persistent display server.

We'd also like to be able to create multiple Shoes apps in a single process (multiple connections to the display server?). And we'd like to run code in the file that's after the Shoes.app loop.

Similarly, Shoes has a bunch of APIs like confirm() where the called method doesn't return until the window closes. That will require a certain amount of separation between the Shoes app and the event loop. It could be done with Fibers, kind of like CatsCradle. But one way or another, it can't 100% match the flow of a local GTK+ app, Webview app, etc. It needs some kind of separation to handle flow control.

Multiple Shoes Apps

Shoes treats multiple windows as multiple apps. But it also shares a lot of state between them. Instance variables are per-app, but mostly Shoes seems to run all its apps in a single global server space. There are some down-sides to that, but also it lets Shoes keep a single shared error console (remember the error-viewer app that's built in?)

It also makes some interesting things like Shoes app URLs more powerful. If the different Shoes apps that are running all share a single set of resources, you can have the apps interact. That's harder (though possible) if they're not in a shared process. Shoes Classic assumed apps could talk to each other.

Managing Webview

Webview makes multiple apps or windows in a single process really hard - it doesn't support opening multiple windows. But if you take the Webview part out of the Shoes app process, you could have a single display server process that opens child processes, one per window, and the different Shoes apps could tell them what to display.

You could have every Shoes app spawn a process for every window and do it that way, so that the process is the display server. But cleanup is going to be pretty ugly if you do that. Remember that GUI apps routinely sit around minimised for a really long time. So guidelines like "I haven't gotten a message from the Shoes app in a whole day so I should shut down" don't work very well. It means if you keep your laptop lid closed for a day, all your running Shoes apps die.

Display Service Independence

Right now it's hard to keep Scarpe-Webview apps "clean". It's just too easy to reach around in between the display side and the Lacci side. But if you put more of the display logic into a separate process, it's a lot easier to be certain you're not touching something you shouldn't.

Testing

Shoes apps that talk to a socket could be really easy to test, especially if the socket protocol is simple enough. Opening sockets is pretty fast. Opening Webview is not.

Instead of testing apps with real Webview, we could test Webview with recorded messages over a socket, and test apps by recording the messages they send on the socket.

We'd need integration tests. But right now nearly all apps need to run Webview, which can take up to 10 seconds to start up. Ew. Wasm is, sadly, even worse. Though it's not as clear that Wasm can use a display server in the same way.

Packaging

Individual Shoes apps could be really easy to package in many cases if they don't have too many dependencies. But if you have to deal with PortAudio and Webview, you already have a noticeable number of dependencies, that take a noticeable amount of room.

A display server could be one piece of software, not even necessarily in Ruby, with annoying dependencies, which could be downloaded from a known location (e.g. GitHub) and installed.

This doesn't fix all of packaging. For instance, if you want your Shoes app to run a program, you need to include that program somehow. But it might be a really good start, and a way to make individual Shoes apps a lot smaller than they would be if they packaged a massive number of dependencies.

You could even package Ruby with the display server since you know you need to install it once per machine. It's a really good place to put large dependencies that you know every Shoes app will use.

What Would a Display Server Be Like?

If we want display service independence, we'd need the protocol to be very Shoes-flavoured. Shoes drawables, Shoes styles, etc. It would probably look a lot like our current events and properties.

We'd want to identify specific Shoes apps somehow. We should look up old Shoes URLs and see how they get set up. Presumably it should be okay to run the same Shoes app more than once. I think Shoes supports loading a URL into a window and running a browser? We could, whether old Shoes does or not.

We'd like the protocol to be as deterministic as possible. The same app starting up multiple times should send pretty much the same messages if possible.

Maybe we build the protocol into Lacci? We'd need to figure out how this works for e.g. Wasm where there's not going to be a socket connecting them normally.

I think we want the local Ruby code to execute in the context of a Shoes app process. That lets a lot of Shoes conventions like backticks to run an app work. In general, I think we want the declared dependencies (e.g. gems) of the Ruby-based Shoes app to happen where the Shoes app runs. And we can't have a display server just support every possible Ruby gem or load them all in.

Clone this wiki locally