Support for idle time under GNOME without X11
* Removes use of most global variables * Adds some some logging * Removes unused close() method for Xss
This commit is contained in:
		
							parent
							
								
									3e0557dae6
								
							
						
					
					
						commit
						2e5d966f1d
					
				
					 2 changed files with 110 additions and 51 deletions
				
			
		| 
						 | 
				
			
			@ -18,6 +18,58 @@
 | 
			
		|||
 | 
			
		||||
import ctypes
 | 
			
		||||
import ctypes.util
 | 
			
		||||
import logging
 | 
			
		||||
from gi.repository import Gio
 | 
			
		||||
from gi.repository import GLib
 | 
			
		||||
 | 
			
		||||
log = logging.getLogger('gajim.c.idle')
 | 
			
		||||
 | 
			
		||||
idle_monitor = None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DBusGnomeIdleMonitor:
 | 
			
		||||
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        self.last_idle_time = 0
 | 
			
		||||
 | 
			
		||||
        log.debug('Connecting to D-Bus')
 | 
			
		||||
        self.dbus_gnome_proxy = Gio.DBusProxy.new_for_bus_sync(
 | 
			
		||||
            Gio.BusType.SESSION,
 | 
			
		||||
            Gio.DBusProxyFlags.NONE,
 | 
			
		||||
            None,
 | 
			
		||||
            'org.gnome.Mutter.IdleMonitor',
 | 
			
		||||
            '/org/gnome/Mutter/IdleMonitor/Core',
 | 
			
		||||
            'org.gnome.Mutter.IdleMonitor',
 | 
			
		||||
            None
 | 
			
		||||
        )
 | 
			
		||||
        log.debug('D-Bus connected')
 | 
			
		||||
 | 
			
		||||
        # Only the following call will trigger exceptions if the D-Bus
 | 
			
		||||
        # interface/method/... does not exist. Using the failing method
 | 
			
		||||
        # for class init to allow other idle monitors to be used on failure.
 | 
			
		||||
        self._get_idle_sec_fail()
 | 
			
		||||
        log.debug('D-Bus call test successful')
 | 
			
		||||
 | 
			
		||||
    def _get_idle_sec_fail(self):
 | 
			
		||||
        (idle_time,) = self.dbus_gnome_proxy.call_sync(
 | 
			
		||||
                    'GetIdletime',
 | 
			
		||||
                    None,
 | 
			
		||||
                    Gio.DBusCallFlags.NO_AUTO_START,
 | 
			
		||||
                    -1,
 | 
			
		||||
                    None
 | 
			
		||||
                )
 | 
			
		||||
        return int(idle_time / 1000)
 | 
			
		||||
 | 
			
		||||
    def get_idle_sec(self):
 | 
			
		||||
        try:
 | 
			
		||||
            self.last_idle_time = self._get_idle_sec_fail()
 | 
			
		||||
        except GLib.Error as e:
 | 
			
		||||
            log.warning(
 | 
			
		||||
                'org.gnome.Mutter.IdleMonitor.GetIdletime() failed: %s',
 | 
			
		||||
                repr(e))
 | 
			
		||||
 | 
			
		||||
        return self.last_idle_time
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class XScreenSaverInfo(ctypes.Structure):
 | 
			
		||||
    _fields_ = [
 | 
			
		||||
| 
						 | 
				
			
			@ -28,72 +80,80 @@ class XScreenSaverInfo(ctypes.Structure):
 | 
			
		|||
            ('idle', ctypes.c_ulong),
 | 
			
		||||
            ('eventMask', ctypes.c_ulong)
 | 
			
		||||
    ]
 | 
			
		||||
XScreenSaverInfo_p = ctypes.POINTER(XScreenSaverInfo)
 | 
			
		||||
 | 
			
		||||
display_p = ctypes.c_void_p
 | 
			
		||||
xid = ctypes.c_ulong
 | 
			
		||||
c_int_p = ctypes.POINTER(ctypes.c_int)
 | 
			
		||||
 | 
			
		||||
