Xsession is a default way of starting, well, nothing less but X sessions in
Debian. You can read about it in detail by running
man xsession, or read
source code of the script itself: /etc/X11/Xsession. It’s not very
complicated, but because it’s a shell script, it can be a little intimidating
for newcomers. That’s why I’m publishing this small introduction.
Keep in mind that it’s based on Debian Stretch (9.0, stable as of writing this article), so things might be anywhere from “a little different” to “totally irrelevant” for other Debian releases.
Xsession is itself quite straightforward. It first sets some environment
variables, does a little bookkeeping and then it sources all scripts from
/etc/X11/Xsession.d, one by one, with help of
run-parts. This is the place
where a lot of recommendations for Debian X session management is implemented,
like that a good place to auto start X applications is ~/.xsessionrc.
It is important to remember that all scripts in Xsession.d are sourced,
not executed. This way all variables, functions and flags (global
defined before are available for all consecutive scripts.
Some third-party packages may install their own scripts into Xsession.d (for
example flatpak does that). They’re usually transparent to end-user, but
sometimes they can be controlled one way or the other. Common way of adding
simple, user-controllable flags is Xsession.options file. Keep in mind
has_option function is defined by
20x11-common_process-args so if you want to process options with
help of this function, you have to ensure that your script is sourced after
Other scripts in Xsession.d are shipped by default for all Debian installations with X capabilities. These are the important ones, because they define common environment variables and functions which are re-used in other scripts.
This is where
$STARTUP variable is initialized. It’s quite important,
because it names a script or program which will be executed later as a
Users can directly affect executed command by passing a single optional
argument to Xsession and
common_process-args will process it and assign to
$STARTUP. This argument accepts also some special names, which are handled
- if it is set to failsafe, x-terminal-emulator will be executed (usually xterm, but it can be changed by update-alternatives mechanism) and processing of further scripts will be terminated;
- if it is set to default, the script won’t set
$STARTUP, which will result in a deduction of default session manager by
This script also defines
has_option function, used for parsing of
These 2 scripts are sourced right after Xsession arguments are processed.
First one merges all system-wide X resources files found in /etc/X11/Xresources and user-specific one from ~/.Xresources.
Second simply sources ~/.xsessionrc file, so all user-defined environment variables found there will be globally available for the whole X session from now on and commands will be executed (note that commands should typically be run in a background to not block execution of Xsession).
This script simply uses xhost to give access to X server to the local user.
If Xsession wasn’t passed any argument, or if passed argument is not
$STARTUP won’t be set and
common_determine-setup will run the
default discovery mechanism of what should be run instead:
- ~/.xsession and ~/.Xsession are tried (because some users apparently like to start their file names with capital letters).
- default system-wide session manager: x-session-manager
- default system-wide window manager: x-window-manager
- default system-wide terminal emulator: x-terminal-emulator
This one often confuses a lot of people. Historically, there always was a problem with finding a good and convienient way to run SSH Agent and even today a lot of people run it from their .bashrc every time new shell starts. Debian solved it by binding its start with start of X session.
Anyway, if no previous ssh-agent appears to be running (e.g. gpg-agent with
enabled support of OpenSSH Agent Protocol),
$STARTUP will be wrapped with
ssh-agent call and executed as agent’s subprocess.
Finally we execute our session manager, as
common_start is typically the last
file sourced by Xsession. It’s quite straightforward:
It replaces (via
exec) the current shell with command stored in
variable. This way executed command inherits the whole environment set up by
all previous scripts.
When Xsession will be run
Typically Xsession is sourced (not executed) whenever /etc/X11/xinit/xinitrc is executed. This is handled by startx script (but not xinit, which is wrapped by startx and by itself will only load .xinitrc from user’s home directory).
Xsession is also sourced by display managers, but there are no clear rules when Xsession is used, when it isn’t, and what arguments are passed to it. Documentation of most Display Managers also lacks this knowledge so often all you’re left is the good old trial and error.
This is the source of a lot of headaches about files not being read (or being read unintentionally) during startup. The rule of thumb is: configure your system to ensure Xsession is executed and you’re back on a well-known waters.
Lightdm allows configuring it to use a session-wrapper, which is a script to run session with. This is pre-configured to be Xsession in /usr/share/lightdm/lightdm.conf.d/01_debian.conf.
Typically all available types of X sessions are read in a form of .desktop files from /usr/share/xsessions and some other directories. On login screen Lightdm only allows selecting one of those and passes the value of its Exec field to the session-wrapper as the first argument, which will cause executing correct program.
There is a special .desktop file there, used for so-called “default sessions”,
which has Exec=default. It will be detected by
20x11-common_process-args and will result in running a fallback
mechanism described in
SDDM is a little more sane than Lightdm. It doesn’t have hidden settings or use any obscure features. For custom sessions it executes /etc/sddm/Xsession, which ultimately sources /etx/X11/Xsession itself.
SDDM tries to source .profile, .bash_profile, .zprofile etc. It’s a little unusual, because these files are usually boud to terminal sessions and graphical sessions usually source .xprofile.
GDM3 runs a bunch of scripts stored in different directories in /etc/gdm3, but ultimately one of them is /etc/gdm3/Xsession. Yep, it has a custom Xsession script, which is similar in some places to the default one, but also adds a bunch of its own logic. For example, if no argument is passed, it defaults to “failsafe” mode.
It doesn’t source the default Xsession, but sources scripts from /etc/X11/Xsession.d by itself. Before that it also tries to source profile and xprofile files.
It also aliases “default” session with a word “custom”.