nielssp.dk

A screenshot of the file manager in TEXTSTEP
Miller columns in TEXTSTEP's file manager.

Since 2016 I've been working on a static site generator with a web-based user interface. The idea is that you can log in and manage layout and content as in a traditional CMS, then you press a button and static HTML files are generated which can be served raw by the web server without any additional processing. There are several technical aspects of TEXTSTEP I would like to describe in detail, but for this blog post I will primarily focus on the design of the GUI.

I had previously spent several years working on a WordPress-like content management system (initially called PeanutCMS, later Jivoo), and I had built a typical CMS interface using flat design consisting of a sidebar with a long list of menu items (e.g. “Posts”, “Pages”, “Media”, etc.) and a main column for the content of the selected page. On the “Posts”-page you would get a paginated list of all posts stored in the database table, and you could change the ordering or search for specific posts. Clicking on the “Add”-button would open a new page on which the title and content (and other metadata) of a new blog post could be entered. Similar CRUD UI existed for the other content types. I don't think there's necessarily anything wrong with that design, after all that's how most content management systems work. And while it's definitely possible to design a similar GUI for a static site generator backed by a database, I wanted something much more conceptually simple for TEXTSTEP. My idea was to instead implement a hierarchical file system like traditional operating systems, and then have separate “applications” for managing, viewing, and editing files. On the backend, all the data would be stored as plain text files and could easily be moved/copied/backed up (the templates and content used to generate this website for instance is on GitHub). Thus, in October 2016, I started using the first somewhat usable version of TEXTSTEP (initially called BlogSTEP) and retired my old CMS project.

Now, the reason I specifically mentioned that my previous CMS project used a flat design, was that by mid-2016 I was getting fairly tired of flat design. I realized that I found much more enjoyment in the designs of classic '90s era operating systems like Windows 95, Classic Mac OS, and NeXTSTEP. Back when buttons still looked and felt like buttons. Just before I started working on TEXTSTEP I had experimented a bit with recreating this sort of design with CSS, initially recreating the Windows 95 look and feel, however it was the NeXTSTEP-inspired design that eventually made its way into TEXTSTEP.

The TEXTSTEP user interface consists of the main window in the center (the active “application”), a sidebar on the left containing application menus and tool windows as well as the workspace menu, and a dock on the right with an icon for each running application. The sidebar dynamically changes depending on the active application; the “Write”-application (a Markdown editor) for instance has a main menu (“New”, “Save”, …) and a tool window that lists open files (“Buffers”, similar to tabs in some text editors). The workspace menu – from which for instance the file manager or control panel can be opened – is always visible at the bottom of the sidebar. Having a vertical dock and menu/tool system like this instead of a horizontal menu like in Windows and Mac OS has some advantages: 1) Most desktop and laptop monitors today are widescreen, so there is way more horizontal space than vertical space available, and 2) when using the UI on a phone or small screen the menu and dock can be hidden behind a menu button (see the screenshots on this page for an example of this behavior).

When you log in to TEXTSTEP, the first application that runs is the “Files”-application, which is the file manager. The file manager borrows another concept from NeXTSTEP: Miller columns. Miller columns allow multiple levels of the file hierarchy to be visible at once. They also work well on multiple different screen sizes since columns can be added and removed depending on how much horizontal space is available (e.g. on a phone screen it may only be possible to show a single column). From the file manager you can create/upload/download/copy/move/delete directories and files. Double clicking on a file will open the associated application, e.g. “Write” for Markdown-files, and there is also an image viewer for image files, and a video player for videos. While editing a file you can switch to another running application and back again without losing any work. Additionally, opening another Markdown-file will create a new buffer in the existing instance of the “Write”-application, so that you can also switch between several different files within the editor.

The design is still very much work in progress, and many improvements can still be made. For instance, all applications are currently maximized and can't be resized or moved. This might change in the future, since I realize it could make sense to be able to tile several applications next to or on top of each other on larger screens (nothing in the architecture technically prevents that at the moment, it's just a question of what the interface would look like). It could even make sense to have draggable/resizable windows, although I'm not usually a fan of that type of interaction in web applications. Another place that can also still be improved is the file manager. I personally like Miller columns, but if everyone liked them then there would probably be more file managers today that use them, so my plan is to also have more traditional large icon and detailed list views available as options. Additionally, I'm still not set on whether there should be a preview-column or not, or whether it requires a double click to open a file. You'll also notice that none of what I've been describing actually has much to do with static site generation, since most of the current applications in TEXTSTEP are fairly general. So in the future I'd also like to add one or more applications that specifically deal with the TEXSTEP template files, perhaps some sort of WYSIWIG theme designer.