try:
 | 
			
		||||
    libX11path = ctypes.util.find_library('X11')
 | 
			
		||||
    if libX11path == None:
 | 
			
		||||
        raise OSError('libX11 could not be found.')
 | 
			
		||||
    libX11 = ctypes.cdll.LoadLibrary(libX11path)
 | 
			
		||||
    libX11.XOpenDisplay.restype = display_p
 | 
			
		||||
    libX11.XOpenDisplay.argtypes = ctypes.c_char_p,
 | 
			
		||||
    libX11.XDefaultRootWindow.restype = xid
 | 
			
		||||
    libX11.XDefaultRootWindow.argtypes = display_p,
 | 
			
		||||
class XssIdleMonitor:
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        XScreenSaverInfo_p = ctypes.POINTER(XScreenSaverInfo)
 | 
			
		||||
 | 
			
		||||
    libXsspath = ctypes.util.find_library('Xss')
 | 
			
		||||
    if libXsspath == None:
 | 
			
		||||
        raise OSError('libXss could not be found.')
 | 
			
		||||
    libXss = ctypes.cdll.LoadLibrary(libXsspath)
 | 
			
		||||
    libXss.XScreenSaverQueryExtension.argtypes = display_p, c_int_p, c_int_p
 | 
			
		||||
    libXss.XScreenSaverAllocInfo.restype = XScreenSaverInfo_p
 | 
			
		||||
    libXss.XScreenSaverQueryInfo.argtypes = (display_p, xid, XScreenSaverInfo_p)
 | 
			
		||||
        display_p = ctypes.c_void_p
 | 
			
		||||
        xid = ctypes.c_ulong
 | 
			
		||||
        c_int_p = ctypes.POINTER(ctypes.c_int)
 | 
			
		||||
 | 
			
		||||
    dpy_p = libX11.XOpenDisplay(None)
 | 
			
		||||
    if dpy_p == None:
 | 
			
		||||
        raise OSError('Could not open X Display.')
 | 
			
		||||
        libX11path = ctypes.util.find_library('X11')
 | 
			
		||||
        if libX11path == None:
 | 
			
		||||
            raise OSError('libX11 could not be found.')
 | 
			
		||||
        libX11 = ctypes.cdll.LoadLibrary(libX11path)
 | 
			
		||||
        libX11.XOpenDisplay.restype = display_p
 | 
			
		||||
        libX11.XOpenDisplay.argtypes = ctypes.c_char_p,
 | 
			
		||||
        libX11.XDefaultRootWindow.restype = xid
 | 
			
		||||
        libX11.XDefaultRootWindow.argtypes = display_p,
 | 
			
		||||
 | 
			
		||||
    _event_basep = ctypes.c_int()
 | 
			
		||||
    _error_basep = ctypes.c_int()
 | 
			
		||||
    if libXss.XScreenSaverQueryExtension(dpy_p, ctypes.byref(_event_basep),
 | 
			
		||||
                    ctypes.byref(_error_basep)) == 0:
 | 
			
		||||
        raise OSError('XScreenSaver Extension not available on display.')
 | 
			
		||||
        libXsspath = ctypes.util.find_library('Xss')
 | 
			
		||||
        if libXsspath == None:
 | 
			
		||||
            raise OSError('libXss could not be found.')
 | 
			
		||||
        self.libXss = ctypes.cdll.LoadLibrary(libXsspath)
 | 
			
		||||
        self.libXss.XScreenSaverQueryExtension.argtypes = display_p, c_int_p, c_int_p
 | 
			
		||||
        self.libXss.XScreenSaverAllocInfo.restype = XScreenSaverInfo_p
 | 
			
		||||
        self.libXss.XScreenSaverQueryInfo.argtypes = (display_p, xid, XScreenSaverInfo_p)
 | 
			
		||||
 | 
			
		||||
    xss_info_p = libXss.XScreenSaverAllocInfo()
 | 
			
		||||
    if xss_info_p == None:
 | 
			
		||||
        raise OSError('XScreenSaverAllocInfo: Out of Memory.')
 | 
			
		||||
        self.dpy_p = libX11.XOpenDisplay(None)
 | 
			
		||||
        if self.dpy_p == None:
 | 
			
		||||
            raise OSError('Could not open X Display.')
 | 
			
		||||
 | 
			
		||||
        _event_basep = ctypes.c_int()
 | 
			
		||||
        _error_basep = ctypes.c_int()
 | 
			
		||||
        if self.libXss.XScreenSaverQueryExtension(self.dpy_p, ctypes.byref(_event_basep),
 | 
			
		||||
                        ctypes.byref(_error_basep)) == 0:
 | 
			
		||||
            raise OSError('XScreenSaver Extension not available on display.')
 | 
			
		||||
 | 
			
		||||
        self.xss_info_p = self.libXss.XScreenSaverAllocInfo()
 | 
			
		||||
        if self.xss_info_p == None:
 | 
			
		||||
            raise OSError('XScreenSaverAllocInfo: Out of Memory.')
 | 
			
		||||
 | 
			
		||||
        self.rootwindow = libX11.XDefaultRootWindow(self.dpy_p)
 | 
			
		||||
 | 
			
		||||
    def get_idle_sec(self):
 | 
			
		||||
        if self.libXss.XScreenSaverQueryInfo(
 | 
			
		||||
                self.dpy_p,
 | 
			
		||||
                self.rootwindow,
 | 
			
		||||
                self.xss_info_p) == 0:
 | 
			
		||||
            return 0
 | 
			
		||||
        else:
 | 
			
		||||
            return int(self.xss_info_p.contents.idle / 1000)
 | 
			
		||||
 | 
			
		||||
    rootwindow = libX11.XDefaultRootWindow(dpy_p)
 | 
			
		||||
    xss_available = True
 | 
			
		||||
