summaryrefslogtreecommitdiffstats
path: root/pylock/LockWindow.py
diff options
context:
space:
mode:
Diffstat (limited to 'pylock/LockWindow.py')
-rw-r--r--pylock/LockWindow.py172
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)