Lately I've also been experimenting with something I call Classic stylesheets for web applications, which is a set of stylesheets that mimic the look and feel of some '90s user interfaces. I don't exactly have a plan with it, but I was toying with the idea of somehow combining it with TEXTSTEP's GUI toolkit to make some sort of '90s GUI toolkit for the web. They will probably still be two separate projects though, as I don't like when I have several personal projects that depend on each other (my previous CMS project Jivoo only got harder to develop when I decided that it was also a web application framework). It's also worth noting that while I've been pretty hooked on the '90s aesthetic, it's definitely possible – using the power of CSS – to create an alternative “modern” flat design for TEXTSTEP.

I've previously mentioned that I have an old Toshiba T2130CS with an Intel 486 processor. With its 24 MB of RAM it will run Windows 95 and even 98, but I'm currently just using it with DOS 6.22 to play an assortment of DOS games. Unfortunately the T2130CS, with its lack of a sound card and its low-contrast passive-matrix LCD, makes for a less than stellar DOS gaming experience (but a pretty cool text mode experience).

I also happen to have a similar looking, but slightly more powerful, Toshiba Satellite Pro 410CDT with a Pentium processor, 40 MB of RAM, an active-matrix LCD, and a SoundBlaster-compatible sound card. Sadly, it stopped working more than a year ago. It would power up, but the screen would remain blank. After connecting an external monitor, I could determine that a VGA signal was being produced, but it was completely blank. I had previously saved the laptop from a leaky backup battery (the 410CDT contains three batteries), and although I hadn't noticed any serious damage at the time, I assumed that the issue I was having was related. So I took it apart but was unable to find any visible damage to the the top of the system board. I gave up and didn't expect to ever get it running again.

