As you may or may not know , a lot of Unity actions are implemented using dbus . The big convenience about dbus is that you can perform lots of root-required actions by calling appropriate methods in command-line without need of having admin account, for instance shutting down your system.
Specifically in our case here we are interested in
/com/canonical/Unity/Session path. You can list information about it with
qdbus command. Particularly we're interested in signals that have
Requested in them.
$ qdbus com.canonical.Unity /com/canonical/Unity/Session | grep 'signal.*Requested.*'
signal void com.canonical.Unity.Session.LockRequested()
signal void com.canonical.Unity.Session.LogoutRequested(bool have_inhibitors)
signal void com.canonical.Unity.Session.RebootRequested(bool have_inhibitors)
signal void com.canonical.Unity.Session.ShutdownRequested(bool have_inhibitors)
signal void com.canonical.Unity.Session.UnlockRequested()
These signals appear on the bus when user clicks any of the shutdown, lock, logout, or reboot items in the drop-down session menu on the right side of the Unity's top bar. So what we need to do is this:
- monitor the bus for those signals to appear.
- once they appear - perform a certain action.
Of course , the big disclamer is that if a user uses
sudo shutdown -P now or
gnome-session-quit , that won't be told to the
dbus , so whatever action is wanted won't be done.
Monitoring the dbus
Conveniently there is a command for that,
dbus-monitor and we can filter its output using a set of options, and perform an action on it using
while read do … done structure
Bellow is an example of a simple monitoring script.
dbus-monitor --profile "interface='com.canonical.Unity.Session',type=signal" | \
while read -r line;
What it does is merely monitor the bus for signals , and echo them back to stdout if they appear; of course echo could be any command. Run it , and try clicking on each item in the session menu that should generate signals, and you should see something like this:
sig 1458319246 172587 2 /org/freedesktop/DBus org.freedesktop.DBus NameAcquired
sig 1458319251 213766 5496 /com/canonical/Unity/Session com.canonical.Unity.Session RebootRequested
sig 1458319265 62555 5525 /com/canonical/Unity/Session com.canonical.Unity.Session LogoutRequested
sig 1458319271 856770 5555 /com/canonical/Unity/Session com.canonical.Unity.Session LockRequested
sig 1458319273 223940 5564 /com/canonical/Unity/Session com.canonical.Unity.Session Locked
sig 1458319276 991413 5604 /com/canonical/Unity/Session com.canonical.Unity.Session UnlockRequested
sig 1458319278 3443 5606 /com/canonical/Unity/Session com.canonical.Unity.Session Unlocked
So now we have a monitoring function that can perform an action once an interrupt occurs. Now , to address the specific question that you were trying to solve , your script is taking snapshots of the icons on the desktop. There's no harm done if we take snapshot each time a signal occurs - it doesn't have to be reboot or shutdown specifically. So if we monitor that specific Unity interface for signals and take snapshots upon each signal's arrival, we can simplify the scripting.
Bellow you can see an interrupt-driven script which will monitor the bus for signals (ignoring the first one ) and if we have a signal coming in , then call an interrupt function (which in your case will be the icon snapshot script that you've written).
dbus-monitor --profile "interface='com.canonical.Unity.Session',type=signal" |
while read -r line;
grep -q '.*NameAcquired.*' <<< "$line" && continue # Ignore that first line
if [ -n "$line" ];then
interrupt $ARG # call your python snapshot script here
echo 'Old McDonald had a ' $ARG ' e-i-e-i-o '
NOTE: Dbus relies on having GUI session , since (as far as I know) it starts with Unity/Gnome login. Older environments such as blackbox and openbox, as well as TTY environments do not start dbus session, hence that script will puke if you try to launch it in
~/.profile (I had one user who tried to do something like that and he got into trouble). Start such script using Unity's or Gnome's Startup Applications program.
Going beyond this script
- Dbus has a lot of API's including python
- I prefer using
qdbus because it's simple, but one could always use
dbus-send . Examples
- The interrupt function can be anything, even other
dbus methods. There's a lot to look into.
Trivia: I've used this same method for preventing shutdown if apt is running