summaryrefslogtreecommitdiff
path: root/public/x11-systemd.md
diff options
context:
space:
mode:
Diffstat (limited to 'public/x11-systemd.md')
-rw-r--r--public/x11-systemd.md210
1 files changed, 105 insertions, 105 deletions
diff --git a/public/x11-systemd.md b/public/x11-systemd.md
index 6c37895..a24a49b 100644
--- a/public/x11-systemd.md
+++ b/public/x11-systemd.md
@@ -23,11 +23,11 @@ This means that all of my graphical units take `DISPLAY` as an `@`
argument. To get this to all work out, this goes in each `.service`
file, unless otherwise noted:
- [Unit]
- After=X11@%i.target
- Requisite=X11@%i.target
- [Service]
- Environment=DISPLAY=%I
+ [Unit]
+ After=X11@%i.target
+ Requisite=X11@%i.target
+ [Service]
+ Environment=DISPLAY=%I
We'll get to `X11@.target` later, what it says is "I should only be
running if X11 is running".
@@ -47,12 +47,12 @@ Xorg requires a TTY to run on; if we log in to a TTY with `logind`, it
will give us the `XDG_VTNR` variable to tell us which one we have, so
I pass this to `X` in [my `.xserverrc`][X11/serverrc]:
- #!/hint/sh
- if [ -z "$XDG_VTNR" ]; then
- exec /usr/bin/X -nolisten tcp "$@"
- else
- exec /usr/bin/X -nolisten tcp "$@" vt$XDG_VTNR
- fi
+ #!/hint/sh
+ if [ -z "$XDG_VTNR" ]; then
+ exec /usr/bin/X -nolisten tcp "$@"
+ else
+ exec /usr/bin/X -nolisten tcp "$@" vt$XDG_VTNR
+ fi
This was the default for [a while][arch-addvt] in Arch, to support
`logind`, but was [later removed][arch-delvt] in part because `startx`
@@ -65,21 +65,21 @@ So I copy/pasted it into my user `xserverrc`.
That's the boring part, though. Where the magic starts happening is
in [my `.xinitrc`][X11/clientrc]:
- #!/hint/sh
-
- if [ -z "$XDG_RUNTIME_DIR" ]; then
- printf "XDG_RUNTIME_DIR isn't set\n" >&2
- exit 6
- fi
-
- _DISPLAY="$(systemd-escape -- "$DISPLAY")"
- trap "rm -f $(printf '%q' "${XDG_RUNTIME_DIR}/x11-wm@${_DISPLAY}")" EXIT
- mkfifo "${XDG_RUNTIME_DIR}/x11-wm@${_DISPLAY}"
-
- cat < "${XDG_RUNTIME_DIR}/x11-wm@${_DISPLAY}" &
- systemctl --user start "X11@${_DISPLAY}.target" &
- wait
- systemctl --user stop "X11@${_DISPLAY}.target"
+ #!/hint/sh
+
+ if [ -z "$XDG_RUNTIME_DIR" ]; then
+ printf "XDG_RUNTIME_DIR isn't set\n" >&2
+ exit 6
+ fi
+
+ _DISPLAY="$(systemd-escape -- "$DISPLAY")"
+ trap "rm -f $(printf '%q' "${XDG_RUNTIME_DIR}/x11-wm@${_DISPLAY}")" EXIT
+ mkfifo "${XDG_RUNTIME_DIR}/x11-wm@${_DISPLAY}"
+
+ cat < "${XDG_RUNTIME_DIR}/x11-wm@${_DISPLAY}" &
+ systemctl --user start "X11@${_DISPLAY}.target" &
+ wait
+ systemctl --user stop "X11@${_DISPLAY}.target"
There are two contracts/interfaces here: the `X11@DISPLAY.target`
systemd target, and the `${XDG_RUNTIME_DIR}/x11-wm@DISPLAY` named
@@ -95,7 +95,7 @@ window manager exits, the pipe will get closed, sending EOF to the
The window manager (WMII) is made to have the pipe opened by executing
it this way in [its `.service` file][wmii@.service]:
- ExecStart=/usr/bin/env bash -c 'exec 8>${XDG_RUNTIME_DIR}/x11-wm@%I; exec wmii'
+ ExecStart=/usr/bin/env bash -c 'exec 8>${XDG_RUNTIME_DIR}/x11-wm@%I; exec wmii'
which just opens the file on file descriptor 8, then launches the
window manager normally. The only further logic required by the
@@ -103,24 +103,24 @@ window manager with regard to the pipe is that in the window manager
[configuration][wmii/config.sh], I should close that file descriptor
after forking any process that isn't "part of" the window manager:
- runcmd() (
- ...
- exec 8>&- # xinit/systemd handshake
- ...
- )
+ runcmd() (
+ ...
+ exec 8>&- # xinit/systemd handshake
+ ...
+ )
So, back to the `X11@DISPLAY.target`; I configure what it "does" with
symlinks in the `.requires` and `.wants` directories:
<ul class=tree><li>[.config/systemd/user/][systemd/user]
-* [X11@.target][]
-* [X11@.target.requires][]/
+ * [X11@.target][]
+ * [X11@.target.requires][]/
+ wmii@.service -> ../[wmii@.service][]
-* [X11@.target.wants][]/
+ * [X11@.target.wants][]/
+ xmodmap@.service -> ../[xmodmap@.service][]
+ xresources-dpi@.service -> ../[xresources-dpi@.service][]
- - doodle
+ - doodle
+ xresources@.service -> ../[xresources@.service][]
</li></ul>
@@ -154,9 +154,9 @@ isn't. Anyway, Mozilla's change drove me to to create a
display resolution. Disclaimer: I have no idea if it works if the X
server has multiple displays (with possibly varying resolution).
- #!/usr/bin/env bash
- dpi=$(LC_ALL=C xdpyinfo|sed -rn 's/^\s*resolution:\s*(.*) dots per inch$/\1/p')
- xrdb -merge <<<"Xft.dpi: ${dpi}"
+ #!/usr/bin/env bash
+ dpi=$(LC_ALL=C xdpyinfo|sed -rn 's/^\s*resolution:\s*(.*) dots per inch$/\1/p')
+ xrdb -merge <<<"Xft.dpi: ${dpi}"
Since we want XRDB to be set up before any other programs launch, we
give both of the `xresources` units `Before=X11@%i.target` (instead of
@@ -174,7 +174,7 @@ I've stuck them in a directory `wmii@.service.wants`:
<ul class=tree><li>[.config/systemd/user/][systemd/user]
-* [wmii@.service.wants][]/
+ * [wmii@.service.wants][]/
+ dunst@.service -> ../[dunst@.service][]        # a notification daemon
+ lxpanel@.service -> ../[lxpanel@.service][]    # a system panel
+ rbar@97_acpi.service -> ../[rbar@.service][]   # wmii stuff
@@ -189,7 +189,7 @@ and call it a day (and I did for a while). But, I like to have
[my WMII configuration][wmii/config.sh] stick this in the WMII
[`/rules`][wmii/rules]:
- /panel/ tags=/.*/ floating=always
+ /panel/ tags=/.*/ floating=always
Unfortunately, for this to work, `lxpanel` must be started _after_
that gets inserted into WMII's rules. That wasn't a problem
@@ -199,26 +199,26 @@ way of notifying systemd that WMII's fully started, and it's safe to
start `lxpanel`. So, I stuck this in
[my WMII `.service` file][wmii@.service]:
- # This assumes that you write READY=1 to $NOTIFY_SOCKET in wmiirc
- Type=notify
- NotifyAccess=all
+ # This assumes that you write READY=1 to $NOTIFY_SOCKET in wmiirc
+ Type=notify
+ NotifyAccess=all
and this in [my WMII configuration][wmii/wmiirc]:
- systemd-notify --ready || true
+ systemd-notify --ready || true
Now, this setup means that `NOTIFY_SOCKET` is set for all the children
of `wmii`; I'd rather not have it leak into the applications that I
start from the window manager, so I also stuck `unset NOTIFY_SOCKET`
after forking a process that isn't part of the window manager:
- runcmd() (
- ...
- unset NOTIFY_SOCKET # systemd
- ...
- exec 8>&- # xinit/systemd handshake
- ...
- )
+ runcmd() (
+ ...
+ unset NOTIFY_SOCKET # systemd
+ ...
+ exec 8>&- # xinit/systemd handshake
+ ...
+ )
Unfortunately, because of a couple of [bugs][sd-slash] and
[race conditions][sd-esrch] in systemd, `systemd-notify` isn't
@@ -238,7 +238,7 @@ getting EOF from the `UNIX-SENDTO` end will ever be faster than the
systemd manager from handling the datagram that got sent. Which is to
say, "we work around the race condition by being slow and shitty."
- socat STDIO UNIX-SENDTO:"$NOTIFY_SOCKET" <<<READY=1 || true
+ socat STDIO UNIX-SENDTO:"$NOTIFY_SOCKET" <<<READY=1 || true
But, I don't like that. I'd rather write my WMII configuration to the
world as I wish it existed, and have workarounds encapsulated
@@ -247,46 +247,46 @@ elsewhere;
So, I wrote a `systemd-notify` compatible
[function][wmii/workarounds.sh] that ultimately calls `socat`:
- ##
- # Just like systemd-notify(1), but slower, which is a shitty
- # workaround for a race condition in systemd.
- ##
- systemd-notify() {
- local args
- args="$(getopt -n systemd-notify -o h -l help,version,ready,pid::,status:,booted -- "$@")"
- ret=$?; [[ $ret == 0 ]] || return $ret
- eval set -- "$args"
-
- local arg_ready=false
- local arg_pid=0
- local arg_status=
- while [[ $# -gt 0 ]]; do
- case "$1" in
- -h|--help) command systemd-notify --help; return $?;;
- --version) command systemd-notify --version; return $?;;
- --ready) arg_ready=true; shift 1;;
- --pid) arg_pid=${2:-$$}; shift 2;;
- --status) arg_status=$2; shift 2;;
- --booted) command systemd-notify --booted; return $?;;
- --) shift 1; break;;
- esac
- done
-
- local our_env=()
- if $arg_ready; then
- our_env+=("READY=1")
- fi
- if [[ -n "$arg_status" ]]; then
- our_env+=("STATUS=$arg_status")
- fi
- if [[ "$arg_pid" -gt 0 ]]; then
- our_env+=("MAINPID=$arg_pid")
- fi
- our_env+=("$@")
- local n
- printf -v n '%s\n' "${our_env[@]}"
- socat STDIO UNIX-SENDTO:"$NOTIFY_SOCKET" <<<"$n"
- }
+ ##
+ # Just like systemd-notify(1), but slower, which is a shitty
+ # workaround for a race condition in systemd.
+ ##
+ systemd-notify() {
+ local args
+ args="$(getopt -n systemd-notify -o h -l help,version,ready,pid::,status:,booted -- "$@")"
+ ret=$?; [[ $ret == 0 ]] || return $ret
+ eval set -- "$args"
+
+ local arg_ready=false
+ local arg_pid=0
+ local arg_status=
+ while [[ $# -gt 0 ]]; do
+ case "$1" in
+ -h|--help) command systemd-notify --help; return $?;;
+ --version) command systemd-notify --version; return $?;;
+ --ready) arg_ready=true; shift 1;;
+ --pid) arg_pid=${2:-$$}; shift 2;;
+ --status) arg_status=$2; shift 2;;
+ --booted) command systemd-notify --booted; return $?;;
+ --) shift 1; break;;
+ esac
+ done
+
+ local our_env=()
+ if $arg_ready; then
+ our_env+=("READY=1")
+ fi
+ if [[ -n "$arg_status" ]]; then
+ our_env+=("STATUS=$arg_status")
+ fi
+ if [[ "$arg_pid" -gt 0 ]]; then
+ our_env+=("MAINPID=$arg_pid")
+ fi
+ our_env+=("$@")
+ local n
+ printf -v n '%s\n' "${our_env[@]}"
+ socat STDIO UNIX-SENDTO:"$NOTIFY_SOCKET" <<<"$n"
+ }
So, one day when the systemd bugs have been fixed (and presumably the
Linux kernel supports passing the cgroup of a process as part of its
@@ -302,12 +302,12 @@ why should I couple them? Instead, I create
[`wm-running@.target`][wm-running@.target] that can be used as a
synchronization point:
- # wmii@.service
- Before=wm-running@%i.target
+ # wmii@.service
+ Before=wm-running@%i.target
- # lxpanel@.service
- After=X11@%i.target wm-running@%i.target
- Requires=wm-running@%i.target
+ # lxpanel@.service
+ After=X11@%i.target wm-running@%i.target
+ Requires=wm-running@%i.target
Finally, I have my desktop started and running. Now, I'd like for
programs that aren't part of the window manager to not dump their
@@ -316,13 +316,13 @@ record of which graphical programs crashed, and like to have a
prettier cgroup/process graph. So, I use `systemd-run` to run
external programs from the window manager:
- runcmd() (
- ...
- unset NOTIFY_SOCKET # systemd
- ...
- exec 8>&- # xinit/systemd handshake
- exec systemd-run --user --scope -- sh -c "$*"
- )
+ runcmd() (
+ ...
+ unset NOTIFY_SOCKET # systemd
+ ...
+ exec 8>&- # xinit/systemd handshake
+ exec systemd-run --user --scope -- sh -c "$*"
+ )
I run them as a scope instead of a service so that they inherit
environment variables, and don't have to mess with getting `DISPLAY`