Drop-in Xorg XClients

XClients is a perfect and cannonical way to autostart graphical application. But personnaly I don’t like to keep various settings in a single file, so let’s add some modularity to XClients.

Traditional approach

$HOME/.XClients and /etc/X11/Xclients (or somewhere else depending on your system) text files are meant to contain programs which are to be executed on X server startup. To be more precise, /etc/X11/XClients sources user’s $HOME/.Xclients file and adds some user independent startup code.

Usual XClients file would look something like this:

# /home/user/.XClients

xset ...
xrandr ...

gdm # kdm, xmonad, whatever

NOTICE: commands specified in this file must be either fast enough or detached from terminal using & at the end of the line. This is so because long-running command will hang further execution. Typically, the last command in XClients is the window manager, which is conversely left attached to the terminal.

NOTICE: this file should be executable by the user.

Okay, but why isn’t this enough?

When the system is meant to be configured and used manually, this is perfectly fine approach. But once I was to create a collection of rpms, containing not only executables and documentation, but user’s initialization code as well. And this code was meant to be: * versionable; * modular; * checkable (using MD5 or such).

To make this a bit clearer: there is some code, that needs to be executed before applications, and window manager is meant to be loaded first. A list of applications is not known beforehand, and this applications were not installed in the system at the moment.

This is where drop-in configuration comes handy

Here I thought it would be nice to split configuration pieces into one-purpose files, that can be packed as rpms. Something like initd or nginx’s sites-available would do.

There are several problems, though: * How to get this system kicked by an X server? * How to fix the order of execution?

First, create a directory inside the $HOME directory called something like .xclients.d. Then add some config files:


# ~/.xclients.d/00-set-resolution.sh

xrandr --output HDMI-1 --mode '1920x1080'


# ~/.xclients.d/01-xset.sh

xset -r


# ~/.xclients.d/99-wm.sh


Okay, now make them executable:

$> chmod a+x ~/.xclients.d/*

Notice the number in file names – these are used to control the order of execution, just like in init or modern xorg.conf.d.

To execute these files add the following to ~/.XClients file:


if [ -d $HOME/.xclients.d ]; then
  for file in $(find $HOME/.xclients.d -type f | sort); do
    exec $file

Adding applications

I did all the packaging, so I added 10-application.sh files to applications’ rpms.


# ~/.xclients.d/10-application.sh

/path/to/application & # <= notice the ampersand, this application is interactive
                       # and would hang further execution,
                       # thus must be datached


Spawning multiple instances of the application

As you detach the application from shell (as I did in previous section), they stay alive despite of shell spawned them. It’s your business to watch these don’t bloat the system. One way is to just check if it is running and kill it if so:


# ~/.xclients.d/10-application.sh

pgrep "^application" &>/dev/null
if [ $? -neq 0 ]; then
  pkill "^application"