Tmux & x11 playing nicely

Steven Buczkowski

Le Problème (The Problem)

Tmux and screen sessions preserve their DISPLAY environment variable across cycles of detach and re-attach but the underlying login session (which drives the path to the actual DISPLAY in use) does not. In other words, a fresh ssh and tmux session may give you DISPLAY=maya-usr1:121.0 but, now disconnect from tmux and logout from maya. When you ssh in next, maya may put you on DISPLAY=maya-usr1:32.0. However, the old tmux session still has the :121.0 display and x11 will not forward windows out until you sync up the DISPLAY variables. You can do this by hand copying the contents of $DISPLAY from your login shell on maya/maya2 and exporting this value inside your tmux windows or,

you can do this automatically by putting the following functions into your .bashrc.

# automate X11 DISPLAY reset for better use in tmux
update-x11-forwarding()
{
    if [ -z "$STY" -a -z "$TMUX" ]; then
        echo $DISPLAY > ~/.display.txt
    else
        export DISPLAY=$(cat ~/.display.txt)
    fi
}

# and run this before every command
preexec()
{
    [ "$BASH_COMMAND" = "$PROMPT_COMMAND" ] && return

    update-x11-forwarding
}
trap 'preexec' DEBUG

The first function looks to see if the current login is through tmux or screen. If not, then store the currrent DISPLAY variable setting for later use as this may be a new login and new DISPLAY. If yes, then pull the previously stored DISPLAY variable value and export it into the current shell environment.

The second runs this first function everytime you run a command at the command line. This way, you can reattach to a tmux session, type any command and get an updated DISPLAY. Further, it updates DISPLAY before executing the requested command so, it should work fine even if your first command would need access to the updated DISPLAY value.

Caveat

If you leave something running under tmux that makes it difficult/impossible to change the environment variables it is running under, you will likely have to exit that program and restart it.

e.g. If you run matlab within emacs under tmux, you do still have to quit emacs and restart it and matlab for the DISPLAY changes to take effect despite the underlying shell getting updated. I haven’t found a way to force emacs to update it’s environment while it’s running much less to then force a similar update on matlab. I think users used to be able to change the display through the figure handle but, that field appears to no longer be editable.