IdealOS Mark 5
After a few weeks long sprint I’ve got another build ready for Ideal OS. Visually it’s starting to come together nicely. Check it out.
There were tons of little things that went into this build so I'll just cover the big stuff.
Typescript
I refactored the core server to use Typescript and completely rewrote the app / websocket / window management code to be simpler and shorter. A big win for maintainability. I was also able to start rewriting the unit tests in Typescript and make them shorter. Why did I wait so many years before learning typescript!
Simple Database
I pulled in the database code from one of my other IdealOS experiments from last year. The database is essentially a list of JSON objects that fit particular schemas. Apps can search the database over the wire using queries for things like items in a particular category or fields that match a certain substring.
As databases go its pretty simple. The magic is that we can bind GUI widgets to queries very easily. Rather than the app doing requests for data and then synchronizing internal state manually, the database itself becomes that state. Right now there’s still more glue code than I’d like, but after some polishing you should be able to declare a list of tasks with something like this to handle incremental text search
let search = new TextBox({text:”abc”})
let list = new ListPanel({
query: AND(
ISTYPE(“note”),
ISSUBSTRING(search.text)
})
Whenever the user types into the text box the query will be automatically updated. In fact, if the database changes by another process, like a background service fetching new emails, the list panel will automatically include those updates as well. No extra code required!
Once the new database system is polished it will make certain types of apps trivial to build. The DB will do all of the heavy lifting. This is the screenshot of a new “notes” which is entirely database driven as described above.
Visual Polish
I cleaned up the visuals. Mostly lots of tiny things but that collectively add up to something that looks more polished. In particular the light and dark themes are now both fully black and white and represent mirror images of each other. The close and resize controls are using glyphs from the standard font, as are all of the dock icons, icons in the right side of the menubar, and the sidebar widgets.
Here's the dark mode theme.
New UI components
There is now a proper multi-line text box that wraps at the word boundaries, uses cursor bias, and accept actions for all navigation instead of arrow keys. This means in the future moving around in a text box could be done by alternate keyset defined through system wide bindings, rather than apps implementing their own keybindings.
I also added very ugly list view and scroll panel which required a minimal implementation of clip rects. I’m still debating where clipping should happen, in the app or the display server. It works well enough for now.
Rust client
The other major change is getting the rust client working again. We now have two complete implementations of the display server. One in the web browser in JS and one in rust using real GPU code. The rust client uses SDL2, so in theory it can run on a raspberry pi without having X11 or Wayland running. I haven’t tested this yet, but this lays the groundwork for deploying my stuff as a “real OS” without so much extra scaffolding.
I’d like to mention something cool I discovered. Everything in ideal os is driven by messages. Most messages are sent to a single receive, like an app. For example, when the user clicks the mouse the display server will send a mouse event to the target application by id.
Some messages, however, are sent to a category of receivers, not a single one. When an app draws something like a button it sends a drawing event to the display. ‘display’ is a category of receiver. There can be multiple displays registered and they will all get the event. This means we could have multiple display servers running at once and they will all just work.
Here’s a screenshot of the rust client and web client both running. This isn’t two copies of the OS. There’s only one OS and one instance of each window, just displayed twice by two clients. Since the important state like window positions is kept in the server, the user could click a button in one display and the other will be immediately updated in sync. Pretty cool.
I hope to use this functionality in the future for other types of clients that must be kept in sync. Maybe a second database that just records all actions into a log file for later analysis. Or maybe multiple keyboards and mice so that two people could use the same computer at the same time?
next steps
That’s it for this build.
I didn’t get a chance to mess with audio streams in this sprint, which is probably just as well. There’s simply so much work to do just to get a basic GUI running.
I still haven’t decided what to work on next. Probably getting the rust client working on a real raspberry pi to prove that this could work without an existing windowing system. And more visual improvements. I’d like to find a way to embed emoji into the text editor using my little 1bit font.
TTFN - J
Posted July 6th, 2021
Tagged: idealos