diff options
Diffstat (limited to 'pylock/LockWindow.py')
-rw-r--r-- | pylock/LockWindow.py | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/pylock/LockWindow.py b/pylock/LockWindow.py new file mode 100644 index 0000000..bb4d0e4 --- /dev/null +++ b/pylock/LockWindow.py @@ -0,0 +1,172 @@ +# 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 sys +import os +import locale + +from gi.repository import Gtk, Gdk, GObject, GLib + + +_ = locale.gettext + + +PACKAGE_DIR = os.path.dirname(__file__) + + +class LockWindow(Gtk.Window): + __gsignals__ = { + 'logout': (GObject.SIGNAL_RUN_FIRST, None, ()), + 'tryUnlock': (GObject.SIGNAL_RUN_FIRST, None, (str,)) + } + + def __init__(self): + Gtk.Window.__init__(self) + + self.display = Gdk.Display.get_default() + self.screen = self.display.get_default_screen() + self.devicesGrabbed = False + + self.overlay = Gtk.Overlay() + self.add(self.overlay) + + self.bg = Gtk.Image.new_from_file(os.path.join(PACKAGE_DIR, 'data/bg.svg')) + self.overlay.add(self.bg) + + self.realize() + self.get_window().set_override_redirect(True) + + self.set_default_size(self.screen.get_width(), self.screen.get_height()) + + self.set_has_resize_grip(False) + + builder = Gtk.Builder() + + if not builder.add_from_file(os.path.join(PACKAGE_DIR, 'data/unlock.ui')): + sys.exit(1) + + self.unlockWindow = builder.get_object('unlock_window') + self.lockLabel = builder.get_object('lock_label') + self.promptEntry = builder.get_object('prompt_entry') + self.messageLabel = builder.get_object('message_label') + self.logoutButton = builder.get_object('logout_button') + self.unlockButton = builder.get_object('unlock_button') + + self.overlay.add_overlay(self.unlockWindow) + + self.connect('delete-event', lambda w, e: True) + + self.promptEntry.connect('activate', lambda w: self._tryUnlock()) + self.logoutButton.connect('clicked', lambda w: self._logout()) + self.unlockButton.connect('clicked', lambda w: self._tryUnlock()) + + self.reset(False, True) + + self.deviceManager = self.display.get_device_manager() + + self.connect('map-event', self._grabDevices) + self.connect('configure-event', lambda w, e: self.get_window().move_resize(0, 0, self.screen.get_width(), self.screen.get_height()) and False) + + def _logout(self): + self.promptEntry.set_sensitive(False) + self.unlockButton.set_sensitive(False) + self.logoutButton.set_sensitive(False) + GLib.idle_add(lambda: self.emit('logout')) + + def _tryUnlock(self): + self.promptEntry.set_sensitive(False) + self.unlockButton.set_sensitive(False) + self.logoutButton.set_sensitive(False) + GLib.idle_add(lambda: self.emit('tryUnlock', self.promptEntry.get_text())) + + def _update(self): + self.promptEntry.set_sensitive(self._enablePromptEntry) + self.logoutButton.set_sensitive(self._enableLogoutButton) + self.unlockButton.set_sensitive(self._enableUnlockButton) + + def reset(self, regrab = True, resetButtons = False): + if resetButtons: + self._enablePromptEntry = True + self._enableLogoutButton = False + self._enableUnlockButton = True + + self.promptEntry.set_text('') + self.messageLabel.set_label('') + self._update() + + if regrab: + self._grabDevices(None, None) + + def updateLockMessage(self, username, logoutTime = None): + if logoutTime is None: + self.lockLabel.set_markup(_('This computer is currently locked by the user <i>{username}</i>.').format(username=GLib.markup_escape_text(username))) + self._enableLogoutButton = False + elif logoutTime > 0: + self.lockLabel.set_markup( + _('This computer is currently locked by the user <i>{username}</i>.\nThe user can be logged out in {minutes:02}:{seconds:02} minutes.').format( + username=GLib.markup_escape_text(username), minutes=logoutTime//60, seconds=logoutTime%60)) + self._enableLogoutButton = False + else: + self.lockLabel.set_markup( + _('This computer is currently locked by the user <i>{username}</i>.\nThe user can be logged out now.').format( + username=GLib.markup_escape_text(username))) + self._enableLogoutButton = True + self._update() + + def setAuthMessage(self, message): + self.messageLabel.set_label(message) + + def _grabDevices(self, w, e): + self.promptEntry.grab_focus() + + if not self.devicesGrabbed: + for device in self.deviceManager.list_devices(Gdk.DeviceType.MASTER): + if device.grab(self.get_window(), Gdk.GrabOwnership.APPLICATION, True, Gdk.EventMask.ALL_EVENTS_MASK, None, Gdk.CURRENT_TIME) != Gdk.GrabStatus.SUCCESS: + self._ungrabDevices() + self.get_window().lower() + return False + + self.present() + + self.devicesGrabbed = True + + return False + + def _ungrabDevices(self): + for device in self.deviceManager.list_devices(Gdk.DeviceType.MASTER): + device.ungrab(Gdk.CURRENT_TIME) + self.devicesGrabbed = False + + def lock(self): + self.show_all() + self.display.sync() + self._grabDevices(self, None) + return self.devicesGrabbed + + def unlock(self): + self._ungrabDevices() + + self.hide() + + self.reset(False, True) |