Tools that run my desktop

Tools that run my desktop

Table of Contents

Seeing as the collection of helper utilities for my Linux desktop, alongside various other projects that I’ve written, keeps growing over time, I wanted 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:

  • PulseAudio volume display and control, including soundcard output switching to switch the very audible relays on my ASUS Xonar Essence STX, even though that card has been in my storage for some time now, as I no longer have anything to plug it into.

  • Brownian noise playback for improved sleep quality, no matter what time of day it is.

  • Music Player Daemon playback information and control.

  • Network UPS Tools status report. Not that I would miss the beeping alarm when the power’s off, but I can see when something eats too much power, or an estimate of remaining time on batteries.

  • Laptop battery status is pretty obvious.

  • Weather display via an external Perl script since I don’t want to parse volatile XML in C.

  • Keyboard layout switching within the set of groups that are active in the X server.

  • Display brightness and input switching via tools mentioned later in this article.

  • Suspend lock, as well as autosuspend (the GNOME Settings Daemon doesn’t work). Sponsored by systemd-logind and DBus.

  • DPMS force off for when I want to open the windows without having inspects fly into the room because of the bright display.

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. Back when I had a standard tenkeyless keyboard, it looked like this:

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:

i3 status bar

Brownian noise

Many things become deep rabbit holes with me. Here I had to understand how to produce this kind of sleep-compatible noise, and then verify that what I came up with had the desired properties. The most important parameter turned out to be the rate of the integrator’s leakiness, because while it won’t by any means ensure that your signal stays within the range and doesn’t click (at least unless you set it unreasonably low), it’s a very effective means of reducing unpleasant low frequency rumbling:

Leaky integrators

On the other hand, the divisor for the white noise that’s being integrated doesn’t seem to be of particular interest. Anything from 5 to 10 looks about alright. Notice that the attenuation of roughly 20 dB per decade is a property of the integration.

Non-leaky integrator tuning
Leaky integrator tuning

I’ve noticed that PulseAudio spends considerable CPU time on resampling 44.1 kHz signal to the sound card’s chosen 48 kHz. But it’s quite apparent that I can tell it that my audio data is either. The difference is exactly as imperceptible as it looks on this plot:

Effect of sample rate

One cool thing that I haven’t seen people write about is that the Hann window, as well as some others, as I suspect, adds up to cover the whole signal when you do DFT averages with 50% overlapped windows:

Hann window 50% overlap

Also, the GNU C Library seems to have a good random number generator these days.

paswitch

Just like an internal soundcard made me bind a command to switch between PulseAudio ports within the current sink, external soundcards made me write a standalone program to move all inputs to a different sink on request. As far as I know, PulseAudio can only do so atomically with its module-switch-on-connect when a new device appears. Changing the default sink (e.g. in pavucontrol, where it’s called a “fallback output device”) only affects new inputs--the old ones need to be moved over manually. This is one of the most confusing aspects of PulseAudio. It also kept making new sinks each time I re-plugged in my Sound Blaster X-Fi HD.

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 I²C 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 5 V I/O).

I²C

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 I²C 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 wouldn’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:

Noisy discrete AMD GPU

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…​

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.

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?