Fixed RemoteGraphicsView on windows

- Avoid using authkey on windows; seems to be broken
 - Included yet another method of accessing shared memory as QImage
This commit is contained in:
Luke Campagnola 2013-11-17 09:27:55 -07:00
parent 1e82104986
commit 08be09ee40
3 changed files with 28 additions and 12 deletions

View File

@ -35,7 +35,7 @@ class Process(RemoteEventHandler):
ProxyObject for more information. ProxyObject for more information.
""" """
def __init__(self, name=None, target=None, executable=None, copySysPath=True, debug=False): def __init__(self, name=None, target=None, executable=None, copySysPath=True, debug=False, timeout=20):
""" """
============ ============================================================= ============ =============================================================
Arguments: Arguments:
@ -63,19 +63,23 @@ class Process(RemoteEventHandler):
## random authentication key ## random authentication key
authkey = os.urandom(20) authkey = os.urandom(20)
## Windows seems to have a hard time with hmac
if sys.platform.startswith('win'):
authkey = None
#print "key:", ' '.join([str(ord(x)) for x in authkey]) #print "key:", ' '.join([str(ord(x)) for x in authkey])
## Listen for connection from remote process (and find free port number) ## Listen for connection from remote process (and find free port number)
port = 10000 port = 10000
while True: while True:
try: try:
## hmac authentication appears to be broken on windows (says AuthenticationError: digest received was wrong)
l = multiprocessing.connection.Listener(('localhost', int(port)), authkey=authkey) l = multiprocessing.connection.Listener(('localhost', int(port)), authkey=authkey)
break break
except socket.error as ex: except socket.error as ex:
if ex.errno != 98: if ex.errno != 98:
raise raise
port += 1 port += 1
## start remote process, instruct it to run target function ## start remote process, instruct it to run target function
sysPath = sys.path if copySysPath else None sysPath = sys.path if copySysPath else None
bootstrap = os.path.abspath(os.path.join(os.path.dirname(__file__), 'bootstrap.py')) bootstrap = os.path.abspath(os.path.join(os.path.dirname(__file__), 'bootstrap.py'))
@ -111,7 +115,7 @@ class Process(RemoteEventHandler):
self.proc.stdin.close() self.proc.stdin.close()
## open connection for remote process ## open connection for remote process
self.debugMsg('Listening for child process..') self.debugMsg('Listening for child process on port %d, authkey=%s..' % (port, repr(authkey)))
while True: while True:
try: try:
conn = l.accept() conn = l.accept()
@ -140,7 +144,12 @@ class Process(RemoteEventHandler):
def startEventLoop(name, port, authkey, ppid, debug=False): def startEventLoop(name, port, authkey, ppid, debug=False):
if debug:
import os
print('[%d] connecting to server at port localhost:%d, authkey=%s..' % (os.getpid(), port, repr(authkey)))
conn = multiprocessing.connection.Client(('localhost', int(port)), authkey=authkey) conn = multiprocessing.connection.Client(('localhost', int(port)), authkey=authkey)
if debug:
print('[%d] connected; starting remote proxy.' % os.getpid())
global HANDLER global HANDLER
#ppid = 0 if not hasattr(os, 'getppid') else os.getppid() #ppid = 0 if not hasattr(os, 'getppid') else os.getppid()
HANDLER = RemoteEventHandler(conn, name, ppid, debug=debug) HANDLER = RemoteEventHandler(conn, name, ppid, debug=debug)
@ -380,7 +389,12 @@ class QtProcess(Process):
self.timer.stop() self.timer.stop()
def startQtEventLoop(name, port, authkey, ppid, debug=False): def startQtEventLoop(name, port, authkey, ppid, debug=False):
if debug:
import os
print('[%d] connecting to server at port localhost:%d, authkey=%s..' % (os.getpid(), port, repr(authkey)))
conn = multiprocessing.connection.Client(('localhost', int(port)), authkey=authkey) conn = multiprocessing.connection.Client(('localhost', int(port)), authkey=authkey)
if debug:
print('[%d] connected; starting remote proxy.' % os.getpid())
from pyqtgraph.Qt import QtGui, QtCore from pyqtgraph.Qt import QtGui, QtCore
#from PyQt4 import QtGui, QtCore #from PyQt4 import QtGui, QtCore
app = QtGui.QApplication.instance() app = QtGui.QApplication.instance()

