18

In Ubuntu 12.04 LTS, I would like to run scripts after resuming from suspend, and after unlocking my desktop. These need to run as my user, and with access to my $DISPLAY.

In particular, I would like to

  • restart nm-applet to work around bug 985028
  • show a custom notification using notify-send
  • possibly other stuff when I get these working

When I resume, scripts in /etc/pm/sleep.d/ are run, but they run as root, without knowledge of my screen and username. It might work if I hard-code my username and export the default DISPLAY :0 in these scripts, but that feels like a very ugly hack.

Scripts in ~/.config/autostart/xyz.desktop run after login, but they don't run after merely unlocking the screen after resume.

Is there a way to run scripts after unlocking the screen after a resume?

Zanna
  • 70,465
mivk
  • 5,312
  • To not hard code the username, you could use users, assuming that no one else is logged in. (or it doesn't matter) – Sparhawk Jun 03 '13 at 16:27

4 Answers4

9

It looks like you have to hard code the username in the previous answer anyways, so here's a simple script for in /etc/pm/sleep.d if anyone is looking for a quick fix:

#!/bin/bash 
case "$1" in
    hibernate|suspend)
        sudo -u USERNAME env DISPLAY=:0 zenity --info --text "do stuff on suspend"
        ;;
    thaw|resume)
        sudo -u USERNAME env DISPLAY=:0 zenity --info --text "do stuff on resume"
        ;;
esac
Sparhawk
  • 6,929
7

This question at the Unix & Linux site documents an alternative approach using dbus messages:

dbus-monitor --session "type='signal',interface='org.gnome.ScreenSaver'" | \
( while true; do
    read X;
    if echo $X | grep "boolean true" &> /dev/null; then
        SCREEN_LOCKED;
    elif echo $X | grep "boolean false" &> /dev/null; then
        SCREEN_UNLOCKED;
        fi
done )

(Replace SCREEN_LOCKED and SCREEN_UNLOCKED with the actions you want to perform.)

Using xrandr 1>/dev/null 2>1 as the action on unlocking fixed my problem that monitor resolutions/positions were not being correctly restored on screen unlocking (xrandr seems to cause a re-reading of screen settings). I added this line as a background task in my .bash_profile (strictly it might be better as a desktop file in ~/.config/autostart, since that only runs when you start gnome):

dbus-monitor --session "type='signal',interface='org.gnome.ScreenSaver'" | \
( while true; do
    read X;
    if echo $X | grep "boolean false" &> /dev/null; then
        xrandr 1>/dev/null 2>1;
        fi
done ) &

Further background on the gnome-screensaver API can be found at this site, and on the dbus monitor here.

Kim SJ
  • 71
  • 1
  • 4
  • Here's a variant that works on Ubuntu 20.04 with Gnome 3. It roughly the same approach but gdbus-monitor and allows you to run arbitrary commands with some level of resilience. https://github.com/gogama/lockheed – 0xbe5077ed Nov 04 '22 at 17:48
1

One solution is a script which runs when logging into the desktop, and which catches dbus messages. After resume from suspend the screen is locked, and after entering the password, there is an Unlock event on dbus.

(Thanks to Kim SJ for putting me on the right track. I have no ScreenSaver signals, but found another interface to use).

In ~/.config/autostart/, I have a .desktop file which starts a bash script:

$ cat ~/.config/autostart/mymonitor.desktop
[Desktop Entry]
Categories=System;Monitor;
Comment=Monitor dbus for unlock signals
Exec=/usr/local/bin/unlock_monitor
Name=unlock_monitor
Type=Application

The unlock_monitor monitor script reads dbus messages from com.canonical.Unity.Session and does stuff on Unlocked signals:

#!/bin/bash

dbus-monitor --session "type=signal,interface=com.canonical.Unity.Session" --profile \
| while read dbusmsg; do
    if [[ "$dbusmsg" =~ Unlocked$ || "$dbusmsg" =~ NameAcquired$ ]] ; then
        sleep 5
        notify-send "$(basename $0)" "Unlocked or freshly logged in..."
        # ...
    fi
done

When logging in, there is no "Unlocked" signal, but there is a "NameAcquired" signal when dbus-monitor starts.

mivk
  • 5,312
0

You can run a script using start-stop-daemon. start-stop-daemon can fork the thread running as different uid and gid, hence solving your problem.

What you need to do is to write a job script placed in system PATH like /usr/bin, and to create an extra daemon script in /etc/pm/sleep.d. Matching pm-suspend action like resume or thaw the daemon script commits the job script via

start-stop-daemon --start $ARGs --name nm-rtvt--exec /usr/bin/job_script

where ARGs could be --chuid 1001:1001 or just --user your_username.

And for integrity, you might as well want the daemon script to stop the damon named nm-rtvt before suspend via

start-stop-daemon --stop <...>

matching pm-suspend actions like suspend or hibernate.

For details, man start-stop-daemon. And there are many other examples in /etc/init.d of daemon scripts.

Zanna
  • 70,465
funicorn
  • 3,866