Rework pylock to behave like xlock
This commit is contained in:
parent
e342d5c724
commit
4659883ba0
4 changed files with 43 additions and 154 deletions
71
Idle.py
71
Idle.py
|
@ -1,71 +0,0 @@
|
|||
# Copyright (c) 2012, Matthias Schiffer <mschiffer@universe-factory.net>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
import ctypes
|
||||
import ctypes.util
|
||||
|
||||
from gi.repository import GdkX11
|
||||
|
||||
|
||||
class XScreenSaverInfo(ctypes.Structure):
|
||||
_fields_ = [
|
||||
('window', ctypes.c_ulong),
|
||||
('state', ctypes.c_int),
|
||||
('kind', ctypes.c_int),
|
||||
('til_or_since', ctypes.c_ulong),
|
||||
('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)
|
||||
|
||||
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)
|
||||
|
||||
dpy_p = hash(GdkX11.x11_get_default_xdisplay())
|
||||
rootwindow = GdkX11.x11_get_default_root_xwindow()
|
||||
|
||||
_event_basep = ctypes.c_int()
|
||||
_error_basep = ctypes.c_int()
|
||||
if libXss.XScreenSaverQueryExtension(ctypes.c_void_p(dpy_p), ctypes.byref(_event_basep),
|
||||
ctypes.byref(_error_basep)) == 0:
|
||||
raise OSError('XScreenSaver Extension not available on display.')
|
||||
|
||||
xss_info_p = libXss.XScreenSaverAllocInfo()
|
||||
if xss_info_p == None:
|
||||
raise OSError('XScreenSaverAllocInfo: Out of Memory.')
|
||||
|
||||
def getIdleSec():
|
||||
if libXss.XScreenSaverQueryInfo(dpy_p, rootwindow, xss_info_p) == 0:
|
||||
return 0
|
||||
else:
|
||||
return int(xss_info_p.contents.idle) / 1000
|
25
Locker.py
25
Locker.py
|
@ -24,35 +24,16 @@
|
|||
|
||||
from gi.repository import Gtk, GLib
|
||||
|
||||
import Idle
|
||||
|
||||
|
||||
class Locker(object):
|
||||
def __init__(self, lockTimeout, doLock, doUnlock, logoutTimeout = None, doLogout = None, updateLogoutTimeout = None):
|
||||
def __init__(self, doLock, doUnlock, logoutTimeout = None, doLogout = None, updateLogoutTimeout = None):
|
||||
self.locked = False
|
||||
self.lockTimeout = lockTimeout
|
||||
self.logoutTimeout = logoutTimeout
|
||||
self.doLock = doLock
|
||||
self.doUnlock = doUnlock
|
||||
self.doLogout = doLogout
|
||||
self.updateLogoutTimeout = updateLogoutTimeout
|
||||
|
||||
if self.lockTimeout > 0:
|
||||
GLib.timeout_add_seconds(1, self._checkLock)
|
||||
else:
|
||||
GLib.idle_add(self.lock)
|
||||
|
||||
def _checkLock(self):
|
||||
if self.locked:
|
||||
return False
|
||||
|
||||
idle = Idle.getIdleSec()
|
||||
if (idle >= self.lockTimeout):
|
||||
GLib.idle_add(self.lock)
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def _checkLogout(self):
|
||||
if not self.locked:
|
||||
return False
|
||||
|
@ -68,7 +49,7 @@ class Locker(object):
|
|||
self.locked = True
|
||||
if not self.doLock(self.logoutTimeout):
|
||||
self.locked = False
|
||||
GLib.timeout_add_seconds(1, self._checkLock)
|
||||
GLib.timeout_add_seconds(1, self.lock)
|
||||
return False
|
||||
|
||||
if self.doLogout is not None:
|
||||
|
@ -84,8 +65,6 @@ class Locker(object):
|
|||
self.doUnlock()
|
||||
self.locked = False
|
||||
|
||||
GLib.timeout_add_seconds(1, self._checkLock)
|
||||
|
||||
def _canLogout(self):
|
||||
return (self.locked and self.doLogout is not None and self.currentLogoutTimeout <= 0)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (c) 2012, Matthias Schiffer <mschiffer@universe-factory.net>
|
||||
# Copyright (c) 2012-2013, Matthias Schiffer <mschiffer@universe-factory.net>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
|
@ -41,8 +41,6 @@ if libX11 == None:
|
|||
raise OSError('libX11 could not be found.')
|
||||
libX11 = ctypes.cdll.LoadLibrary(libX11)
|
||||
|
||||
libX11.XSendEvent.argtypes = display_p, xid, x11_bool, ctypes.c_long, XEvent_p
|
||||
libX11.XSendEvent.restype = status
|
||||
libX11.XSetSelectionOwner.argtypes = display_p, xid, xid, x11_time
|
||||
libX11.XSetSelectionOwner.restype = ctypes.c_int
|
||||
libX11.XGetSelectionOwner.argtypes = display_p, xid
|
||||
|
@ -52,27 +50,17 @@ libX11.XGetSelectionOwner.restype = xid
|
|||
display = Gdk.Display.get_default()
|
||||
dpy_p = display_p(hash(GdkX11.X11Display.get_xdisplay(display)))
|
||||
atomPylockWindow = GdkX11.x11_get_xatom_by_name("PYLOCK_WINDOW")
|
||||
atomPylockActionLock = GdkX11.x11_get_xatom_by_name("PYLOCK_ACTION_LOCK")
|
||||
|
||||
|
||||
def getSelection():
|
||||
def get():
|
||||
return libX11.XGetSelectionOwner(dpy_p, atomPylockWindow)
|
||||
|
||||
def sendLockMessage():
|
||||
window = getSelection()
|
||||
if window == 0:
|
||||
return
|
||||
|
||||
gdkWindow = GdkX11.X11Window.foreign_new_for_display(display, window)
|
||||
gdkWindow.show()
|
||||
display.sync()
|
||||
|
||||
def acquireSelection(window):
|
||||
if getSelection() != 0:
|
||||
def acquire(window):
|
||||
if get() != 0:
|
||||
return False
|
||||
|
||||
window.realize()
|
||||
xid = GdkX11.X11Window.get_xid(window.get_window())
|
||||
libX11.XSetSelectionOwner(dpy_p, atomPylockWindow, xid, 0)
|
||||
|
||||
return (getSelection() == xid)
|
||||
return (get() == xid)
|
75
pylock.py
75
pylock.py
|
@ -30,33 +30,27 @@ import sys
|
|||
import os
|
||||
import pwd
|
||||
import locale
|
||||
import argparse
|
||||
import configparser
|
||||
|
||||
from gi.repository import Gtk, Gdk, Gio
|
||||
from gi.repository import Gtk, GLib
|
||||
|
||||
from Locker import Locker
|
||||
from LockWindow import LockWindow
|
||||
import Message
|
||||
import Selection
|
||||
import pam
|
||||
|
||||
|
||||
CONFIG_FILE = '/etc/pylock.conf'
|
||||
|
||||
|
||||
_ = locale.gettext
|
||||
|
||||
|
||||
def get_username():
|
||||
return pwd.getpwuid(os.getuid())[0]
|
||||
configParser = configparser.ConfigParser()
|
||||
configParser.read_file(open(CONFIG_FILE))
|
||||
|
||||
|
||||
theme = 'UzL-login'
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser(prog='pylock', description=_('GTK-based screen locker.'))
|
||||
parser.add_argument('-t', '--timeout', type=int, default=0, help=_('Start in daemon mode that will automatically activate after a given time of inactivity.'))
|
||||
parser.add_argument('-l', '--logout', type=int, default=0, help=_('Allow to logout the current user after a given time.'))
|
||||
parser.add_argument('-c', '--logout-command', help=_('Specifies the command to be called to log out a user.'))
|
||||
parser.add_argument('-u', '--username', default=get_username(), help=_('Set the name of the user that is able to unlock the screen.'))
|
||||
|
||||
args = parser.parse_args()
|
||||
config = configParser['pylock']
|
||||
username = pwd.getpwuid(os.getuid())[0]
|
||||
|
||||
|
||||
def handler(signum, frame):
|
||||
|
@ -71,58 +65,54 @@ signal.signal(signal.SIGQUIT, handler)
|
|||
locale.setlocale(locale.LC_ALL, '')
|
||||
locale.textdomain('pylock')
|
||||
|
||||
Gtk.Settings.get_default().set_property('gtk-theme-name', theme)
|
||||
Gtk.Settings.get_default().set_property('gtk-theme-name', config['theme'])
|
||||
|
||||
|
||||
if Message.getSelection() != 0:
|
||||
if args.timeout == 0:
|
||||
Message.sendLockMessage()
|
||||
def waitForSelection():
|
||||
if Selection.get() != 0:
|
||||
return True
|
||||
|
||||
Gtk.main_quit()
|
||||
return False
|
||||
|
||||
if Selection.get() != 0:
|
||||
GLib.timeout_add_seconds(1, waitForSelection)
|
||||
Gtk.main()
|
||||
exit(0)
|
||||
else:
|
||||
print('There seems to be a Pylock instance already running.', file=sys.stderr)
|
||||
exit(1)
|
||||
|
||||
|
||||
window = LockWindow()
|
||||
|
||||
if not Message.acquireSelection(window):
|
||||
print('Unable to register for lock messages', file=sys.stderr)
|
||||
if not Selection.acquire(window):
|
||||
print('Unable to register pylock at X server', file=sys.stderr)
|
||||
exit(1)
|
||||
|
||||
|
||||
def lock(timeLeft):
|
||||
window.updateLockMessage(args.username, timeLeft)
|
||||
window.updateLockMessage(username, timeLeft)
|
||||
return window.lock()
|
||||
|
||||
def logout():
|
||||
try:
|
||||
os.system(args.logout_command)
|
||||
os.system(config['logout_command'])
|
||||
except:
|
||||
pass
|
||||
|
||||
window.reset(False)
|
||||
|
||||
def updateTimeout(timeLeft):
|
||||
window.updateLockMessage(args.username, timeLeft)
|
||||
window.updateLockMessage(username, timeLeft)
|
||||
|
||||
if args.logout_command is None:
|
||||
locker = Locker(args.timeout, lock, window.unlock)
|
||||
if not ('logout_timeout' in config and 'logout_command' in config):
|
||||
locker = Locker(lock, window.unlock)
|
||||
else:
|
||||
locker = Locker(args.timeout, lock, window.unlock, args.logout, logout, updateTimeout)
|
||||
|
||||
|
||||
def _triggerLock(w, e):
|
||||
locker.lock()
|
||||
|
||||
window.connect('map-event', _triggerLock)
|
||||
|
||||
locker = Locker(lock, window.unlock, int(config['logout_timeout']), logout, updateTimeout)
|
||||
|
||||
pamAuth = pam.pam()
|
||||
|
||||
def tryUnlock(w, password):
|
||||
if pamAuth.authenticate(args.username, password):
|
||||
if pamAuth.authenticate(username, password):
|
||||
locker.unlock()
|
||||
|
||||
if args.timeout == 0:
|
||||
Gtk.main_quit()
|
||||
else:
|
||||
window.reset()
|
||||
|
@ -130,7 +120,10 @@ def tryUnlock(w, password):
|
|||
|
||||
return True
|
||||
|
||||
|
||||
window.connect('logout', lambda w: locker.logout())
|
||||
window.connect('tryUnlock', tryUnlock)
|
||||
|
||||
GLib.idle_add(lambda: locker.lock())
|
||||
|
||||
Gtk.main()
|
||||
|
|
Reference in a new issue