Page MenuHomePhabricator

No OneTemporary

diff --git a/lt_presentation.py b/lt_presentation.py
--- a/lt_presentation.py
+++ b/lt_presentation.py
@@ -1,240 +1,307 @@
#!/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
+import os
+import configparser
from PyQt4.QtCore import QTimer
from PyQt4 import QtGui
-DEV_C = "Logitech USB Receiver"
+class ConfigManager(QtGui.QWidget):
+ def __init__(self, config, parent = None):
+ QtGui.QWidget.__init__(self, parent)
+ self.config = config
class Manager():
- def __init__(self, parent = None):
+ def __init__(self, config, parent = None):
+ self.config = config
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
+ self.viewer = self.which(self.config['programs']['pdfviewer'])
+ self.wmctrl = self.which('wmctrl')
+ self.xdotool = self.which('xdotool')
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)
+ if self.config['general']['inhibit_xdg_pm'] == 'yes':
+ pm = dbus.SessionBus().get_object("org.freedesktop.PowerManagement", "/org/freedesktop/PowerManagement/Inhibit")
+ pm.UnInhibit(self.pm_cookie)
+ if self.config['general']['xfce_pm_presentation_mode'] == 'yes':
+ 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
+ if self.viewer:
+ return True
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
+ if self.xdotool:
+ ret = subprocess.run([self.xdotool, "--version"], stdout = subprocess.PIPE,
+ universal_newlines = True)
+ if ret.returncode == 0:
+ version = ret.stdout.replace('xdotool version ', '').replace('\n', '')
+ return version
+
+ 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
+ if self.wmctrl:
+ ret = subprocess.run([self.wmctrl, "--version"], stdout = subprocess.PIPE,
+ universal_newlines = True)
+ if ret.returncode == 0:
+ version = ret.stdout.replace('\n', '')
+ return version
+
+ 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,
+ ret = subprocess.run([self.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],
+ ret = subprocess.run([self.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])
+ ret = subprocess.run([self.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)
+ device = self.get_device(self.config['devices']['presenter'])
if not 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
+ self.process = subprocess.Popen([self.viewer, fname])
+ # Give the PDF viewer some time to show its window
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')
+ QtGui.QMessageBox.critical(self.parent, 'PDF Viewer not found!',
+ 'Could not find the PDF presentation window in time')
return False
+
self.wid = wid
- print('Found Atril Window: ' + wid)
+ print('Found PDF Viewer 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))
+ if self.config['general']['inhibit_xdg_pm'] == 'yes':
+ pm = dbus.SessionBus().get_object("org.freedesktop.PowerManagement", "/org/freedesktop/PowerManagement/Inhibit")
+ self.pm_cookie = pm.Inhibit("lt_presentation", "Presentation Starting")
+
+ if self.config['general']['xfce_pm_presentation_mode'] == 'yes':
+ 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)
+ def which(self, program):
+ def is_exe(fpath):
+ return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
+
+ fpath, fname = os.path.split(program)
+ if fpath:
+ if is_exe(program):
+ return program
+ else:
+ for path in os.environ["PATH"].split(os.pathsep):
+ path = path.strip('"')
+ exe_file = os.path.join(path, program)
+ if is_exe(exe_file):
+ return exe_file
+
+ return None
+
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 load_config(cfgFile):
+ config = configparser.ConfigParser()
+ config.read(cfgFile)
+ return config
+
+def save_config(config, cfgFile):
+ with open(cfgFile, 'w') as configFile:
+ config.write(configFile)
+
+def recreate_config(cfgFile):
+ config = configparser.ConfigParser()
+ config['general'] = {
+ 'xfce_pm_presentation_mode' : 'yes',
+ 'inhibit_xdg_pm' : 'yes'
+ }
+ config['programs'] = {
+ 'pdfviewer' : 'atril'
+ }
+ config['devices'] = {
+ 'presenter' : 'Logitech USB Receiver'
+ }
+ save_config(config, cfgFile)
+
def main():
app = QtGui.QApplication(sys.argv)
app.setQuitOnLastWindowClosed(False);
+ cfgPath = os.path.expanduser("~") + "/.lt_presentation/"
+ if not os.path.isdir(cfgPath):
+ os.makedirs(cfgPath)
+ cfgFile = cfgPath + "config.ini"
+ if not os.path.exists(cfgFile):
+ recreate_config(cfgFile)
+
+ cfg = load_config(cfgFile)
+
w = QtGui.QWidget()
- m = Manager(w)
+ m = Manager(cfg, w)
+
version = m.check_xdotool()
if version:
print('Running on xdotool version ' + version)
else:
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)
+ viewer = m.check_viewer()
+ if viewer:
+ print('Found configured PDF viewer ' + cfg['programs']['pdfviewer'])
else:
- QtGui.QMessageBox.critical(w, 'Tool not found', 'Could not find Atril, will now quit')
+ QtGui.QMessageBox.critical(w, 'Tool not found', 'Could not find PDF viewer, will now quit')
sys.exit(1)
wmctrlVersion = m.check_wmctrl()
if wmctrlVersion:
print('Running on wmctrl version ' + wmctrlVersion)
else:
QtGui.QMssageBox.critical(w, 'Tool not found', 'Could not find wmctrl, will now quit')
sys.exit(1)
trayIcon = SystemTrayIcon(QtGui.QIcon("/usr/share/icons/lt_presentation.png"), m, w)
trayIcon.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

File Metadata

Mime Type
text/x-diff
Expires
Fri, Jan 24, 3:27 AM (1 d, 16 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
526533
Default Alt Text
(13 KB)

Event Timeline