diff options
-rw-r--r-- | DBus.py | 90 | ||||
-rw-r--r-- | LockWindow.py | 53 | ||||
-rw-r--r-- | Locker.py | 2 | ||||
-rw-r--r-- | Message.py | 78 | ||||
-rw-r--r-- | pylock.py | 20 | ||||
-rw-r--r-- | unlock.ui | 210 |
6 files changed, 229 insertions, 224 deletions
diff --git a/DBus.py b/DBus.py deleted file mode 100644 index 6f24694..0000000 --- a/DBus.py +++ /dev/null @@ -1,90 +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. - - -from gi.repository import GLib, Gio - -from ctypes import CDLL, POINTER, Structure, CFUNCTYPE, pointer -from ctypes import c_void_p, c_char_p, c_bool -from ctypes.util import find_library - -from functools import partial - - -dbus_xml = ''' -<node> - <interface name="net.universe_factory.Pylock"> - <method name="Lock"/> - </interface> -</node> -''' - -gio = CDLL(find_library('gio-2.0')) - -nodeInfo = Gio.DBusNodeInfo.new_for_xml(dbus_xml) -interfaceInfo = nodeInfo.lookup_interface('net.universe_factory.Pylock') - -METHOD_CALL_FUNC = CFUNCTYPE(None, c_void_p, c_char_p, c_char_p, c_char_p, c_char_p, c_void_p, c_void_p, c_void_p) -GET_PROPERTY_FUNC = CFUNCTYPE(c_void_p, c_void_p, c_char_p, c_char_p, c_char_p, c_char_p, c_void_p, c_void_p) -SET_PROPERTY_FUNC = CFUNCTYPE(c_bool, c_void_p, c_char_p, c_char_p, c_char_p, c_char_p, c_void_p, c_void_p, c_void_p) - -def method_call(locker, connection, sender, object_path, interface_name, method_name, parameters, invocation, user_data): - assert str(method_name, 'ascii') == 'Lock' - - locker.lock() - gio.g_dbus_method_invocation_return_value(invocation, hash(GLib.Variant.new_tuple())) - -@GET_PROPERTY_FUNC -def get_property(connection, sender, object_path, interface_name, property_name, error, user_data): - assert False - -@SET_PROPERTY_FUNC -def set_property(connection, sender, object_path, interface_name, property_name, value, error, user_data): - assert False - -class VTable(Structure): - _fields_ = [ - ("method_call", METHOD_CALL_FUNC), - ("get_property", GET_PROPERTY_FUNC), - ("set_property", SET_PROPERTY_FUNC) - ] - - def __init__(self, locker): - Structure.__init__(self) - self.method_call = METHOD_CALL_FUNC(partial(method_call, locker)) - self.get_property = get_property - self.set_property = set_property - -gio.g_dbus_connection_register_object.argtypes = [c_void_p, c_char_p, c_void_p, POINTER(VTable), c_void_p, c_void_p, c_void_p] -gio.g_dbus_method_invocation_return_value.argtypes = [c_void_p, c_void_p] - - -class DBus(object): - def __init__(self, locker): - self.vtable = VTable(locker) - - Gio.bus_own_name(Gio.BusType.SESSION, 'net.universe_factory.Pylock', Gio.BusNameOwnerFlags.NONE, self.bus_aquired, None, None) - - def bus_aquired(self, connection, name): - b = lambda s: bytes(s, 'ascii') - gio.g_dbus_connection_register_object(c_void_p(hash(connection)), b('/net/universe_factory/Pylock'), c_void_p(hash(interfaceInfo)), pointer(self.vtable), None, None, None) diff --git a/LockWindow.py b/LockWindow.py index e040ea8..2ead7be 100644 --- a/LockWindow.py +++ b/LockWindow.py @@ -40,14 +40,19 @@ class LockWindow(Gtk.Window): def __init__(self): Gtk.Window.__init__(self) - bg = Gtk.Image.new_from_file("bg.svg") - self.add(bg) + self.display = Gdk.Display.get_default() + self.screen = self.display.get_default_screen() + + self.overlay = Gtk.Overlay() + self.add(self.overlay) + + self.bg = Gtk.Image.new_from_file("bg.svg") + self.overlay.add(self.bg) + + self.realize() + self.get_window().set_override_redirect(True) - self.set_decorated(False) - self.set_skip_taskbar_hint(True) - self.set_skip_pager_hint(True) - self.set_keep_above(True) - self.fullscreen() + self.set_has_resize_grip(False) builder = Gtk.Builder() @@ -61,12 +66,9 @@ class LockWindow(Gtk.Window): self.logoutButton = builder.get_object('logout_button') self.unlockButton = builder.get_object('unlock_button') - self.unlockWindow.set_position(Gtk.WindowPosition.CENTER_ALWAYS) - self.unlockWindow.set_transient_for(self) - self.unlockWindow.set_modal(True) + self.overlay.add_overlay(self.unlockWindow) self.connect('delete-event', lambda w, e: True) - self.unlockWindow.connect('delete-event', lambda w, e: True) self.promptEntry.connect('activate', lambda w: self._tryUnlock()) self.logoutButton.connect('clicked', lambda w: self._logout()) @@ -74,10 +76,9 @@ class LockWindow(Gtk.Window): self.reset(True) - self.display = Gdk.Display.get_default() self.deviceManager = self.display.get_device_manager() - self.unlockWindow.connect('map-event', self._grab_devices) + self.connect('map-event', self._grabDevices) def _logout(self): self.promptEntry.set_sensitive(False) @@ -128,26 +129,34 @@ class LockWindow(Gtk.Window): def setAuthMessage(self, message): self.messageLabel.set_label(message) - def _grab_devices(self, w, e): + def _grabDevices(self, w, e): + self.get_window().move_resize(0, 0, self.screen.get_width(), self.screen.get_height()) + + self.promptEntry.grab_focus() + for device in self.deviceManager.list_devices(Gdk.DeviceType.MASTER): - device.grab(self.unlockWindow.get_window(), Gdk.GrabOwnership.APPLICATION, True, Gdk.EventMask.ALL_EVENTS_MASK, None, Gdk.CURRENT_TIME) + device.grab(self.get_window(), Gdk.GrabOwnership.APPLICATION, True, Gdk.EventMask.ALL_EVENTS_MASK, None, Gdk.CURRENT_TIME) + + self.present() return False - def _ungrab_devices(self): + def _ungrabDevices(self): for device in self.deviceManager.list_devices(Gdk.DeviceType.MASTER): device.ungrab(Gdk.CURRENT_TIME) def lock(self): - self.show_all() - self.unlockWindow.show_all() + #geom = Gdk.Geometry() + #geom.min_width = self.screen.get_width() + #geom.max_width = self.screen.get_width() + #geom.min_height = self.screen.get_height() + #geom.max_height = self.screen.get_height() + #self.set_geometry_hints(self.overlay, geom, Gdk.WindowHints.MAX_SIZE) - self.promptEntry.grab_focus() + self.show_all() def unlock(self): - self._ungrab_devices() + self._ungrabDevices() - self.unlockWindow.hide() self.hide() - self.reset(True) @@ -62,8 +62,8 @@ class Locker(object): def lock(self): if not self.locked: - self.doLock(self.logoutTimeout) self.locked = True + self.doLock(self.logoutTimeout) if self.doLogout is not None: self.currentLogoutTimeout = self.logoutTimeout diff --git a/Message.py b/Message.py new file mode 100644 index 0000000..b78a0f3 --- /dev/null +++ b/Message.py @@ -0,0 +1,78 @@ +# 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 Gdk, GdkX11 + + +XEvent_p = ctypes.c_void_p +display_p = ctypes.c_void_p +xid = ctypes.c_ulong +x11_bool = ctypes.c_int +x11_time = ctypes.c_ulong +status = ctypes.c_int + + +libX11 = ctypes.util.find_library('X11') +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 +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(): + 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: + return False + + window.realize() + xid = GdkX11.X11Window.get_xid(window.get_window()) + libX11.XSetSelectionOwner(dpy_p, atomPylockWindow, xid, 0) + + return (getSelection() == xid) @@ -34,9 +34,9 @@ import argparse from gi.repository import Gtk, Gdk, Gio -from DBus import DBus from Locker import Locker from LockWindow import LockWindow +import Message import pam @@ -74,8 +74,20 @@ locale.textdomain('pylock') Gtk.Settings.get_default().set_property('gtk-theme-name', theme) +if Message.getSelection() != 0: + if args.timeout == 0: + Message.sendLockMessage() + 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) + def lock(timeLeft): window.updateLockMessage(args.username, timeLeft) @@ -98,8 +110,10 @@ else: locker = Locker(args.timeout, lock, window.unlock, args.logout, logout, updateTimeout) -if args.timeout != 0: - dbus = DBus(locker) +def _triggerLock(w, e): + locker.lock() + +window.connect('map-event', _triggerLock) pamAuth = pam.pam() @@ -1,172 +1,166 @@ <?xml version="1.0" encoding="UTF-8"?> <interface> <requires lib="gtk+" version="2.24"/> - <object class="GtkWindow" id="unlock_window"> + <object class="GtkNotebook" id="unlock_window"> + <property name="width_request">700</property> + <property name="visible">True</property> <property name="can_focus">False</property> - <property name="resizable">False</property> - <property name="decorated">False</property> - <property name="has_resize_grip">False</property> - <signal name="size-allocate" handler="login_window_size_allocate_cb" swapped="no"/> + <property name="halign">center</property> + <property name="valign">center</property> + <property name="show_tabs">False</property> <child> - <object class="GtkNotebook" id="login_notebook"> - <property name="width_request">700</property> + <object class="GtkHBox" id="box1"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="show_tabs">False</property> + <property name="can_focus">False</property> + <property name="spacing">40</property> <child> - <object class="GtkHBox" id="box1"> + <object class="GtkImage" id="image1"> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="spacing">40</property> + <property name="pixbuf">siegel.png</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkVBox" id="vbox2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="border_width">12</property> + <property name="spacing">12</property> <child> - <object class="GtkImage" id="image1"> + <object class="GtkLabel" id="lock_label"> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="pixbuf">siegel.png</property> + <property name="label" comments="This is a placeholder string and will be replaced with the hostname of the system">[lock]</property> </object> <packing> - <property name="expand">False</property> + <property name="expand">True</property> <property name="fill">True</property> - <property name="position">0</property> + <property name="position">1</property> </packing> </child> <child> - <object class="GtkVBox" id="vbox2"> - <property name="visible">True</property> + <object class="GtkVBox" id="login_box"> <property name="can_focus">False</property> - <property name="border_width">12</property> - <property name="spacing">12</property> + <property name="spacing">6</property> <child> - <object class="GtkLabel" id="lock_label"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" comments="This is a placeholder string and will be replaced with the hostname of the system">[lock]</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - <child> - <object class="GtkVBox" id="login_box"> + <object class="GtkHBox" id="prompt_box"> <property name="can_focus">False</property> <property name="spacing">6</property> <child> - <object class="GtkHBox" id="prompt_box"> + <object class="GtkLabel" id="prompt_label"> + <property name="visible">True</property> <property name="can_focus">False</property> - <property name="spacing">6</property> - <child> - <object class="GtkLabel" id="prompt_label"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">Password:</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkEntry" id="prompt_entry"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="visibility">False</property> - <property name="invisible_char">•</property> - <property name="primary_icon_activatable">False</property> - <property name="secondary_icon_activatable">False</property> - <signal name="activate" handler="login_cb" swapped="no"/> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> + <property name="label" translatable="yes">Password:</property> </object> <packing> - <property name="expand">True</property> + <property name="expand">False</property> <property name="fill">True</property> <property name="position">0</property> </packing> </child> <child> - <object class="GtkLabel" id="message_label"> - <property name="can_focus">False</property> - <property name="yalign">0</property> - <property name="label" comments="This is a placeholder string and will be replaced with a message from PAM">[message]</property> + <object class="GtkEntry" id="prompt_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="visibility">False</property> + <property name="invisible_char">•</property> + <property name="invisible_char_set">True</property> + <property name="primary_icon_activatable">False</property> + <property name="secondary_icon_activatable">False</property> + <signal name="activate" handler="login_cb" swapped="no"/> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="message_label"> + <property name="can_focus">False</property> + <property name="yalign">0</property> + <property name="label" comments="This is a placeholder string and will be replaced with a message from PAM">[message]</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="hbox2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">20</property> + <child> + <object class="GtkButton" id="unlock_button"> + <property name="label" translatable="yes">Unlock</property> + <property name="use_action_appearance">False</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_action_appearance">False</property> </object> <packing> <property name="expand">True</property> <property name="fill">True</property> + <property name="pack_type">end</property> <property name="position">1</property> </packing> </child> <child> - <object class="GtkHBox" id="hbox2"> + <object class="GtkButton" id="logout_button"> + <property name="label" translatable="yes">Logout</property> + <property name="use_action_appearance">False</property> <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="spacing">20</property> - <child> - <object class="GtkButton" id="unlock_button"> - <property name="label" translatable="yes">Unlock</property> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="use_action_appearance">False</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="pack_type">end</property> - <property name="position">1</property> - </packing> - </child> - <child> - <object class="GtkButton" id="logout_button"> - <property name="label" translatable="yes">Logout</property> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="use_action_appearance">False</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="pack_type">end</property> - <property name="position">2</property> - </packing> - </child> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_action_appearance">False</property> </object> <packing> <property name="expand">True</property> <property name="fill">True</property> + <property name="pack_type">end</property> <property name="position">2</property> </packing> </child> </object> <packing> - <property name="expand">False</property> + <property name="expand">True</property> <property name="fill">True</property> - <property name="position">3</property> + <property name="position">2</property> </packing> </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> - <property name="position">1</property> + <property name="position">3</property> </packing> </child> </object> - </child> - <child type="tab"> - <placeholder/> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> </child> </object> </child> + <child type="tab"> + <placeholder/> + </child> </object> </interface> |