TRACK_ZERO


Windowing Systems by Example: Introduction


So, I’ll say this upfront and before I get into anything else: I am not a great programmer. Okay, so yes. I’ve been doing it, like I assume the majority of you have, since I was a little kid[1]. But I’ve always been a bit lazy about things and have never had a great drive for making sure I’m using really great design patterns all the time. I assume a good chunk of you can identify with my tendency to tell myself I’ll clean up and refactor once everything’s working with my fingers firmly crossed behind my own back.

Okay, so you’re self-deprecating. We get it already. Why on earth are you opening with this depressing crap?

Certainly a good question, and one of the answers[2] is this: I want the introduction of this series to include an explanation of why the hell I would even write this series in the first place. Because this is a really weird topic, right? Like, why would anyone need to or want to know how to make a windowing system[3]? Don’t we have libraries and shit to do that for us? It’s a solved problem!

So the introductory paragraph serves to preface this argument: That there are two major classes of programmers. These classes, like anything, certainly Venn[4]. But I end up identifying strongly with one side over the other, myself, and so it becomes a very clear distinction for me. These two classes are:

1) The Programmer’s Programmer: This person builds things to build things. If you are in this category, you are a lover of libraries and the language environments in which they flourish in multitude. You design your code as correctly as possible and make sure to abstract away as much of the needless housekeeping as you can that doesn’t relate directly to what you’re trying to accomplish. If you went to school, you took your OSes and/or hardware classes and then thought to yourself good, now I have a better understanding of the stack and never thought more about it.

2) The Academic Programmer: This person builds things to find out how things are built. If you are in this category, you shun libraries in lieu of reimplementing them yourself because you like learning by doing. You’re a lover of languages that do nothing for you, but also do their best to stay out from between you and the machine[5]. As a result, your actual implementations tend to be woefully underdeveloped and your projects themselves stretch into ridiculous overtime as you get hung up in all of the implementation black magic and the brick walls they can sometimes present. Your design tends to be rather haphazard because you don’t have the time for better architecturing once you’ve implemented all of the silly details. You may have been insane enough to begin writing an operating system or an emulator[6] after you learned a bit about OSes or hardware because you thought to yourself okay, yeah, but how does it ACTUALLY do that?

So I’m firmly a class 2. And it’s a bit ridiculous, because I realize how kind of stupid this attitude is. You just keep reinventing the wheel and usually building nothing of actual value while category 1s are out there on the front lines making snapstagrambook[7]. But I accept my fate in this matter, because, considering the personalities of the people who end up getting attracted to programming in the first place, I think it’s hopeless to think that anyone on either side of the room is going to be addressing their personal approach addictions any time soon.

So instead of going to AA, I’ve decided to just get real comfortable here in the gutter.

And that’s why I’m writing this series. Because class 2s exist, and because I’m a class 2. I just can’t stop asking ‘why’ and ‘how’ -- and unfortunately, that compulsion only gets exponentially worse with the inverse of the amount of documentation there is on a given subject. And I know there are others of you out there who have the same problem. I’ve met you on places like OSDev. You can be a little weird[8], but you’re my people, dammit.

Yup. I’m one of those guys. I’ve been dicking around with writing an x86 OS in my spare time for like a decade now[9]. You can check it out on my github, but be forewarned that what you’ll find there is a tangled mess that is the product of years of good intentions. But if you check out the readme, you’ll catch a brief snippet where I gloss over the whole reason that I even started such a dumb project in the first place: making a GUI happen.

So, that’s where you start. You’re thirteen and your metacity OSX brushed metal theme just isn’t cutting it for you anymore. You want a computer that looks exactly like you want it and behaves exactly like you want it. And you’re a class 2, so you want a computer that looks and acts like you want it because you made it look and act at all. And that’s how you get sucked into the hole of writing an OS; All you really wanted was a dope desktop theme. But now you find yourself still working at it years later trying to get task switching to happen and lamenting the lust and hubris that doomed you to this sisyphean nightmare.

