Cairo Plus

A fork of a Windows shell

Cairo Desktop is an open-source replacement for the Windows taskbar and desktop shell, written in WPF. Cairo Plus is my fork of it. The goal was Omarchy-style whole-desktop theming: pick one theme and the bar, the icons, the wallpaper and the colours all follow, the same way a Linux rice does.

I run the fork as my actual desktop now. It's installed as a self-contained build and starts at login, so every bug in it is one I see every day.

What I added

  • Theme packs — one choice restyles the bar, the colours and the icons. Icons come from Cairo's own UI set, with per-app overrides. A pack's wallpaper stays in memory while Cairo is the shell. Outside Cairo it sets the Windows wallpaper permanently, which is the behaviour I picked on purpose.
  • Bar layout and widgets — rearrange the bar and add widgets, and the layout is saved so it can be restored.
  • Shapes and effects — floating and rounded bars. Blur is off on those, because applying a window region to the layered WPF bar made it vanish on Windows 10 21H2.
  • Hotkeys with live reload — bindings live in the same config file, and saving the file applies them without a restart.

The config is a single JSONC file in the local app-data folder, so comments are allowed. Everything is default-off. Someone who installs the fork gets the original Cairo experience until they opt into a feature. Upstream changes are kept minimal, every touch point is marked with a comment, and each feature is its own commit, so rebasing on upstream stays sane.

WPF bit me in specific ways

  • Cairo's taskbar flash animation writes to gradient stops 0 through 2. A palette brush with fewer stops throws, so every taskbar brush has to be a three-stop gradient.
  • Menu items moved into wrapper menus need their style set exactly once. Using a dynamic resource reference means a theme reload strands the items on the old template panel.
  • After restoring a layout, call UpdateLayout before resizing a floating bar. Otherwise Cairo's menu measures empty and the bar comes out the wrong size.
  • Headless WPF tests didn't reproduce the last two. Only running the real thing and looking at it did, so those fixes are verified live.
The lesson I keep relearning: the 64 xUnit tests, passing on net6 and net480, prove the logic. Layout and theme bugs only show up on screen.

Build tricks and live checks

Only the .NET 8 SDK is installed on the build machine, so the net6 and net480 targets are built with a target-framework override on the command line. The release is a self-contained x64 zip.

Testing the UI needed more than the usual tools. The automation I used masks the dev build by its executable path, so I capture only the dev process's window rectangles and use UI Automation on its own process. Cairo's settings tab content is invisible to UI Automation, which means I have to check it by eye.

Done, shipped, and still partly untested

All four features are done and pushed to a branch of my fork, and there's a public release zip for v1.0. The honest gaps are shell mode, the widget click wiring, the settings Apply button, and ARM64 and .NET 10 builds. Those haven't been exercised yet, so treat them as unverified.

← back to projects