LinkedIn Sourceforge Twitter

Vincent's Blog

Pleasure in the job puts perfection in the work (Aristote)

Nice looking and light login screen for xenodm

Posted on 2019-06-26 22:23:00 from Vincent in OpenBSD Desktop

In this blog, I will describe how I've build a simple, but still nice looking login screen based on xenodm.


I'm currently running OpenBSD 6.5.

As you know, xenodm is the default window manager that OpenBSD provides.

Since OpenBSD 6.5, it's the first interface that users will see when Xorg is selected during the installation process of OpenBSD. Before that release, xenodm was already present, but it was not activated by default. Until OpenBSD 6.5, I was simply using the command startx. I did the change because xenodm offers important security benefits.

I've searched on internet if someone has made something. And bingo!!!, I've found the blog of Joel Carnat. I invite you to check his xenodm's proposition.

An other source of inspiration, is the blog of Thuban. It's in french, but via google translate, you should understand it.

I've also used the Xresources file created by Artic Ice Studio


Without customisation, the login screen look like this:

My customized login screen looks like this:

How to build it

You need to create 3 files of xenodm located in /etc/X11/xenodm and you need to adapt one parameter in order to fit your screen's resolution.

You must download the famous Puffy logo and save it to the file: /etc/X11/xenodm/pixmaps/bluepuffy.gif.

doas ftp -o /etc/X11/xenodm/pixmaps/bluepuffy.gif

Lastly, you must install feh, our image display tool:

doas pkg_add feh

You must be sure that yoor xenodm-config file is unmodified. In any case, here after mine:

! $OpenBSD:,v 1.5 2018/11/03 18:04:45 matthieu Exp $
DisplayManager.authDir: /etc/X11/xenodm
DisplayManager.errorLogFile:    /var/log/xenodm.log
DisplayManager.servers:     /etc/X11/xenodm/Xservers
DisplayManager*resources:   /etc/X11/xenodm/Xresources
! All displays should use authorization, but we cannot be sure
! X terminals may not be configured that way, so they will require
! individual resource settings.
DisplayManager*authorize:   true
DisplayManager*startup:     /etc/X11/xenodm/Xstartup
DisplayManager*session:     /etc/X11/xenodm/Xsession
DisplayManager*reset:       /etc/X11/xenodm/Xreset
DisplayManager*authComplain:    true
! The following three resources set up display :0 as the console.
DisplayManager._0.setup:    /etc/X11/xenodm/Xsetup_0
DisplayManager._0.startup:  /etc/X11/xenodm/GiveConsole
DisplayManager._0.reset:    /etc/X11/xenodm/TakeConsole

DisplayManager.*.authName:  MIT-MAGIC-COOKIE-1


The 1st file we will adapt is: Xresources.

This file contains basic info about fonts, colors and login/password position on your screen.

Here after mine inspired by a file posted on Github by Artic Ice Studio under the MIT license.

This file contains the first element you will have to adapt: xlogin.Login.y.

I have a screen resolution of 1920x1080, so, I'll put the Login and password prompt at 700 pixels from the top.
Please adapt it to the height of your screen.

Optionally, you could also adapt the font size of xmessage. In such case, you should also adapt the Xsetup_0 file.

! ----------------------------------------------------------------------
! Nord colorscheme
! File:!
#define nord0 #203051
#define nord1 #3B4252
#define nord4 #D8DEE9
#define nord11 #BF616A

DisplayManager*terminateServer: true

xroot.background: nord0

! ----------------------------------------------------------------------
! XLogin

xlogin.Login.allowRootLogin: false
xlogin.Login.echoPasswd:   false         Authorization failed

xlogin.Login.y:                700
xlogin.Login.width:            480
xlogin*borderWidth:            0
xlogin.Login.frameWidth:       0
xlogin.Login.innerFramesWidth: 0
xlogin.Login.sepWidth:         0

xlogin.Login.background:  nord0
xlogin.Login.foreground:  nord4
xlogin.Login.failColor:   nord11
xlogin.Login.greetColor:  nord0
xlogin.Login.inpColor:    nord1
xlogin.Login.promptColor: nord0

xlogin.Login.face:       DejaVu Sans-16
xlogin.Login.failFace:   DejaVu Sans-18:bold
xlogin.Login.greetFace:  DejaVu Sans-0
xlogin.Login.promptFace: DejaVu Sans-18

! ----------------------------------------------------------------------
! XClock

xclock*background:       nord0
xclock*foreground:       nord4
xclock*borderWidth:      0
xclock*font:             -*-terminus-bold-*-*-*-16-*-*-*-*-*-iso8859-15
xclock.Clock.analog:     false
xclock.Clock.chime:      false
xclock.Clock.render:     false
xclock.Clock.twentyfour: true
xclock.Clock.update:     10

! ----------------------------------------------------------------------
! XMessage

xmessage*background: nord0
xmessage*foreground: nord4
xmessage*borderWidth: 0
xmessage*font: -*-terminus-bold-*-*-*-24-*-*-*-*-*-iso8859-15
xmessage*message.scrollHorizontal: Never
xmessage*message.scrollVertical: Never
xmessage*timeout: 0