View File

@ -97,7 +97,6 @@ class RemoteEventHandler(object):
after no more events are immediately available. (non-blocking) after no more events are immediately available. (non-blocking)
Returns the number of events processed. Returns the number of events processed.
""" """
self.debugMsg('processRequests:')
if self.exited: if self.exited:
self.debugMsg(' processRequests: exited already; raise ClosedError.') self.debugMsg(' processRequests: exited already; raise ClosedError.')
raise ClosedError() raise ClosedError()
@ -108,7 +107,7 @@ class RemoteEventHandler(object):
self.handleRequest() self.handleRequest()
numProcessed += 1 numProcessed += 1
except ClosedError: except ClosedError:
self.debugMsg(' processRequests: got ClosedError from handleRequest; setting exited=True.') self.debugMsg('processRequests: got ClosedError from handleRequest; setting exited=True.')
self.exited = True self.exited = True
raise raise
#except IOError as err: ## let handleRequest take care of this. #except IOError as err: ## let handleRequest take care of this.
@ -121,7 +120,8 @@ class RemoteEventHandler(object):
print("Error in process %s" % self.name) print("Error in process %s" % self.name)
sys.excepthook(*sys.exc_info()) sys.excepthook(*sys.exc_info())
self.debugMsg(' processRequests: finished %d requests' % numProcessed) if numProcessed > 0:
self.debugMsg('processRequests: finished %d requests' % numProcessed)
return numProcessed return numProcessed
def handleRequest(self): def handleRequest(self):

View File

@ -188,11 +188,16 @@ class Renderer(GraphicsView):
self.img = QtGui.QImage(ch, self.width(), self.height(), QtGui.QImage.Format_ARGB32) self.img = QtGui.QImage(ch, self.width(), self.height(), QtGui.QImage.Format_ARGB32)
else: else:
address = ctypes.addressof(ctypes.c_char.from_buffer(self.shm, 0)) address = ctypes.addressof(ctypes.c_char.from_buffer(self.shm, 0))
# different versions of pyqt have different requirements here..
try: try:
self.img = QtGui.QImage(sip.voidptr(address), self.width(), self.height(), QtGui.QImage.Format_ARGB32) self.img = QtGui.QImage(sip.voidptr(address), self.width(), self.height(), QtGui.QImage.Format_ARGB32)
except TypeError: except TypeError:
# different versions of pyqt have different requirements here.. try:
self.img = QtGui.QImage(memoryview(buffer(self.shm)), self.width(), self.height(), QtGui.QImage.Format_ARGB32) self.img = QtGui.QImage(memoryview(buffer(self.shm)), self.width(), self.height(), QtGui.QImage.Format_ARGB32)
except TypeError:
# Works on PyQt 4.9.6
self.img = QtGui.QImage(address, self.width(), self.height(), QtGui.QImage.Format_ARGB32)
self.img.fill(0xffffffff) self.img.fill(0xffffffff)
p = QtGui.QPainter(self.img) p = QtGui.QPainter(self.img)
self.render(p, self.viewRect(), self.rect()) self.render(p, self.viewRect(), self.rect())
@ -236,6 +241,3 @@ class Renderer(GraphicsView):
ev = QtCore.QEvent(QtCore.QEvent.Type(typ)) ev = QtCore.QEvent(QtCore.QEvent.Type(typ))
return GraphicsView.leaveEvent(self, ev) return GraphicsView.leaveEvent(self, ev)