summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2012-03-22 16:32:01 +0100
committerMatthias Schiffer <mschiffer@universe-factory.net>2012-03-22 16:32:01 +0100
commitcaa1f49279f2cf1b034a592d67c46b9df5428f65 (patch)
treeb6010c691df3ec93deb4f3bb1b987cb725af1d92
parent58cf425fb02cd3adc5d5fa96af865e9732914e29 (diff)
downloadpylock-caa1f49279f2cf1b034a592d67c46b9df5428f65.tar
pylock-caa1f49279f2cf1b034a592d67c46b9df5428f65.zip
Throw out DBus, add X11 based lock activation
-rw-r--r--DBus.py90
-rw-r--r--LockWindow.py53
-rw-r--r--Locker.py2
-rw-r--r--Message.py78
-rw-r--r--pylock.py20
-rw-r--r--unlock.ui210
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)
diff --git a/Locker.py b/Locker.py
index a872b38..f8e97ce 100644
--- a/Locker.py
+++ b/Locker.py
@@ -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)
diff --git a/pylock.py b/pylock.py
index dda47ba..f4841cd 100644
--- a/pylock.py
+++ b/pylock.py
@@ -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()
diff --git a/unlock.ui b/unlock.ui
index 8b33ab7..89bc3b8 100644
--- a/unlock.ui
+++ b/unlock.ui
@@ -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>