Here after the GiveConsole file you have to use. You can use it as it is.

# Assign ownership of the console to the invoking user
# $OpenBSD: GiveConsole,v 1.2 2018/07/11 19:20:40 matthieu Exp $

pkill feh
pkill xclock
pkill xmessage

chown $USER /dev/console
if [ -c /dev/drm0 ]; then
    chown $USER /dev/drm0
/usr/X11R6/bin/sessreg -a -l $DISPLAY -u none $USER


Here after my Xsetup file.
This file tries to be as flexible as possible.
Nevertheless, you will have to adapt the PUFFY_WIDTH variable. Indeed, this variable takes into account the position of the Login's prompt as specified in the Xresources's file. You will recognize the value of 700 like I've specified in my Xresources file.

Except that, all the rest should automatically align all element on your screen.

This script allow you to display the Blue Puffy logo, a text at the top right of the screen with the machine's name the keyboard mapping and time.

The script adds, at the bottom of the screen, 3 commands: Sleep, Restart, shutdown.


/usr/X11R6/bin/xrandr --output default --dpi 96

# requires pkg_add terminus-font
/usr/X11R6/bin/xset fp+ /usr/local/share/fonts/terminus

# set background color
/usr/X11R6/bin/xsetroot -solid $BG_COLOR

SIZES=$(/usr/X11R6/bin/xrandr | /usr/bin/awk ' /\*/ { print $1}' )
WIDTH=$(echo $SIZES | /usr/bin/cut -d "x" -f 1)
HEIGHT=$(echo $SIZES | /usr/bin/cut -d "x" -f 2)
PUFFY_WIDTH=$(( $HEIGHT - 700))  #700 is xlogin.Login.y coming from the Xresources file
POSX=$(( ( $WIDTH - $PUFFY_WIDTH ) / 2 ))
POSY=$(( $HEIGHT * 10 / 100 ))

# show BluePuffy 
/usr/local/bin/feh -B $BG_COLOR -g ${PUFFY_WIDTH}x${PUFFY_WIDTH}+$POSX+$POSY -. -Z /etc/X11/xenodm/pixmaps/bluepuffy.gif &

# show the Sleep / Restart / Shutdown bar
# in case of sleep, pop xmessage again after waking up
while true; do
  #to position the text at the middle of the screen
  POS=$(( ( $WIDTH - 12*34 ) / 2  ))  #text is 34 char, 12 is linked to the size of font select in Xresources
  /usr/X11R6/bin/xmessage -geometry +$POS-150         -buttons "[ Sleep ]":20,"[ Restart ]":21,"[ Shutdown ]":22 ""
  echo "Xmessage said: $ACTION"
  if   [ $ACTION -eq 20 ]; then /usr/sbin/zzz;
  elif [ $ACTION -eq 21 ]; then
    /usr/X11R6/bin/xsetroot -cursor_name watch
    /sbin/shutdown -r now
  elif [ $ACTION -eq 22 ]; then
    /usr/X11R6/bin/xsetroot -cursor_name watch
    /sbin/shutdown -p now
  else echo "Something bad happened to Xmessage.";
  # stop looping if xclock died (hopefully killed by GiveConsole)
  if [ -z "$(/usr/bin/pgrep -U root xclock)" ]; then break; fi
) &

OS_NAME=$(/usr/bin/uname -n)
OS_INFO=$(/usr/bin/uname -smr)
KEYBD=$(/usr/X11R6/bin/setxkbmap -print | grep xkb_symbols | cut -d"+" -f2)

/usr/X11R6/bin/xclock -geometry -0+20       -strftime "$OS_NAME ($OS_INFO) Keyboard: $KEYBD | %a. %d %b. %Y  %H:%M:%S " &

48, 45
displayed: 13414

1. From rjc on Wed Jun 26 23:25:46 2019

A couple of small nits:


WIDTH=$(echo $SIZES | /usr/bin/cut -d "x" -f 1)
HEIGHT=$(echo $SIZES | /usr/bin/cut -d "x" -f 2)

No need to run `cut(1)` in a subshell twice there. The above can be trivially replaced by:



POSY=$(( $HEIGHT * 10 / 100 ))

Times 10 divided by 100? Huh? Why not this?

POSY=$(( $HEIGHT / 10 ))


I can understand the alignment in:

if [ $ACTION -eq 20 ]; then /usr/sbin/zzz;

but if there's no `else`, why not use this instead?

test $ACTION -eq 20 && /usr/sbin/zzz

Also, not need for `;` at the end of the lines.


if [ -z "$(/usr/bin/pgrep -U root xclock)" ]; then break; fi

can be simplified:

/usr/bin/pgrep -qx -U root xclock || break


KEYBD=$(/usr/X11R6/bin/setxkbmap -print | grep xkb_symbols | cut -d"+" -f2)

can be simplified to:

KEYBD=$(/usr/X11R6/bin/setxkbmap -query | awk '/layout:/ { print $2 }')

2. From Vincent on Fri Jun 28 09:54:26 2019

Thanks rjc for the propositions. I'll check them and adapt the scripts accordingly.

What is the first letter of the word Python?