I'd like to run a script if the Gnome session is locked and unlocked.
Is there a way that I can intercept this and perform certain actions when the desktop is locked or unlocked?
- 13,920
- 7
- 41
- 79
- 38,686
- 85
- 220
- 311
12 Answers
Gnome-screensaver emits some signals on dbus when something happens.
Here the documentation (with some examples).
You could write a scripts that runs:
dbus-monitor --session "type='signal',interface='org.gnome.ScreenSaver'"
and that does what you need anytime dbus-monitor prints a line about the screen being locked/unlocked.
Here a bash command to do what you need:
dbus-monitor --session "type='signal',interface='org.gnome.ScreenSaver'" |
while read x; do
case "$x" in
*"boolean true"*) echo SCREEN_LOCKED;;
*"boolean false"*) echo SCREEN_UNLOCKED;;
esac
done
Just replace echo SCREEN_LOCKED and echo SCREEN_UNLOCKED with what you need.
-
Hi @peoro, That makes me think you can unlock or lock gnome screen/session from a scripted program, worth doing some ssh tricks about it ;-) – Nikhil Mulley Jan 03 '12 at 05:13
-
2@Nikhil: to do that you don't need to play around with dbus: `gnome-screensaver-command` is already there. Passing `-a` to `gnome-screensaver-command` you'll lock the screen, while you'll unlock it with `-d`. Anyway most gnome apps use dbus extensively, so you'll be able to do many amazing things with it. – peoro Jan 03 '12 at 05:18
-
1@peoro Thanks great, very helpful! Can I also run this as some sort of daemon? When I enter this in the terminal now, it has to stay open to monitor the dbus for that case. I would like to execute this command at login and then it can be active during the entire session. – Sander Jan 04 '12 at 16:13
-
1I think things may have changed now in 2014? as the output doesnt change if the screen was only locked, it only shows something when it gets blanked and is very different from here :(, I created this question http://askubuntu.com/questions/505681/unity-how-to-detect-if-the-screen-is-locked, do you believe there is still some way to do that? thx! – Aquarius Power Aug 02 '14 at 02:18
-
How to run that script that it catches the lock event? Kinda like a watcher. – Starx Nov 01 '16 at 13:03
-
1Does anybody know how or where to hook this script to start listening on first login? – hanzo2001 Nov 29 '17 at 11:30
Nowadays I think it's better to listen to the LockedHint rather than screensaver messages. That way you're not tied to a screensaver implementation.
Here's a simple script to do that:
gdbus monitor -y -d org.freedesktop.login1 | grep LockedHint
Gives this:
/org/freedesktop/login1/session/_32: org.freedesktop.DBus.Properties.PropertiesChanged ('org.freedesktop.login1.Session', {'LockedHint': <true>}, @as [])
/org/freedesktop/login1/session/_32: org.freedesktop.DBus.Properties.PropertiesChanged ('org.freedesktop.login1.Session', {'LockedHint': <false>}, @as [])
- 361
- 3
- 3
-
1This approach with `gdbus monitor` is the one that worked for me on Ubuntu 20.04 with Gnome 3. Packaged it as a script if you want to use it as a building block for automation: https://github.com/gogama/lockheed. – 0xbe5077ed Nov 04 '22 at 17:52
In ubuntu 14.04 the DBus event for screen lock unlock has changed and the new script for binding to screen lock and unlock events looks like the following
dbus-monitor --session "type='signal',interface='com.ubuntu.Upstart0_6'" | \
(
while true; do
read X
if echo $X | grep "desktop-lock" &> /dev/null; then
SCREEN_LOCKED;
elif echo $X | grep "desktop-unlock" &> /dev/null; then
SCREEN_UNLOCKED;
fi
done
)
- 341
- 2
- 5
-
-
2
-
@JacobVlijm Thanks for testing this and green-lighting it for me to use tonight :) – WinEunuuchs2Unix Dec 08 '16 at 00:44
Expanding on already given answer.
If you try to run a script from inside a screen or tmux session, you'll need to find the correct $DBUS_SESSION_BUS_ADDRESS first and pass it as an argument for dbus-monitor instead of --session. Also if you're running it as a daemon you should make sure only one instance is running at a time (e.g. with a lock file) and that the script cleans up after itself with trap. The following example will work as a daemon in most current Gnome environments (tested on Ubuntu GNOME 16.04):
#!/bin/bash
set -o nounset # good practice, exit if unset variable used
pidfile=/tmp/lastauth.pid # lock file path
logfile=/tmp/lastauth.log # log file path
cleanup() { # when cleaning up:
rm -f $pidfile # * remove the lock file
trap - INT TERM EXIT # * reset kernel signal catching
exit # * stop the daemon
}
log() { # simple logging format example
echo $(date +%Y-%m-%d\ %X) -- $USER -- "$@" >> $logfile
}
if [ -e "$pidfile" ]; then # if lock file exists, exit
log $0 already running...
exit
fi
trap cleanup INT TERM EXIT # call cleanup() if e.g. killed
log daemon started...
echo $$ > $pidfile # create lock file with own PID inside
# usually `dbus-daemon` address can be guessed (`-s` returns 1st PID found)
export $(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$(pidof -s dbus-daemon)/environ)
expr='type=signal,interface=org.gnome.ScreenSaver' # DBus watch expression here
dbus-monitor --address $DBUS_SESSION_BUS_ADDRESS "$expr" | \
while read line; do
case "$line" in
*"boolean true"*) log session locked;;
*"boolean false"*) log session unlocked;;
esac
done
cleanup # let's not leave orphaned lock file when the loop ends (e.g. dbus dies)
If this doesn't work for you, it's probably because:
- you don't use Gnome - check other answers for better DBus watch expression.
- you run multiple DBus lines - check details on how to make PID finding deterministic.
-
1This actually answers a different question I had for dynamically discovering the DBus session information given a user account, which I have solved [here](https://gist.github.com/naftulikay/f4c229b3c71fff9ac2102a0e03bd756f). Thanks for your contribution here! – Naftuli Kay Jun 02 '17 at 05:10
-
-
1Nice solution with great techniques within. To suppress `bash: warning: command substitution: ignored null byte in input`, I suggest: `export $(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$(pidof -s dbus-daemon)/environ|xargs -0)`. – fbicknel Jan 31 '22 at 21:45
If you're on Kubuntu or using KDE / Plasma as your Desktop Environment, you have to listen for the interface org.freedesktop.ScreenSaver, so the script for listening to that event would look like this:
dbus-monitor --session "type='signal',interface='org.freedesktop.ScreenSaver'" |
while read x; do
case "$x" in
*"boolean true"*) echo SCREEN_LOCKED;;
*"boolean false"*) echo SCREEN_UNLOCKED;;
esac
done
- 330
- 2
- 11
-
4If you use KDE/Plasma you can use the Plasma Desktop settings to execute scripts on notifications... `Personalization>Notifications>Notifications>Screensaver`. – xenoid Apr 03 '19 at 12:40
-
thanks @xenoid ! KDE is such a personalizable de that you never have to fiddle with these things. its as if they anticipate what I need – Ankur S Sep 19 '19 at 13:32
Ubuntu 16.04: ozma’s solution did not work for me, however this one did:
dbus-monitor --session "type=signal,interface=com.canonical.Unity.Session,member=Unlocked" |
while read MSG; do
LOCK_STAT=`echo $MSG | awk '{print $NF}'`
if [[ "$LOCK_STAT" == "member=Unlocked" ]]; then
echo "was unlocked"
fi
done
- 181
- 1
- 5
this may not be the cleanest solution but it works for me when dbus-monitor ... does not:
gdbus monitor -y -d org.freedesktop.login1 |\
grep --line-buffered -i "LockedHint" |\
sed -uE 's/.*LockedHint.*<(.*)>.*/\1/g'
Should return stream of lines with strings 'true' or 'false'
Using: Fedora release 30 (Thirty)
- 21
- 1
-
appears to be an extension of [this answer](https://unix.stackexchange.com/a/449013/117549) – Jeff Schaller Nov 08 '19 at 14:34
Thanks for HaterTot comment another version. Tested on ubuntu 18.04
echo "start at `date`" >> ~/Documents/time-trecking.log
dbus-monitor --session "type=signal,interface=org.gnome.ScreenSaver" |
while read MSG; do
LOCK_STAT=`echo $MSG | grep boolean | awk '{print $2}'`
if [[ "$LOCK_STAT" == "true" ]]; then
echo "locked `date +%s` `date`" >> ~/Documents/time-trecking.log
elif [[ "$LOCK_STAT" == "false" ]]; then
echo "unlock `date +%s` `date`" >> ~/Documents/time-trecking.log
fi
done
[Before Edit] this is what worked for me in ubuntu 16.04
dbus-monitor --session "type=signal,interface=org.gnome.ScreenSaver" |
while read MSG; do
LOCK_STAT=`echo $MSG | grep boolean | awk '{print $2}'`
if [[ "$LOCK_STAT" == "true" ]]; then
echo "was locked"
else
echo "was un-locked"
fi
done
- 119
- 3
-
This didn't work for me. As it finished executing and does not listen to the state changed. – Starx Nov 01 '16 at 13:12
-
which screen saver are you using? gnome or xscreensaver? which flavor ubuntu, xubuntu, kubuntu etc. which version (it was tested on 16.04) – ozma Nov 01 '16 at 14:06
-
-
1this worked for me on Ubuntu 19.10, but for me the "else" condition kept triggering when other messages unrelated messages popped up on invocation. So I just changed the logic to explicitly check for "false" – HaterTot Mar 10 '20 at 17:02
-
1Might be easier to use a `case` rather than (non-portable) `[[`. Instead of `grep|awk`, consider using a single `awk` invocation (`awk '$1 == "boolean" {print $2}'`). – Toby Speight Oct 13 '22 at 15:55
Version for Cinnamon Desktop (Ubuntu 18.04):
dbus-monitor --session "type='signal',interface='org.cinnamon.ScreenSaver'" | \
(
while true; do
read X
if echo $X | grep "boolean true" &> /dev/null; then
echo `date` - SCREEN_LOCKED;
elif echo $X | grep "boolean false" &> /dev/null; then
echo `date` - SCREEN_UNLOCKED;
fi
done
)
- 11
- 1
upstart session jobs support desktop-lock and desktop-unlock events in start on stanza. Just create a job .conf for your user with relevant triggers and commands to call under $XDG_CONFIG_HOME/upstart/ or $HOME/.config/upstart like example below:
description "some job description"
start on desktop-lock
script
/path/to/your/executable
end script
- 328
- 1
- 6
For KDE Plasma, we can listen to org.freedesktop.ScreenSaver with:
dbus-monitor --session "type='signal',interface='org.freedesktop.ScreenSaver'"
But note that lock/unlock action are reported twice, the following script limit the action within 5 seconds (to avoid executing required command twice)
#!/bin/bash
screen_locked () {
if [[ $firstrun == '' ]] || [[ $(expr $(date +%s) - $firstrun) -ge 5 ]]
then
screen_locked_core;
firstrun=$(date +%s);
fi
}
screen_locked_core () {
echo locked
}
dbus-monitor --session "type='signal',interface='org.freedesktop.ScreenSaver'" |
while read x; do
case "$x" in
*"boolean true"*) screen_locked;;
# *"boolean false"*) screen_unlocked;;
esac
done
- 13,920
- 7
- 41
- 79
I used the same answer as peoro, but first I run only dbus-monitor --session "type='signal'" in a terminal, and locked an unlocked my screen. Then, I could figure out the correct name for my operating system:
signal time=1680812432.954794 sender=:1.27 -> destination=(null destination) serial=3080 path=/org/xfce/ScreenSaver; interface=org.xfce.ScreenSaver; member=ActiveChanged
boolean true
signal time=1680812435.757417 sender=:1.27 -> destination=(null destination) serial=3082 path=/org/xfce/ScreenSaver; interface=org.xfce.ScreenSaver; member=ActiveChanged
boolean false
So, my command starts with dbus-monitor --session "type='signal',interface='org.xfce.ScreenSaver'"' instead of dbus-monitor --session "type='signal',interface='org.gnome.ScreenSaver'".
- 731
- 2
- 11
- 20