Then, suddenly, all the groundwork is there. You have task switching and some kind of process system working. You have a system for spawning virtual 8086 tasks[10]. You wrote a graphics abstraction layer that sets a VESA mode and lets processes draw into it. At long last, you’ve made it to the fun part!

So… what now?

There’s a few levels of class 2 psychopathy. The first would have to be implementing common data structures. They’re well defined. They have tons of documentation and proven algorithm examples. There are thousands of textbooks on the subject. Not too bad.

The next most stupid would be writing drivers. There’s literally only one piece of documentation that covers the operation of the piece of hardware you’re trying to drive. You have to glean that information from an incredibly obtuse PDF that was hidden away on an FTP site somewhere. Oh, and by the way, it’s wrong. If you’re really lucky, there’s code in Linux that you can reference. But damn if that doesn’t feel like cheating.

Finally, you arrive at where we are. Implementing arbitrary operating system mechanics. Okay, so I’m being overdramatic. You could definitely go look at how BSD handles its process scheduling or pull apart how X is designed. There is documentation on this stuff. But the real pain in the ass is that there aren’t many examples to work off of and, more crucially than anything else -- especially with something as arbitrary as a UI framework -- everyone does it differently and there’s really no one answer on how to make it happen. Because it’s not often that you have to. 99.9[11]% of the time, someone already did that for you.

And so it is at this confluence of issues that we find windowing system design. It’s somewhat arbitrary, relies quite a bit on underlying abstractions whose existence, in most scenarios, would imply that you also already have the windowing system itself as well, and on the whole for which a new implementation is incredibly rarely needed[12].

But, indeed, I needed it for writing my OS and making the dreams of my internal 13-year-old finally bear fruit. And once I had learned some things hacking away on that, I needed it again for my current project, Patch.

The plan with Patch[13] is to build an audio synthesis playpen inspired by modular synths in which the user can spawn an assortment of audio generators and filters and wire them all together to make some gnarly sounds. It’s not exactly a new idea, but I had been playing with writing some audio software and decided that it would be fun to make it a little more interactive. And I decided to write it in JS so that I could share it with my music nerd friends easily.

So one of the core features here is that the screen needs to be able to display these little synth modules floating all over the place and potentially behind and in front of each other. I probably could’ve made a normal DOM-based program that hovered DIVs all over the place. But there’s some stuff in that, like the wires between units, that I really didn’t even want to begin thinking about trying to twist HTML into doing. And even in this modern world of browsers playing mostly nicely with the standards, I personally detest trying to make CSS work the way I want it to[14]. So I figured, considering that I had just done a bunch of groundwork in making WYG, the windowing system for my OS, more or less functional I might as well just go full hog, slap a canvas across everything and make my own GUI toolkit in JS[15].

Because I am a class 2, dammit[16].

And it all boils down to this: I could go on and on about how I want to find those other crazies who like reinventing the wheel for borderline romantic reasons. Or how I want to try and use this as an opportunity to convert unsuspecting newcomers over to our horrible lich army. But at the end of the day, even OSDev doesn’t have a basic tutorial on how to make this happen in general[17] while I’ve already found[18] two needs for it. With any luck, the articles[19] in this series will become that tutorial. Because there’s almost nothing I can find online that covers the seemingly trivial task of efficiently[20] sharing a single framebuffer safely between multiple processes or object instances. There’s really no single article breaking down how X or user32.dll do what they do. And to me, among other relatively undocumented things, that’s a crying shame.

So, tune in next week if you’re ready to learn with me all about how you can cram clipping and blitting and recursive structures and message passing and all of this other goodness together in order to transform a screen full of pixels into an actual working GUI. So it might not quite be a super cool technical breakdown of how MP3s work or anything, but at the same time this is the thing that changed our fundamental experience of computers in 1973 from nothing but text streams to full on WYSIWYG everywhere, so even if you don’t want to implement one yourself I’m sure you’ll enjoy it from a historical perspective[21]. If I do, then there’s got to be at least a couple of other class 2 freaks on the internet who would as well.