Like a few other folks, I use the computer much more easily when there are not bright colors involved. Some Wayland desktop environments, like GNOME, support extensions to do this. This is great, but I have a strong preference for using a tiling window manager for a number of reasons.
My tiling window manager of choice, Sway, does not have support for a grayscale mode, or saturation controls of any kind. So I hacked them on.
How?
I added patches to wlroots' GLES fragment shaders to add desaturation support just before drawing to the screen, disabled the Vulkan renderer, plumbed this into Sway, and wrapped it all up in a Nix flake.
Thanks to Izzy for helping me understand the graphics concepts involved here.
This is not good code and it won't be upstreamed in this form. But it solves an accessibility need for me, so that's okay. If you are okay with all of this, you can either build my sway and wlroots "forks" yourself, or use them in a home-manager configuration with something like this:
In flake.nix
:
inputs.sway-tris = {
url = "github:an-empty-string/sway-hacks/tris-patches";
inputs.nixpkgs.follows = "nixpkgs";
}
outputs = { ..., sway-tris, ... }: {
homeConfigurations = let
extraSpecialArgs.sway-tris = sway-tris.packages.x86_64-linux.default;
in {
inherit extraSpecialArgs;
modules = [ home.nix ];
}
}
In home.nix
or your equivalent:
{ ..., sway-tris, ... }: {
wayland.windowManager.sway.package = sway-tris;
}
Then, in your Sway config, make keybinds like:
bindsym Mod4+Shift+d set $grayscale 0.75
bindsym Mod4+Shift+f set $grayscale 0
bindsym Mod4+Shift+g set $grayscale 1
This config would make Shift+Super+f disable desaturation, Shift+Super+g enable complete desaturation, and Shift+Super+d enable partial desaturation. Note that the scaling factor isn't perceptually linear (like 20% desaturation doesn't mean your eyes will perceive 80% of the color — in fact set $grayscale 0.2
was pretty much imperceptible when I was testing).
The "right" way...
...is probably to hook into the Vulkan renderer's color transform infrastructure, like ICC profile-based color calibration support does, and write a new color transform type that applies either a desaturation transformation, or a more generic transformation (like being able to specify a matrix to multiply the drawn colors by; that could support other color accessibility needs too). Then you could hook into Sway's output color profile support.
I haven't done this yet, but would like to, because it has a much better chance of landing upstream :)