except OSError:
 | 
			
		||||
    # Logging?
 | 
			
		||||
    xss_available = False
 | 
			
		||||
 | 
			
		||||
def getIdleSec():
 | 
			
		||||
    global xss_available
 | 
			
		||||
    """
 | 
			
		||||
    Return the idle time in seconds
 | 
			
		||||
    """
 | 
			
		||||
    if not xss_available:
 | 
			
		||||
        return 0
 | 
			
		||||
    if libXss.XScreenSaverQueryInfo(dpy_p, rootwindow, xss_info_p) == 0:
 | 
			
		||||
    if idle_monitor is None:
 | 
			
		||||
        return 0
 | 
			
		||||
    else:
 | 
			
		||||
        return int(xss_info_p.contents.idle) / 1000
 | 
			
		||||
        return idle_monitor.get_idle_sec()
 | 
			
		||||
 | 
			
		||||
def close():
 | 
			
		||||
    global xss_available
 | 
			
		||||
    if xss_available:
 | 
			
		||||
        libX11.XFree(xss_info_p)
 | 
			
		||||
        libX11.XCloseDisplay(dpy_p)
 | 
			
		||||
        xss_available = False
 | 
			
		||||
try:
 | 
			
		||||
    idle_monitor = DBusGnomeIdleMonitor()
 | 
			
		||||
except GLib.Error as e:
 | 
			
		||||
    log.info("Idle time via D-Bus not available: %s", repr(e))
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        idle_monitor = XssIdleMonitor()
 | 
			
		||||
    except OSError as e:
 | 
			
		||||
        log.info("Idle time via XScreenSaverInfo not available: %s", repr(e))
 | 
			
		||||
        raise Exception('No supported idle monitor found')
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    import time
 | 
			
		||||
    time.sleep(2.1)
 | 
			
		||||
    print(getIdleSec())
 | 
			
		||||
    close()
 | 
			
		||||
    print(getIdleSec())
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -53,9 +53,8 @@ try:
 | 
			
		|||
        SystemParametersInfo = ctypes.windll.user32.SystemParametersInfoW
 | 
			
		||||
    else: # unix
 | 
			
		||||
        from gajim.common import idle
 | 
			
		||||
        idle.xss_available
 | 
			
		||||
except Exception:
 | 
			
		||||
    log.debug('Unable to load idle module')
 | 
			
		||||
    log.warning('Unable to load idle module')
 | 
			
		||||
    SUPPORTED = False
 | 
			
		||||
 | 
			
		||||
class SleepyWindows:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue