Restoring GUI connectivity from screen

Posted on Thu 19 November 2009 by alex in geek

GNU Screen is one of the most useful tools in my arsenal. In the days before I used screen I used to make extensive use of Gnome Terminal's multiple tab functionality. I'd have one tab for edit/commit commands, one for running code, others for watching logs and the plethora of other tasks you may be doing while working on something. Whenever X went down (sadly a fairly common occurrence if you are a heavy Compiz user) I spent a significant amount of time recreating my terminal sessions.

With screen all that happens is the controlling terminal detaches, preserving all the running processes inside and allowing a simple reattach once you have a GUI again. As a bonus you can do this at any time, this is most useful when working from home. All I need to do is logon to my machine remotely and attach to the screen session and I can pick up from where I left of the previous day. It's also incredibly useful for servers. I read all my mail in Mutt running in a screen session on my server which I can attach to from anywhere on the net.

One problem however is GUI environments, specifically talking to various agents and the like. As the shell inside the screen never terminates the environment variables telling it how to talk to things like the Session Manager or the various other desktop agents will not be updated. So I spent a little time hacking up a solution to the problem. First of all I need to detect when in the GUI and dump the environment variables somewhere:

ENV_DUMP_FILE="${HOME}/current_${HOSTNAME}.env"
alias dump_env="env > ${ENV_DUMP_FILE}"

# If in a GUI dump the current environment
# This is not perfect, if you spawn an xterm out of your screen session it
# vape your carefully stored environment, so don't do that.
if [[ ${TERM} == "screen" ]]; then
    echo "In a screen session - run restore_gui_env to pick up GUI vars"
elif [[ ${TERM} == "linux" ]]; then
    echo "In a console session"
else
    echo "In a GUI session - dumping env in ${ENV_DUMP_FILE}"
    dump_env
fi

Once that is done I have a simple function I can run to slurp up the relevant environment variables into my current screen session:

# Restore a single environment variable from ${ENV_DUMP_FILE}
function restore_env_var
{
    if [[ "$1"  && -f ${ENV_DUMP_FILE} ]]
    then
        line=`grep $1 ${ENV_DUMP_FILE}`
        delim=`expr index $line =`
        value=${line:$delim}
        echo "export $1=$value"
        export $1=$value
    fi
}

function restore_gui_env
{
    echo "Restoring GUI environment settings"
    restore_env_var DBUS_SESSION_BUS_ADDRESS
    restore_env_var XDG_SESSION_COOKIE
    restore_env_var DISPLAY
    restore_env_var SSH_AUTH_SOCK
    restore_env_var GPG_AGENT_INFO
    restore_env_var GNOME_KEYRING_SOCKET
}

It's not perfect, for example if I spawn a GUI shell from inside screen it could overwrite the current correct environment with stale data. However I think that's just a case of "don't do that then". The changes can be seen in context in my dotfiles repo.