Tools that run my desktop

Tools that run my desktop

Seeing as the collection of helper utilities for my Linux desktop, alongside various other projects that I've written, keeps growing over time, I think it's a good moment to write a few words about them, if only because some of them simply couldn't be found on the Internet before I made them for myself.

Another purpose of this article might be to inspire others in building an environment that fits their needs.

wmstatus

Several years ago I got into the tiling window manager business out of annoyance, starting with awesome, later converting to dwm and finally ending up at i3. One aspect of them is that they allow you to specify what exactly you want to see in the (task)bar by way of an external program. Me being me, I've written a C application to generate the information, and also to respond to some global shortcuts in order to make better use of already initiated connections to various daemons. It handles:

It's not even that much code, yet it makes all the difference in making my computers comfortable to use. Though I'm slowly running out of keys to bind all these actions to on a tenkeyless keyboard:

Function keys Input VGA Input DVI Input DP Input HDMI Layout CZ DSK Layout CZ Layout PL DSK Layout RU Layout cycle DPMS SleepLk Sound output Bright. up Volume up Mute Bright. down Volume down MPD toggle MPD prev/« MPD stop MPD next/»

Unfortunately at the time of writing NUT is completely broken in Archlinux because of OpenSSL, however for completeness the status area normally looks something like this:

priod

Has it ever happened to you that you ran a parallel compilation with low RAM and your X cursor stopped moving? Has an out-of-memory situation ever brought down your entire X11 session? That's because your stupid Linux installation doesn't know what to prioritize. And so I came up with a simple daemon that can help you prevent such annoyances—just write the process name with the requested adjustments to its configuration file and it will make sure to apply them to both current and freshly created processes.

Linux has a thing called the proc connector that allows this kind of tracking with relative ease—forks, execs, UID/GID sets and such. Funnily you can only filter this stream using the BPF/LSF state machine but it's a decent opportunity to learn a bit about the way libpcap works.

The worst thing about this project was learning that under Linux, renice and ionice only work with thread granularity and there's no way to atomically reprioritize an entire process. Only a process group or all of a user's processes but not a single process. Linux doesn't care about no POSIX.

brightness and input-switch

I don't think it's very common knowledge but usually you don't have to touch your monitor at all in order to change most of its settings, as most monitors provide a standardized interface called DDC/CI and respond to all sorts of commands.

It is exposed directly on the connectors as an I2C bus. With open source drivers, it's enough to modprobe i2c-dev to get acces to it. In general, you can connect pretty much anything to those contacts, like an Arduino (as it has 5V I/O).

Some monitors, such as the EIZO ColorEdge I have, can however only be controlled using an alternative MCCS over USB protocol, and proprietary drivers have special I2C endpoints, so it's not all that straight-forward.

There is a program called ddccontrol that can be used to configure monitors this way and even has a decent database of quirks for various models, but it's somewhat unwieldy to use, and so I went all the way to reverse engineer it to make tools that better suit my needs—I just want to iterate over all /dev/i2c-* endpoints and send commands to either switch the display input, or to read out current brightness and change it a bit.

Unfortunately high-end EIZO panels no longer have this interface, not even as MCCS over USB. Paradoxically, everything else I've touched to this day does.

iexec

This must be something that every developer secretly wants but I haven't seen one have it: when you change the program and recompile it, the program will restart automatically to the new version. It's fairly trivial to achieve this: all you have to do is watch for when the old binary is unlinked and replaced with a new one (which is what a compiler does), or replaced atomically with mv, then ask the program to terminate and run it anew once it dies.

inotify (Linux) and kqueue (BSD, macOS) both allow this. Thus I've written this simple wrapper, to stop repeating myself when I'm trying to focus on programming.

fancontrol-ng

One day I thought the DPI on my display was too low and bought a WQHD monitor, only to learn that my motherboard won't support the resolution. Since I rarely play games and I didn't have any other significant requirements either, I quickly got a modest HP AMD Firepro W2100 to go with it:

You may have noticed the size of the fan—I believe it won't come as a surprise when I say that it sounds like a vacuum cleaner. And so I started looking for ways of getting it somehow under control and found fancontrol from lm-sensors, which is a shell script that allows me to set the card to run much hotter and only spin the fans when the temperature starts going through the roof. It had but one problem: when I came back from work and resumed my PC from suspend, it choked up, set the PWM to full speed and died. Metal.

Eventually I became tired of that shit and wrote my own version of the tool that doesn't do this. There's not much to it: first you set the PWM to manual control, and then every few seconds you check the value of the temperature sensor in sysfs and update the PWM setting accordingly. Now if only the paths didn't change in between boots…

shellify

There are CLI programs out there such as vgdb or nmcli where you get this strong feeling that they should have a shell mode, so that you can stop repeating the command name constantly, but they don't. Luckily this is very easy to solve with a few lines of Python and its integrated Readline module.

$ shellify nmcli
nmcli 1> help
Usage: nmcli [OPTIONS] OBJECT { COMMAND | help }
[...]
nmcli 2> g
STATE      CONNECTIVITY  WIFI-HW  WIFI     WWAN-HW  WWAN    
connected  full          enabled  enabled  enabled  enabled 
nmcli 3>

The only thing missing at this point is autocomplete, and that's something to be done per application.

gdm-switch-user

In order to switch users with GDM from shell, you must write a program that calls a library function. This was a one-off project for when I was sharing a work laptop, to allow others to swap out my dwm session.

siprandom

Trying to erase disks with /dev/urandom prompted me to try using SipHash 2-4 with a counter for a much faster source of pseudorandom data given a seed, as I've seen advised by someone during a talk. It works. There's not much else to add. I wish hard drives were as fast as they are big today.

big-brother

This is mostly a prototype for a more serious application to come to help me track how much time I spend and where. But so far it only writes the important events to its standard output and a proper GUI will be needed to make any sense of the data. The events include the focused X11 window having changed, that window changing its title (think of a web browser), or the user being idle longer than some threshold.

2017-07-06 18:23:29.493 -- Window changed: urxvt
2017-07-06 18:23:33.253 -- Window changed: ./degesch (server)
2017-07-06 18:23:36.867 -- Window changed: Pentadactyl
2017-07-06 18:23:42.075 -- User is inactive
2017-07-06 18:23:44.183 -- User is active

I seem to have a few people waiting for this. Maybe someone else will make it sooner than I can?