Sunday, June 26, 2011

Run scripts when gnome-screensaver starts or stops in Ubuntu

For a project I have been playing with I need to be able to run a script when gnome-screensaver starts or stops on Ubuntu (10.04).

The gnome-screensaver FAQ provides detail on the dbus signal fired when gnome-screensaver activates and deactivates. The FAQ even has sample perl code to respond to the signal. Unfortunately the sample code polls dbus-monitor which is too inefficient for script I plan to run in the background on my laptop.

Python offers a great dbus library which allows signal receivers to be registered with dbus resulting in an efficient event listener.

On to the script.

Step 1: Setup the required files and directories
  1. Make a directory for your work:
    sudo mkdir -p /opt/ssTrigger
  2. Change yourself the owner of the new directory:
    sudo chown `whoami`:`whoami` /opt/ssTrigger
  3. Create stubs for the scripts to be used
    touch /opt/ssTrigger/ssTrigger /opt/ssTrigger/ssStart /opt/ssTrigger/ssStop
  4. Make the stub scripts executable:
    chmod 755 /opt/ssTrigger/*

Step 2: Edit the ssTrigger script
  1. Open the ssTriger file created earlier:
    gedit /opt/ssTrigger/ssTrigger
  2. Add the following to ssTrigger:
    #!/usr/bin/env python
    from gobject import MainLoop
    from dbus import SessionBus
    from dbus.mainloop.glib import DBusGMainLoop
    from subprocess import Popen
    
    class SSTrigger:
        def __init__(self):
            DBusGMainLoop(set_as_default=True)
            self.mem='ActiveChanged'
            self.dest='org.gnome.ScreenSaver'
            self.bus=SessionBus()
            self.loop=MainLoop()
            self.bus.add_signal_receiver(self.catch,self.mem,self.dest)
        def catch(self,ssOn):
            if ssOn == 1: #Screensaver turned on
                Popen(["/opt/ssTrigger/ssStart"])
            else: #Screensaver turned off
                Popen(["/opt/ssTrigger/ssStop"])
    
    SSTrigger().loop.run()
    
  3. Save and close the file.

Step 3: Set ssTrigger to start when you login:
  1. Open the Startup Applications menu:
    System -> Preferences -> Startup Applications

  2. Click "Add" to create a new startup application.

  3. Enter the following details:
    Name: Screensaver Trigger Script
    Command: /opt/ssTrigger/ssTrigger

  4. Click "Add" to save your new application.

  5. Restart your computer.

Finishing up:
Once you have restarted you can run:
ps aux | grep ssTrigger
Check the output to make sure the ssTrigger script has started at login.

Edit the ssStart and ssStop scripts to run commands as gnome-screensaver starts and stops respectively.

3 comments:

innobits said...

Thanks Trastle! That's exactly what I was looking for. I'm planning to run a script that limits the frequency of my cpu when the system is idle. I have BOINC distributed computing applications running when the system is not in use and I don't want the cpu fan to become loud while they are running. When I'm using the computer again, the cpu should again be capable of running at full performance. Thanks for your great guide! :)

joseheitor said...

Thanks for your post! I am having a problem and am not a Python programmer, so hope that you may be able to assist. Here is the log when running the ssTrigger script in a Terminal (once the screensaver is triggered):

ERROR:dbus.connection:Exception in handler for D-Bus signal:
Traceback (most recent call last):
File "/usr/lib/pymodules/python2.6/dbus/connection.py", line 214, in maybe_handle_message
self._handler(*args, **kwargs)
File "/opt/ssTrigger/ssTrigger", line 17, in catch
Popen(["/opt/ssTrigger/ssStart"])
File "/usr/lib/python2.6/subprocess.py", line 633, in __init__
errread, errwrite)
File "/usr/lib/python2.6/subprocess.py", line 1139, in _execute_child
raise child_exception
OSError: [Errno 8] Exec format error
ERROR:dbus.connection:Exception in handler for D-Bus signal:
Traceback (most recent call last):
File "/usr/lib/pymodules/python2.6/dbus/connection.py", line 214, in maybe_handle_message
self._handler(*args, **kwargs)
File "/opt/ssTrigger/ssTrigger", line 19, in catch
Popen(["/opt/ssTrigger/ssStop"])
File "/usr/lib/python2.6/subprocess.py", line 633, in __init__
errread, errwrite)
File "/usr/lib/python2.6/subprocess.py", line 1139, in _execute_child
raise child_exception
OSError: [Errno 8] Exec format error

Any suggestions?

Troy Astle said...

@joseheitor

OSError: [Errno 8] is reported by your OS and not by Python. It means there is a problem trying to execute the bash script you have provided at /opt/ssTrigger/ssStop and/or /opt/ssTrigger/ssStart.

Double check that this script works when you run it manually from the terminal and double check that you have included the #!/bin/bash (or similar) to specify the shell you want your script to run inside.

Troy.

Post a Comment