Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F1880386
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Size
9 KB
Subscribers
None
View Options
diff --git a/12-logitech-usb.rules b/12-logitech-usb.rules
new file mode 100644
--- /dev/null
+++ b/12-logitech-usb.rules
@@ -0,0 +1,9 @@
+ACTION!="add|remove", GOTO="usb_lt_end"
+SUBSYSTEMS=="usb", GOTO="usb_lt_check"
+GOTO="usb_lt_end"
+
+LABEL="usb_lt_check"
+
+ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c538", MODE="0666"
+
+LABEL="usb_lt_end"
diff --git a/lt_presentation.py b/lt_presentation.py
--- a/lt_presentation.py
+++ b/lt_presentation.py
@@ -1,189 +1,240 @@
#!/usr/bin/env python
+# This is lt_presentation
+# A simple system tray tool to send LogiTech Presenter events
+# directly to the desired presentation tool.
+#
+# It wraps around Atril, xdotool and wmctrl and requires python-evdev
+# to communicate with the Presenter.
+#
+# Xfce's Presentation Mode is automatically activated and reset whenever
+# a presentation is active.
+
+import dbus
import evdev
import subprocess
import sys
import time
from PyQt4.QtCore import QTimer
from PyQt4 import QtGui
DEV_C = "Logitech USB Receiver"
class Manager():
def __init__(self, parent = None):
self.parent = parent
self.timer = QTimer()
self.timer.timeout.connect(self.check_events)
self.process = None
self.device = None
self.wid = None
+ self.pm_cookie = None
+ self.presentation_mode = False
+ self.presentation_active = False
def check_events(self):
if self.process:
if self.process.poll() == None:
try:
for event in self.device.read():
if event.type == evdev.ecodes.EV_KEY:
if event.code == evdev.ecodes.KEY_PAGEUP and event.value == 1:
self.send_key(self.wid, 'Page_Up')
elif event.code == evdev.ecodes.KEY_PAGEDOWN and event.value == 1:
self.send_key(self.wid, 'Page_Down')
elif event.code == evdev.ecodes.KEY_F5 and event.value == 1:
self.send_key(self.wid, 'F5')
elif event.code == evdev.ecodes.KEY_ESC and event.value == 1:
self.send_key(self.wid, 'Escape')
elif event.code == evdev.ecodes.KEY_DOT and event.value == 1:
self.send_key(self.wid, 'b')
except BlockingIOError:
pass
else:
self.stop_presentation()
else:
self.stop_presentation()
def stop_presentation(self):
print('Stopping Presentation')
+ self.presentation_active = False
self.timer.stop()
+ try:
+ self.device.ungrab()
+ except IOError:
+ pass
self.device.close()
self.device = None
self.wid = None
+ pm = dbus.SessionBus().get_object("org.freedesktop.PowerManagement", "/org/freedesktop/PowerManagement/Inhibit")
+ pm.UnInhibit(self.pm_cookie)
+ xfc = dbus.SessionBus().get_object('org.xfce.Xfconf', '/org/xfce/Xfconf')
+ xfc.SetProperty('xfce4-power-manager', '/xfce4-power-manager/presentation-mode', self.presentation_mode)
def check_viewer(self):
ret = subprocess.run(["atril", "--version"], stdout = subprocess.PIPE,
universal_newlines = True)
if ret.returncode == 0:
version = ret.stdout.replace('MATE Document Viewer ', '').replace('\n', '')
return version
else:
return False
def check_xdotool(self):
ret = subprocess.run(["xdotool", "--version"], stdout = subprocess.PIPE,
universal_newlines = True)
if ret.returncode == 0:
version = ret.stdout.replace('xdotool version ', '').replace('\n', '')
return version
else:
return False
def check_wmctrl(self):
ret = subprocess.run(["wmctrl", "--version"], stdout = subprocess.PIPE,
universal_newlines = True)
if ret.returncode == 0:
version = ret.stdout.replace('\n', '')
return version
else:
return False
def find_window_for_pid(self, pid):
print('Looking for window for PID: ' + str(pid))
ret = subprocess.run(["wmctrl", "-l", "-p"], stdout = subprocess.PIPE,
universal_newlines = True)
if ret.returncode == 0:
wpid = 0
wmid = 0
for line in ret.stdout.split('\n'):
args = line.split(' ')
pos = 1
for arg in args:
if arg == '':
continue
if pos == 1:
wmid = arg
elif pos == 3:
wpid = arg
pos += 1
if wpid == str(pid):
return wmid
return False
else:
return False
def get_window(self, pattern):
ret = subprocess.run(["xdotool", "search", "--name", pattern],
stdout = subprocess.PIPE, universal_newlines = True)
if ret.returncode == 0:
return ret.stdout.replace('\n', '')
else:
return False
def get_device(self, devname):
devices = [evdev.InputDevice(fn) for fn in evdev.list_devices()]
for dev in devices:
if dev.name == devname:
print('Found device: ', dev.fn)
return dev.fn
return False
def send_key(self, wid, key):
ret = subprocess.run(["xdotool", "key", "--window", wid, key])
return ret.returncode
def startPresentation(self):
print('Start Presentation')
+ if self.presentation_active:
+ QtGui.QMessageBox.critical(self.parent, 'Presentation already running!',
+ 'There is already a presentation running.')
+ return False
+
device = self.get_device(DEV_C)
if not device:
- print('Could not find device!')
+ QtGui.QMessageBox.critical(self.parent, 'Device not found!',
+ 'Could not find presentation remote control')
return False
+
self.device = evdev.InputDevice(device)
+ try:
+ self.device.grab()
+ except IOError:
+ QtGui.QMessageBox.critical(self.parent, 'Error grabbing device',
+ 'Could not grab Input device.')
+ return False
fname = QtGui.QFileDialog.getOpenFileName(self.parent, 'Open file', '', 'PDF (*.pdf)')
self.process = subprocess.Popen(["atril", fname])
# Give Atril some time to show its window
- time.sleep(2)
wid = self.find_window_for_pid(self.process.pid)
+ count = 0
+ while not wid and count < 10:
+ time.sleep(0.5)
+ wid = self.find_window_for_pid(self.process.pid)
+ count += 1
if not wid:
+ QtGui.QMessageBox.critical(self.parent, 'Atril not found!',
+ 'Could not fin Atril presentation window in time')
return False
self.wid = wid
print('Found Atril Window: ' + wid)
+ # Inhibit power management
+ pm = dbus.SessionBus().get_object("org.freedesktop.PowerManagement", "/org/freedesktop/PowerManagement/Inhibit")
+ self.pm_cookie = pm.Inhibit("lt_presentation", "Presentation Starting")
+ xfc = dbus.SessionBus().get_object('org.xfce.Xfconf', '/org/xfce/Xfconf')
+ self.presentation_mode = xfc.GetProperty('xfce4-power-manager', '/xfce4-power-manager/presentation-mode')
+ xfc.SetProperty('xfce4-power-manager', '/xfce4-power-manager/presentation-mode', dbus.Boolean(True, variant_level=1))
+ self.presentation_active = True
self.timer.start(10)
class SystemTrayIcon(QtGui.QSystemTrayIcon):
def __init__(self, icon, m, parent=None):
+ self.parent = parent
QtGui.QSystemTrayIcon.__init__(self, icon, parent)
menu = QtGui.QMenu(parent)
presentationAction = menu.addAction("Start Presentation...")
presentationAction.triggered.connect(m.startPresentation)
exitAction = menu.addAction("Exit")
exitAction.triggered.connect(QtGui.qApp.quit)
self.setContextMenu(menu)
def main():
app = QtGui.QApplication(sys.argv)
+ app.setQuitOnLastWindowClosed(False);
w = QtGui.QWidget()
m = Manager(w)
version = m.check_xdotool()
if version:
print('Running on xdotool version ' + version)
else:
- print('Could not find xdotool, will now quit')
+ QtGui.QMessageBox.critical(w, 'Tool not found', 'Could not find xdotool, will now quit')
sys.exit(1)
atrilVersion = m.check_viewer()
if atrilVersion:
print('Running on Atril version ' + atrilVersion)
else:
- print('Could not find Atril, will now quit')
+ QtGui.QMessageBox.critical(w, 'Tool not found', 'Could not find Atril, will now quit')
sys.exit(1)
wmctrlVersion = m.check_wmctrl()
if wmctrlVersion:
print('Running on wmctrl version ' + wmctrlVersion)
else:
- print('Could not find wmctrl, will now quit')
+ QtGui.QMssageBox.critical(w, 'Tool not found', 'Could not find wmctrl, will now quit')
sys.exit(1)
trayIcon = SystemTrayIcon(QtGui.QIcon("lt_presentation.ico"), m, w)
trayIcon.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Fri, Jan 24, 4:19 AM (1 d, 17 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
526302
Default Alt Text
(9 KB)
Attached To
rLTPRES Logitech Presentation Tool
Event Timeline
Log In to Comment