diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | README | 27 | ||||
-rwxr-xr-x | remote/Xsession | 4 | ||||
-rw-r--r-- | remote/__init__.py | 0 | ||||
-rwxr-xr-x | remote/brause.py | 37 | ||||
-rwxr-xr-x | remote/projector.py | 128 | ||||
-rwxr-xr-x | reset_projector.py | 15 | ||||
-rwxr-xr-x | video_projector.py | 15 | ||||
-rwxr-xr-x | vnc_projector.py | 29 | ||||
-rwxr-xr-x | web_projector.py | 15 |
10 files changed, 271 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0d20b64 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pyc @@ -0,0 +1,27 @@ +This is "projector", a hacky way to supply +input to a projector connected to a shared +system. + +Using this collection of scripts, you can: + - display Web Pages + - play back video + - display your screen via vnc + +Usage: +====== + +This script assumes /usr/bin/python2 points to a python +interpreter adhering to python language version >= 2.6 +If this is not true, you will either have to create a +fitting symlink or change the scripts. + +The files in the 'remote' directory should be placed +somewhere on the box attached to the projector. Xsession +is an example how an Xsession file to start the projector +might look. On the remote box, also TightVNC Viewer, +python-cairo, python-webkit, Mplayer are required. + +The scripts in the top directory enable the user to control +the projector. They should be pretty much self explanatory, +the beamer URL is by default http://<beamer-ip>:8082/ +vnc_projector requires x11vnc. diff --git a/remote/Xsession b/remote/Xsession new file mode 100755 index 0000000..0939958 --- /dev/null +++ b/remote/Xsession @@ -0,0 +1,4 @@ +#!/bin/sh + +metacity & +python projector.py diff --git a/remote/__init__.py b/remote/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/remote/__init__.py diff --git a/remote/brause.py b/remote/brause.py new file mode 100755 index 0000000..e9c0fce --- /dev/null +++ b/remote/brause.py @@ -0,0 +1,37 @@ +#!/usr/bin/python2 + +# written by equinox in 5 mintes on 09-04-2010 :) + +import sys + +import gobject +import pango +import pygtk +pygtk.require('2.0') +import gtk +from gtk import gdk +import cairo + +import webkit + +class BrauseWindow(gtk.Window): + def _destroy(s, widget, event): + gtk.main_quit() + + def __init__(s): + gtk.Window.__init__(s, type = gtk.WINDOW_TOPLEVEL) + s.connect('delete-event', s._destroy) + s.set_decorated(False) + s.fullscreen() + + s.webkit = webkit.WebView() + s.add(s.webkit) + s.show_all() + + s.webkit.open(sys.argv[1]) + + def run(s): + gtk.main() + +BrauseWindow().run() + diff --git a/remote/projector.py b/remote/projector.py new file mode 100755 index 0000000..16cceb8 --- /dev/null +++ b/remote/projector.py @@ -0,0 +1,128 @@ +#!/usr/bin/python2 + +import subprocess +import os +import time +import sys +import signal +import select +import errno +import inspect + +from SimpleXMLRPCServer import SimpleXMLRPCServer + +projection_process = None +default_task = [ + './brause.py', + 'http://sublab.rotefraktion.org/loungescreen/' +] +projection_task = default_task + +class ChildProcess(subprocess.Popen): + def __init__(self, *args, **kwargs): + subprocess.Popen.__init__(self, *args, **kwargs) + self._kill = os.kill + def __del__(self): + try: + self._kill(self.pid, 9) + self.poll() + except EnvironmentError as e: + if e.args[0] != errno.ESRCH: + raise + +def restart_projection(dummy=None): + global projection_process + global projection_task + + print "Replacing projection_process..." + projection_process = ChildProcess(projection_task) + +def sigchld(signum, trace): + global projection_process + + print "Got SIGCHLD" + if projection_process is not None and \ + projection_process.poll() is None: + # This info was not about the current projection_process... + return + + # Current projection_process exited, fallback to default + reset_projection() + +def display_url(url): + global projection_task + + projection_task = [ + './brause.py', + url + ] + restart_projection() + + return 0 # For RPC + +def display_video(url): + global projection_task + + if not (url.startswith('http://') or \ + url.startswith('ftp://')): + raise ValueError('URL should point to a http/ftp resource...') + + projection_task = [ + 'mplayer', + '-fs', + url + ] + restart_projection() + + return 0 # For RPC + +def reset_projection(): + global projection_task + global default_task + + projection_task = default_task + restart_projection() + + return 0 # For RPC + +def start_vnc(port): + global projection_task + + if type(port) is not int: + raise TypeError("start_vnc expects (port:int) as arguments") + + # Worst Monkey Patch ever (tm) + host = inspect.stack()[3][0].f_locals['self'].client_address[0] + print 'Connecting vncviewer to %s:%d' % (host,port) + + projection_task = [ + "vncviewer", "-fullscreen", + "-viewonly", "%s::%d" % (host,port) ] + restart_projection() + + return 0 + +def main(): + global projecting + subprocess.check_call("xset s off".split()) + subprocess.check_call("xset -dpms".split()) + + signal.signal(signal.SIGCHLD, sigchld) + restart_projection() + + server = SimpleXMLRPCServer(("0.0.0.0", 8082)) + server.register_function(display_url) + server.register_function(display_video) + server.register_function(reset_projection) + server.register_function(start_vnc) + + while True: + try: + server.serve_forever() + except select.error as e: + if e.args[0] == errno.EINTR: + continue + raise + +if __name__ == '__main__': + main() diff --git a/reset_projector.py b/reset_projector.py new file mode 100755 index 0000000..660d387 --- /dev/null +++ b/reset_projector.py @@ -0,0 +1,15 @@ +#!/usr/bin/python2 + +import sys +import xmlrpclib + +def main(): + if len(sys.argv) != 2: + sys.stderr.write('Usage: %s <projector-url>\n' % sys.argv[0]) + sys.exit(1) + + projector = xmlrpclib.ServerProxy(sys.argv[1]) + projector.reset_projection() + +if __name__ == '__main__': + main() diff --git a/video_projector.py b/video_projector.py new file mode 100755 index 0000000..6236010 --- /dev/null +++ b/video_projector.py @@ -0,0 +1,15 @@ +#!/usr/bin/python2 + +import sys +import xmlrpclib + +def main(): + if len(sys.argv) != 3: + sys.stderr.write('Usage: %s <projector-url> <url>\n' % sys.argv[0]) + sys.exit(1) + + projector = xmlrpclib.ServerProxy(sys.argv[1]) + projector.display_video(sys.argv[2]) + +if __name__ == '__main__': + main() diff --git a/vnc_projector.py b/vnc_projector.py new file mode 100755 index 0000000..dcb2d28 --- /dev/null +++ b/vnc_projector.py @@ -0,0 +1,29 @@ +#!/usr/bin/python2 + +from remote.projector import ChildProcess + +import sys +import xmlrpclib +import time + +def main(): + if len(sys.argv) not in [ 2, 3 ]: + sys.stderr.write('Usage: %s <projector-url> [port]\n' % sys.argv[0]) + sys.exit(1) + + if len(sys.argv) == 3: + port = int(sys.argv[2]) + else: + port = 5900 + + cmdline = "x11vnc -listen 0.0.0.0 -viewonly -nopw -rfbport %d" % port + x11vnc = ChildProcess(cmdline.split()) + time.sleep(2) + + projector = xmlrpclib.ServerProxy(sys.argv[1]) + projector.start_vnc(port) + + x11vnc.communicate() + +if __name__ == '__main__': + main() diff --git a/web_projector.py b/web_projector.py new file mode 100755 index 0000000..64e9089 --- /dev/null +++ b/web_projector.py @@ -0,0 +1,15 @@ +#!/usr/bin/python2 + +import sys +import xmlrpclib + +def main(): + if len(sys.argv) != 3: + sys.stderr.write('Usage: %s <projector-url> <url>\n' % sys.argv[0]) + sys.exit(1) + + projector = xmlrpclib.ServerProxy(sys.argv[1]) + projector.display_url(sys.argv[2]) + +if __name__ == '__main__': + main() |