How to inhibit suspend temporarily?

Solution 1:

A program to keep your computer awake is Caffeine. I would make a .bash_aliases file to also call caffeine when your original code is called.

alias newname="origcode && caffeine"

Depending on which code you are trying to keep your computer awake for, you'll have to make a custom script that includes killing caffeine when the other code is stopped. Some more details about the particular code would help.

Update: A simpler way would be to run xdotool, which can be installed with sudo apt-get install xdotool. You can write a script that is called when your target code is opened and then use the sleep command for 29 minutes and then run xdotool key a or something arbitrary to keep the computer awake.

Solution 2:

If

  1. A script in /usr/lib/pm-utils/sleep.d can check if the application is running and return 1 to indicate that suspend should be prevented.
  2. The problem of "the system then gives up on suspending automatically, instead of trying again after another 30 minutes" is solved by moving the mouse which restarts the timer again (I hope I've understood properly what you mean by this)

then why not just jiggle mouse pointer after the application terminates.

To summarise:

  1. Use sleep.d to keep system from suspending.
  2. Write a script that jiggles mouse once.
  3. Call 'Long-running-script && mousejiggle'

This will not hinder the screensaver.

The only problem is that it will be 30 minutes after the process terminates when the system suspends. This is the case with your 'EDIT' solution also.

PS: I was looking for a solution to a similar problem when I learnt of xdotool from this page. So, thanks. Hope this helps.

Solution 3:

Although EDIT 2 lets the screensaver kick-in and resumes autosuspend service on removal of inhibit file, as noted above it will be 30 minutes after the file is removed when the system will suspend.

One possible solution is to disable the inbuilt auto-screensaver and auto-suspend functionality and implement them on our own, and choose the behaviour of the timer as required. The command xprintidle (you may have to install this) prints the number of milliseconds for which there has been no keyboard or mouse activity. This opens up several possibilities. I've implemented the following inactivity manager in python (not too much of a bash scripter). Features include setting the command, timeout and inhibit file(I've called it lock) for screensaver and/or autosuspend. In addition there is option to choose whether inactivity timer should restart when inhibit file is removed or not (behaviour can be different for suspend and screensaver). I've tried to make the usage clear in the notes but if something is unclear do ask.

#!/usr/bin/python

#Notes:##################

#   1. All TIMEOUTs are specified in seconds
#   2. 0 or negative TIMEOUT disables a particular action.
#   3. If an actionCOMMAND (like pm-suspend) requires 'sudo'ing, make them 'sudo'able without password. Alternatively, you may run this script in sudo mode, and make this script sudoable without password. https://askubuntu.com/questions/159007/specific-sudo-commands-without-password
#   4. 'action'_timer_starts_... option: True - if a lock file is created and then removed, inactivity timer (for that action) restarts at the time of deletion of lock. False - doesn't restart.
#   5. screensaverCOMMAND can be screen-lock (security) or screen-off (power saving) or both. To do both, but at different times (I can't see any reason to do so) extend this script from two actions (screensaver, autosuspend) to three (screen-lock, screen-off, autosuspend).

#########################

import os
import time
import threading
import subprocess

HOME = os.getenv('HOME') + '/'

#Configuration###########

screensaverCOMMAND = "gnome-screensaver-command --lock && xset -display :0.0 +dpms dpms force off"
autosuspendCOMMAND = "gnome-screensaver-command --lock && sudo pm-suspend"

screensaverTIMEOUT = 10*60
autosuspendTIMEOUT = 20*60

screensaverLOCK = HOME + ".inactivitymanager/screensaverLOCK"
autosuspendLOCK = HOME + ".inactivitymanager/autosuspendLOCK"

screensaver_timer_starts_only_after_lockfile_is_deleted = False
autosuspend_timer_starts_only_after_lockfile_is_deleted = False

#########################

def stayOn():
    print "inactivitymanager is running..."
    try:
        while True:
            time.sleep(10)
    except:
        print "Closed."

class inactivity_action(threading.Thread):
    def __init__(self, command, timeout, lock, timer_starts_blah):
        threading.Thread.__init__(self)
        self.daemon = True
        self.command = command
        self.timeout = timeout
        self.lock = lock
        self.timer_starts_blah = timer_starts_blah
    def run(self):
        if not(self.timer_starts_blah):
            while True:
                try:
                    while True:
                        time.sleep(1)
                        f = open(self.lock, 'r')
                        f.close()
                except IOError:
                    xidletime = int(subprocess.Popen('xprintidle', stdout = subprocess.PIPE).communicate()[0])/1000
                    if xidletime > self.timeout:
                        os.system(self.command)
                    else:
                        time.sleep(self.timeout - xidletime + 2)
        else:
            lockremovetime = 0
            while True:
                lockdetected = False
                try:
                    while True:
                        time.sleep(1)
                        f = open(self.lock, 'r')
                        f.close()
                        lockdetected = True
                except IOError: #Will enter this section if/when lockfile is/becomes absent
                    xidletime = int(subprocess.Popen('xprintidle', stdout = subprocess.PIPE).communicate()[0])/1000
                    if lockdetected:
                        lockremovetime = int(time.time())
                    timesincelockremove = int(time.time()) - lockremovetime
                    if min(xidletime, timesincelockremove) > self.timeout:
                        os.system(self.command)

if screensaverTIMEOUT > 0:
    inactivity_screensaver = inactivity_action(screensaverCOMMAND, screensaverTIMEOUT, screensaverLOCK, screensaver_timer_starts_only_after_lockfile_is_deleted)
    inactivity_screensaver.start()

if autosuspendTIMEOUT > 0:
    inactivity_autosuspend = inactivity_action(autosuspendCOMMAND, autosuspendTIMEOUT, autosuspendLOCK, autosuspend_timer_starts_only_after_lockfile_is_deleted)
    inactivity_autosuspend.start()

stayOn()

Usage:

  1. Just add inactivitymanager & to .profile or .xsessionrc in home directory (see which one works for you. Don't add in both, else two instances of this script will run simultaneously, something I've not handled. I guess it is in these details that the mainstream implementations trump custom ones).
  2. You may have to install xprintidle.

How the inhibit file gets there is left to the imagination of the user for now (if I bring myself to implement a daemon for this, I'll put that in an EDIT to this answer). You (OP) of course have solved it for your case. One pitfall to avoid when trying to inhibit suspend for more than one process is deleting the lock file when one process terminates while another is still running. Alternatively, the script can be edited slightly to inhibit suspend if some file exists in a particular directory (a lock directory). This way each process can have its own lock file.

Notes:

  1. This script is pretty light on the processor and memory. But removing the time.sleep(1) s in the code might cause trouble - haven't checked though.
  2. pm-suspend requires sudo permissions. To pm-suspend without giving password checkout How do I run specific sudo commands without a password?. Alternatively you may run this script in sudo mode, and make this script sudoable without password (Not a problem if you running script as root)
  3. The script might run into trouble if timeouts are set to be less than ~10 seconds (Haven't check where exactly the trouble starts must be less than 5, I guess). This can be handled by removing some time.sleep(1) s at the expense of system resources. Don't think anybody will need this though.
  4. Because we have a handle on the timers, no mousejiggles required!