Recently I took another look at the maintenance manual (which I've used previously when disassembling), and in section 2-4 there's a troubleshooting procedure that uses a special parallel port LED device to indicate status codes while the laptop is booting. I didn't have such a device, but I was able to make one with 8 LEDs+resistors, a breadboard, and some jump wires.

Debugging contraption
My LED status code display connected to the parallel port of the laptop.

After powering on the laptop several status codes were shown before settling on 0x18: “PIC initialization”. According to the manual, the next step when 0x18 is displayed is to replace the system board with a new one. Since I didn't have an easy way of getting a new system board for a more than 20 year old laptop, and since I didn't have the skills, tools, or knowledge to further debug the system board, I once again had to give up.

It was only today, after having the laptop sit partially disassembled on my workbench for a couple of weeks, that I decided to dig further. While I've disassembled the 410CDT a couple of times, I've never actually removed the system board to investigate the back of it. So today I decided to do just that. I was surprised to find a small section of the backside of the system board that was clearly damaged by battery acid. I cleaned it up with a toothbrush and some baking soda, and then started poking around with my multimeter. Initially I wasn't sure what I was looking for, but after zooming in on the area with one of those cheap USB microscopes from eBay, I was able to find a single trace that had been broken. I found the endpoints and used my multimeter to confirm that there was indeed no continuity. I then heated up my soldering iron and added a wire to bypass the broken trace.

Bypassing broken trace
Bypassing the broken trace with a bit of wire.

At first I didn't really expect this to work, but after applying power to the system board and once again connecting the LEDs to the parallel port, I was amazed to see that it no longer settled on 0x18. I quickly reassembled everything and was ecstatic to see the laptop come back to life booting into Windows 98 with the startup sound blasting from the mono speaker.

Booting Windows 98 once again
Booting Windows 98 for the first time in over a year.

In conclusion, I think that feeling of getting something to work after tinkering with it for several hours is pretty neat. And I guess the moral of the story is that batteries are evil.

KDE 1.2.1 on Slackware Linux 7.1
KDE 1.1.2 on Slackware Linux 7.1

I'm a big fan of websites like GUIdebook and the toastytech GUI gallery that collect screenshots of old desktop GUIs. I think it's interesting to travel back in time and take a look at how GUI design has changed over the years. I'm particularly interested in early Linux desktop environments and window managers.

One such desktop environment is KDE, which had its 1.0 release almost 20 years ago on 12 July 1998. Sadly, KDE 1 and other early KDE (as well as GNOME and XFCE) releases are missing from GUIdebook and toastytech. So I tasked myself with finding, installing, and documenting those old releases. It seemed the easiest way to do that was to find an old release of a Linux distribution that includes one or more desktop environments. As it turns out, it's not exactly easy to figure out which contemporary distributions included which versions of which desktop environments.

I ended up picking Slackware since it began including KDE 1.1 from version 7.0 (and also included early versions of GNOME and XFCE in later releases). I've previously used Slackware 12.0 with KDE 3.5, so I'm already somewhat familiar with the installation process which hasn't changed much over the years. Additionally it's fairly easy to find ISOs for early Slackware releases online (e.g. just search for “slackware 7.1 iso” and you'll find it on several mirrors).

I'm now in the process of gathering screenshots of desktop environments and applications from several different Slackware releases that I've downloaded and installed in VirtualBox. The screenshots will (eventually) be available in the new GUI section of my website. So far I've added a page full of screenshots from KDE 1.1.2 on Slackware 7.1.

csol
csol running in DOS 6.22 on an i486 Toshiba laptop from the mid-'90s.

I'm not sure how the thought entered my mind, but I was suddenly curious about how easy it would be to get a somewhat simple ncurses application like csol to run on DOS. Aside from ncurses, I knew csol didn't really have any dependencies other than a C compiler, so I searched for “DOS curses” and PDCurses (Public Domain Curses) showed up.

Helpfully, the PDCurses github repository contains a list of C compilers for DOS. At first I tried to get DJGPP up and running in DOSBox, but eventually ended up using Open Watcom instead because the installation was simpler. After compiling PDCurses my new DOS development environment was ready. To compile csol with Open Watcom and PDCurses I had to make a number of changes to the source:

From C99 to ANSI C: The first step was to remove the use of C99 features from the source code. One such feature is the ability to declare variable anywhere in a block, whereas in ANSI C all declarations must be at the top of the block. This was rather easy to fix by running each source file through gcc -c -ansi -pedantic which helpfully lists all incompatibilities.

From ncurses to pdcurses: Rather unexpectedly it was enough to just include curses.h instead of ncurses.h and change a single occurrence of getmouse(&mouse) to nc_getmouse(&mouse).

From POSIX to DOS: The csol configuration file format has support for including entire directories (e.g. the games and themes directories). Unfortunately standard C doesn't have any concept of “directories” so in order to get the contents of a directory I had used the dirent.h header which is part of the C POSIX library. No such header is provided by Open Watcom, but I was able to recreate the functionality using the functions _dos_findfirst() and _dos_findnext() which are part of the dos.h header.

Similarly I had used getopt_long() from getopt.h (a GNU header) to parse command line options. I replaced this with getopt() from unistd.h (which Open Watcom does include). Unfortunately this means that long options are not currently supported.

From Unicode to Code page 437: The default csol theme uses several Unicode characters to draw cards and suits. Since DOS doesn't support Unicode I created a new default theme based on Code page 437 which happens to include the exact same characters I was using in the Unicode theme.

The modified source code is available on github. I've also uploaded a zip-file containing the compiled EXE and configuration files. It works in DOSBox, and I was also able to run it directly from a 3.5″ floppy on my Toshiba T2130CS with a 486. It should also work on older 386 and 286 machines.

There isn't much to say about this one. It started out as a desire to play Yukon in a terminal – I could only find a few implementations of Klondike. So I created yuk, a simple ncurses-based Yukon implementation in C. I then realized that most of the code could easily be reused to implement other games, such as Klondike and Freecell. The result was csol.

csol
A game of Yukon in csol.

At the moment, csol includes 5 different solitaire games: Yukon, Klondike, Freecell, Eight Off (very similar to Frecell), and Russian Solitaire (very similar to Yukon). They are implemented in a simple declarative language I designed for csol. It should be possible to implement a lot more games using it, but unfortunately I don't know that many different solitaire games. csol also has support for different themes using the same declarative language.

Some more screenshots of games and themes, as well as the source code, are available on the github repository. As usual, I've also created an aur package.