add view system + bug fix
This commit is contained in:
@@ -29,7 +29,7 @@ sys.path.insert(1, os.path.join(sys.path[0], '..'))
|
||||
|
||||
from rdpy.base import log, error
|
||||
from rdpy.protocol.rdp import rdp
|
||||
from rdpy.ui import widget
|
||||
from rdpy.ui import view
|
||||
from twisted.internet import reactor
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
@@ -42,6 +42,8 @@ class IProxyClient(object):
|
||||
pass
|
||||
def sendPointerEvent(self, x, y, button, isPressed):
|
||||
pass
|
||||
def sendRefreshOrder(self, left, top, right, bottom):
|
||||
pass
|
||||
|
||||
class ProxyServer(rdp.RDPServerObserver):
|
||||
"""
|
||||
@@ -69,21 +71,27 @@ class ProxyServer(rdp.RDPServerObserver):
|
||||
Event use to inform state of server stack
|
||||
Use to connect client
|
||||
"""
|
||||
domain, username, password = self._controller.getCredentials()
|
||||
|
||||
if self._credentialProvider.isAdmin(domain, username, password):
|
||||
self.clientConnected(ProxyAdmin(self))
|
||||
return
|
||||
|
||||
try:
|
||||
dstIp, dstPort, dstDomain, dstUsername, dstPassword = self._credentialProvider.getCredentials(domain, username, password)
|
||||
except error.InvalidExpectedDataException as e:
|
||||
log.info(e.message)
|
||||
#self._controller.close()
|
||||
return
|
||||
|
||||
width, height = self._controller.getScreen()
|
||||
reactor.connectTCP(dstIp, dstPort, ProxyClientFactory(self, width, height, dstDomain, dstUsername, dstPassword, "%s/%s -> %s %s/%s"%(domain, username, dstIp, dstDomain, dstUsername)))
|
||||
if self._client is None:
|
||||
#try a connection
|
||||
domain, username, password = self._controller.getCredentials()
|
||||
|
||||
if self._credentialProvider.isAdmin(domain, username, password):
|
||||
self.clientConnected(ProxyAdmin(self))
|
||||
return
|
||||
|
||||
try:
|
||||
dstIp, dstPort, dstDomain, dstUsername, dstPassword = self._credentialProvider.getCredentials(domain, username, password)
|
||||
except error.InvalidExpectedDataException as e:
|
||||
log.info(e.message)
|
||||
#self._controller.close()
|
||||
return
|
||||
|
||||
width, height = self._controller.getScreen()
|
||||
reactor.connectTCP(dstIp, dstPort, ProxyClientFactory(self, width, height, dstDomain, dstUsername, dstPassword, "%s/%s -> %s %s/%s"%(domain, username, dstIp, dstDomain, dstUsername)))
|
||||
else:
|
||||
#refresh client
|
||||
width, height = self._controller.getScreen()
|
||||
self._client.sendRefreshOrder(0, 0, width, height)
|
||||
|
||||
def onKeyEventScancode(self, code, isPressed):
|
||||
"""
|
||||
@@ -159,14 +167,21 @@ class ProxyClient(rdp.RDPClientObserver, IProxyClient):
|
||||
@param data: bitmap data
|
||||
"""
|
||||
self._server._controller.sendUpdate(destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data)
|
||||
|
||||
def getColorDepth(self):
|
||||
return self._controller.getColorDepth()
|
||||
|
||||
def sendKeyEventScancode(self, code, isPressed):
|
||||
self._controller.sendKeyEventScancode(code, isPressed)
|
||||
|
||||
def sendKeyEventUnicode(self, code, isPressed):
|
||||
self._controller.sendKeyEventUnicode(code, isPressed)
|
||||
|
||||
def sendPointerEvent(self, x, y, button, isPressed):
|
||||
self._controller.sendPointerEvent(x, y, button, isPressed)
|
||||
|
||||
def sendRefreshOrder(self, left, top, right, bottom):
|
||||
self._controller.sendRefreshOrder(left, top, right, bottom)
|
||||
|
||||
class ProxyServerFactory(rdp.ServerFactory):
|
||||
"""
|
||||
@@ -177,7 +192,7 @@ class ProxyServerFactory(rdp.ServerFactory):
|
||||
@param config: rdp-proxy configuration
|
||||
@param credentialProvider: CredentialProvider
|
||||
"""
|
||||
rdp.ServerFactory.__init__(self, "/home/sylvain/dev/certificate/rdpy.key", "/home/sylvain/dev/certificate/rdpy.crt", 16)
|
||||
rdp.ServerFactory.__init__(self, "/home/speyrefitte/dev/certificate/rdpy.key", "/home/speyrefitte/dev/certificate/rdpy.crt", 16)
|
||||
self._credentialProvider = credentialProvider
|
||||
|
||||
def buildObserver(self, controller):
|
||||
@@ -277,19 +292,28 @@ class CredentialProvider(object):
|
||||
return self._config['admin']['domain'] == domain and self._config['admin']['username'] == username and self._config['admin']['password'] == password
|
||||
|
||||
class ProxyAdmin(IProxyClient):
|
||||
"""
|
||||
Use to manage client side of admin session
|
||||
Add GUI to select wich session to see
|
||||
"""
|
||||
def __init__(self, server):
|
||||
self._server = server
|
||||
#self._list = widget.List(ProxyClientFactory._CLIENT_PROXY_.keys(), 100, 100, self.onSelect, widget.Anchor(0, 0, widget.RDPWidgetListener(self._server._controller)))
|
||||
self._list = widget.List(["salut les copains"], 300, 300, self.onSelect, widget.Anchor(0, 0, widget.RDPWidgetListener(self._server._controller)))
|
||||
self._list = view.ListView(ProxyClientFactory._CLIENT_PROXY_.keys(), 300, 300, self.onSelect)
|
||||
self._render = view.RDPRenderer(self._server._controller)
|
||||
self._list.update(self._render)
|
||||
def getColorDepth(self):
|
||||
return 16
|
||||
def sendKeyEventScancode(self, code, isPressed):
|
||||
if isPressed:
|
||||
self._list.keyEvent(code)
|
||||
self._list.update(self._render)
|
||||
def sendKeyEventUnicode(self, code, isPressed):
|
||||
pass
|
||||
def sendPointerEvent(self, x, y, button, isPressed):
|
||||
pass
|
||||
def sendRefreshOrder(self, left, top, right, bottom):
|
||||
self._list.keyEvent(code)
|
||||
self._list.update(self._render)
|
||||
def onSelect(self, name):
|
||||
if ProxyClientFactory._CLIENT_PROXY_.has_key(name):
|
||||
self._server.clientConnected(ProxyClient(ProxyClientFactory._CLIENT_PROXY_[name]._controller, self._server))
|
||||
|
||||
@@ -668,7 +668,7 @@ class String(Type, CallableValue):
|
||||
"""
|
||||
String network type
|
||||
"""
|
||||
def __init__(self, value = "", readLen = None, conditional = lambda:True, optional = False, constant = False, unicode = False):
|
||||
def __init__(self, value = "", readLen = None, conditional = lambda:True, optional = False, constant = False, unicode = False, until = None):
|
||||
"""
|
||||
@param value: python string use for inner value
|
||||
@param readLen: length use to read in stream (SimpleType) if 0 read entire stream
|
||||
@@ -676,12 +676,14 @@ class String(Type, CallableValue):
|
||||
@param optional: boolean check before read if there is still data in stream
|
||||
@param constant: if true check any changement of object during reading
|
||||
@param unicode: Encode and decode value as unicode
|
||||
@param until: read until sequence is readed or write sequence at the end of string
|
||||
"""
|
||||
Type.__init__(self, conditional = conditional, optional = optional, constant = constant)
|
||||
CallableValue.__init__(self, value)
|
||||
#type use to know read length
|
||||
self._readLen = readLen
|
||||
self._unicode = unicode
|
||||
self._until = until
|
||||
|
||||
def __eq__(self, other):
|
||||
'''
|
||||
@@ -710,6 +712,11 @@ class String(Type, CallableValue):
|
||||
Write the entire raw value
|
||||
@param s: Stream
|
||||
"""
|
||||
toWrite = self.value
|
||||
|
||||
if not self._until is None:
|
||||
toWrite += self._until
|
||||
|
||||
if self._unicode:
|
||||
s.write(encodeUnicode(self.value))
|
||||
else:
|
||||
@@ -722,7 +729,12 @@ class String(Type, CallableValue):
|
||||
@param s: Stream
|
||||
"""
|
||||
if self._readLen is None:
|
||||
self.value = s.getvalue()
|
||||
if self._until is None:
|
||||
self.value = s.getvalue()
|
||||
else:
|
||||
self.value = ""
|
||||
while self.value[-len(self._until):] != self._until or s.dataLen() == 0:
|
||||
self.value += s.read(1)
|
||||
else:
|
||||
self.value = s.read(self._readLen.value)
|
||||
|
||||
|
||||
@@ -576,7 +576,7 @@ class Server(PDULayer, tpkt.IFastPathListener):
|
||||
self._transport.close()
|
||||
|
||||
def recvFastPath(self, fastPathS):
|
||||
"""
|
||||
"""r
|
||||
Implement IFastPathListener interface
|
||||
Fast path is needed by RDP 8.0
|
||||
@param fastPathS: Stream that contain fast path data
|
||||
|
||||
@@ -247,7 +247,6 @@ class RDPServerController(pdu.layer.PDUServerListener):
|
||||
@param colorDepth: 15, 16, 24
|
||||
"""
|
||||
self._isReady = False
|
||||
self._sendReady = False
|
||||
#list of observer
|
||||
self._serverObserver = []
|
||||
#build RDP protocol stack
|
||||
@@ -342,9 +341,6 @@ class RDPServerController(pdu.layer.PDUServerListener):
|
||||
RDP stack is now ready
|
||||
"""
|
||||
self._isReady = True
|
||||
if self._sendReady:
|
||||
return
|
||||
self._sendReady = True
|
||||
for observer in self._serverObserver:
|
||||
observer.onReady()
|
||||
|
||||
@@ -490,6 +486,7 @@ class RDPServerObserver(object):
|
||||
def onReady(self):
|
||||
"""
|
||||
Stack is ready and connected
|
||||
May be called after an setColorDepth too
|
||||
"""
|
||||
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onReady", "RDPServerObserver"))
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ RDP basic security is not supported by RDPY (because is not a true security laye
|
||||
"""
|
||||
|
||||
from rdpy.network.layer import LayerAutomata, IStreamSender
|
||||
from rdpy.network.type import UInt8, UInt16Le, UInt16Be, UInt32Le, CompositeType, sizeof
|
||||
from rdpy.network.type import UInt8, UInt16Le, UInt16Be, UInt32Le, CompositeType, sizeof, String
|
||||
from rdpy.base.error import InvalidExpectedDataException
|
||||
|
||||
class MessageType(object):
|
||||
@@ -66,17 +66,30 @@ class NegotiationFailureCode(object):
|
||||
HYBRID_REQUIRED_BY_SERVER = 0x00000005
|
||||
SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER = 0x00000006
|
||||
|
||||
class TPDUConnectMessage(CompositeType):
|
||||
class ClientConnectionRequestPDU(CompositeType):
|
||||
"""
|
||||
Header of TPDU connection messages
|
||||
Connection request
|
||||
client -> server
|
||||
@see: http://msdn.microsoft.com/en-us/library/cc240470.aspx
|
||||
"""
|
||||
def __init__(self, code):
|
||||
"""
|
||||
@param code: MessageType
|
||||
"""
|
||||
def __init__(self):
|
||||
CompositeType.__init__(self)
|
||||
self.len = UInt8(lambda:sizeof(self) - 1)
|
||||
self.code = UInt8(code, constant = True)
|
||||
self.code = UInt8(MessageType.X224_TPDU_CONNECTION_REQUEST, constant = True)
|
||||
self.padding = (UInt16Be(), UInt16Be(), UInt8())
|
||||
self.cookie = String(until = "\x0d\x0a", conditional = lambda:(self.len._is_readed and self.len.value > 14))
|
||||
#read if there is enough data
|
||||
self.protocolNeg = Negotiation(optional = True)
|
||||
|
||||
class ServerConnectionConfirm(CompositeType):
|
||||
"""
|
||||
Server response
|
||||
@see: http://msdn.microsoft.com/en-us/library/cc240506.aspx
|
||||
"""
|
||||
def __init__(self):
|
||||
CompositeType.__init__(self)
|
||||
self.len = UInt8(lambda:sizeof(self) - 1)
|
||||
self.code = UInt8(MessageType.X224_TPDU_CONNECTION_CONFIRM, constant = True)
|
||||
self.padding = (UInt16Be(), UInt16Be(), UInt8())
|
||||
#read if there is enough data
|
||||
self.protocolNeg = Negotiation(optional = True)
|
||||
@@ -103,7 +116,7 @@ class Negotiation(CompositeType):
|
||||
self.code = UInt8()
|
||||
self.flag = UInt8(0)
|
||||
#always 8
|
||||
self.len = UInt16Le(0x0008)#not constant because freerdp send me random value...
|
||||
self.len = UInt16Le(0x0008, constant = True)#not constant because freerdp send me random value...
|
||||
self.selectedProtocol = UInt32Le(conditional = lambda: (self.code.value != NegociationType.TYPE_RDP_NEG_FAILURE))
|
||||
self.failureCode = UInt32Le(conditional = lambda: (self.code.value == NegociationType.TYPE_RDP_NEG_FAILURE))
|
||||
|
||||
@@ -164,7 +177,7 @@ class Client(TPDULayer):
|
||||
Next state is recvConnectionConfirm
|
||||
@see: http://msdn.microsoft.com/en-us/library/cc240500.aspx
|
||||
"""
|
||||
message = TPDUConnectMessage(MessageType.X224_TPDU_CONNECTION_REQUEST)
|
||||
message = ClientConnectionRequestPDU()
|
||||
message.protocolNeg.code.value = NegociationType.TYPE_RDP_NEG_REQ
|
||||
message.protocolNeg.selectedProtocol.value = self._requestedProtocol
|
||||
self._transport.send(message)
|
||||
@@ -179,7 +192,7 @@ class Client(TPDULayer):
|
||||
@see: response -> http://msdn.microsoft.com/en-us/library/cc240506.aspx
|
||||
@see: failure ->http://msdn.microsoft.com/en-us/library/cc240507.aspx
|
||||
"""
|
||||
message = TPDUConnectMessage(MessageType.X224_TPDU_CONNECTION_CONFIRM)
|
||||
message = ServerConnectionConfirm()
|
||||
data.readType(message)
|
||||
|
||||
#check presence of negotiation response
|
||||
@@ -231,7 +244,7 @@ class Server(TPDULayer):
|
||||
@param data: Stream
|
||||
@see : http://msdn.microsoft.com/en-us/library/cc240470.aspx
|
||||
"""
|
||||
message = TPDUConnectMessage(MessageType.X224_TPDU_CONNECTION_REQUEST)
|
||||
message = ClientConnectionRequestPDU()
|
||||
data.readType(message)
|
||||
|
||||
if not message.protocolNeg._is_readed or message.protocolNeg.failureCode._is_readed:
|
||||
@@ -241,8 +254,7 @@ class Server(TPDULayer):
|
||||
|
||||
if not self._requestedProtocol & Protocols.PROTOCOL_SSL:
|
||||
#send error message and quit
|
||||
message = TPDUConnectMessage()
|
||||
message.code.value = MessageType.X224_TPDU_CONNECTION_CONFIRM
|
||||
message = ServerConnectionConfirm()
|
||||
message.protocolNeg.code.value = NegociationType.TYPE_RDP_NEG_FAILURE
|
||||
message.protocolNeg.failureCode.value = NegotiationFailureCode.SSL_REQUIRED_BY_SERVER
|
||||
self._transport.send(message)
|
||||
@@ -258,7 +270,7 @@ class Server(TPDULayer):
|
||||
Next state is recvData
|
||||
@see : http://msdn.microsoft.com/en-us/library/cc240501.aspx
|
||||
"""
|
||||
message = TPDUConnectMessage(MessageType.X224_TPDU_CONNECTION_CONFIRM)
|
||||
message = ServerConnectionConfirm()
|
||||
message.protocolNeg.code.value = NegociationType.TYPE_RDP_NEG_RSP
|
||||
message.protocolNeg.selectedProtocol.value = self._selectedProtocol
|
||||
self._transport.send(message)
|
||||
|
||||
@@ -179,7 +179,7 @@ class RDPClientQt(RDPClientObserver, QAdaptor):
|
||||
@param e: QKeyEvent
|
||||
@param isPressed: event come from press or release action
|
||||
"""
|
||||
self._controller.sendKeyEventUnicode(ord(unicode(e.text().toUtf8(), encoding="UTF-8")), isPressed)
|
||||
self._controller.sendKeyEventScancode(e.nativeScanCode(), isPressed)
|
||||
|
||||
def closeEvent(self, e):
|
||||
"""
|
||||
@@ -207,28 +207,28 @@ class RDPClientQt(RDPClientObserver, QAdaptor):
|
||||
image = QtGui.QImage(width, height, QtGui.QImage.Format_RGB555)
|
||||
data = rle.bitmap_decompress(image.bits(), width, height, data, len(data), 2)
|
||||
else:
|
||||
image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB555)
|
||||
image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB555).transformed(QtGui.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0))
|
||||
|
||||
elif bitsPerPixel == 16:
|
||||
if isCompress:
|
||||
image = QtGui.QImage(width, height, QtGui.QImage.Format_RGB16)
|
||||
data = rle.bitmap_decompress(image.bits(), width, height, data, len(data), 2)
|
||||
else:
|
||||
image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB16)
|
||||
image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB16).transformed(QtGui.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0))
|
||||
|
||||
elif bitsPerPixel == 24:
|
||||
if isCompress:
|
||||
image = QtGui.QImage(width, height, QtGui.QImage.Format_RGB24)
|
||||
data = rle.bitmap_decompress(image.bits(), width, height, data, len(data), 3)
|
||||
else:
|
||||
image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB24)
|
||||
image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB24).transformed(QtGui.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0))
|
||||
|
||||
elif bitsPerPixel == 32:
|
||||
if isCompress:
|
||||
image = QtGui.QImage(width, height, QtGui.QImage.Format_RGB32)
|
||||
data = rle.bitmap_decompress(image.bits(), width, height, data, len(data), 4)
|
||||
else:
|
||||
image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB32)
|
||||
image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB32).transformed(QtGui.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0))
|
||||
else:
|
||||
log.error("Receive image in bad format")
|
||||
return
|
||||
@@ -288,9 +288,6 @@ class QRemoteDesktop(QtGui.QWidget):
|
||||
Call when Qt renderer engine estimate that is needed
|
||||
@param e: QEvent
|
||||
"""
|
||||
#if there is no refresh -> done
|
||||
if self._refresh == []:
|
||||
return
|
||||
#fill buffer image
|
||||
with QtGui.QPainter(self._buffer) as qp:
|
||||
#draw image
|
||||
|
||||
137
rdpy/ui/view.py
Normal file
137
rdpy/ui/view.py
Normal file
@@ -0,0 +1,137 @@
|
||||
#
|
||||
# Copyright (c) 2014 Sylvain Peyrefitte
|
||||
#
|
||||
# This file is part of rdpy.
|
||||
#
|
||||
# rdpy is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
"""
|
||||
Fake widget
|
||||
"""
|
||||
from rdpy.base.error import CallPureVirtualFuntion
|
||||
from PyQt4 import QtGui, QtCore
|
||||
|
||||
|
||||
class KeyCode(object):
|
||||
ENTER = 28
|
||||
UP = 328
|
||||
DOWN = 336
|
||||
|
||||
class IRender(object):
|
||||
def translate(self, dx, dy):
|
||||
pass
|
||||
def drawImage(self, image):
|
||||
pass
|
||||
|
||||
class IView(object):
|
||||
def keyEvent(self, code):
|
||||
pass
|
||||
def pointerEvent(self, x, y, button):
|
||||
pass
|
||||
def update(self, render):
|
||||
pass
|
||||
|
||||
class AnchorView(IView):
|
||||
def __init__(self, x, y, view):
|
||||
self._x = x
|
||||
self._y = y
|
||||
self._view = view
|
||||
def keyEvent(self, code):
|
||||
self._view.keyEvent(code)
|
||||
def pointerEvent(self, x, y, button):
|
||||
self._view.pointerEvent(x - self._x, y - self._y)
|
||||
def update(self, render):
|
||||
render.translate(self._x, self._y)
|
||||
self._view.update(self._view, render)
|
||||
render.translate(- self._x, - self._y)
|
||||
|
||||
|
||||
class ListView(IView):
|
||||
"""
|
||||
List widget simulate by QT painter
|
||||
"""
|
||||
def __init__(self, labels, width, height, callback):
|
||||
self._labels = labels
|
||||
self._width = width
|
||||
self._height = height
|
||||
self._cellHeight = 25
|
||||
self._backGroudColor = QtGui.QColor(24, 93, 123)
|
||||
self._fontSize = 14
|
||||
self._current = 0
|
||||
self._callback = callback
|
||||
|
||||
def keyEvent(self, code):
|
||||
#enter key
|
||||
if len(self._labels) == 0:
|
||||
return
|
||||
if code == KeyCode.ENTER:
|
||||
self._callback(self._labels[self._current])
|
||||
elif code == KeyCode.DOWN:
|
||||
self._current = min(len(self._labels) - 1, self._current + 1)
|
||||
elif code == KeyCode.UP:
|
||||
self._current = max(0, self._current - 1)
|
||||
|
||||
def pointerEvent(self, x, y, button):
|
||||
pass
|
||||
|
||||
def update(self, render):
|
||||
"""
|
||||
Draw GUI that list active session
|
||||
"""
|
||||
i = 0
|
||||
drawArea = QtGui.QImage(self._width, self._height, QtGui.QImage.Format_RGB16)
|
||||
#fill with background Color
|
||||
drawArea.fill(self._backGroudColor)
|
||||
with QtGui.QPainter(drawArea) as qp:
|
||||
for label in self._labels:
|
||||
rect = QtCore.QRect(0, i * self._cellHeight, self._width, self._cellHeight)
|
||||
if i == self._current:
|
||||
qp.setPen(QtCore.Qt.darkGreen)
|
||||
qp.drawRoundedRect(rect, 0.2, 0.2)
|
||||
qp.setPen(QtCore.Qt.white)
|
||||
qp.setFont(QtGui.QFont('arial', self._fontSize, QtGui.QFont.Bold))
|
||||
qp.drawText(rect, QtCore.Qt.AlignCenter, label)
|
||||
i += 1
|
||||
render.drawImage(drawArea)
|
||||
|
||||
class RDPRenderer(object):
|
||||
def __init__(self, server):
|
||||
"""
|
||||
@param server: RDPServerController
|
||||
"""
|
||||
self._server = server
|
||||
self._dx = 0
|
||||
self._dy = 0
|
||||
self._renderSize = 64
|
||||
|
||||
def translate(self, dx, dy):
|
||||
self._dx += dx
|
||||
self._dy += dy
|
||||
|
||||
def drawImage(self, image):
|
||||
"""
|
||||
Render of widget
|
||||
"""
|
||||
nbWidth = image.width() / self._renderSize + 1
|
||||
nbHeight = image.height() / self._renderSize + 1
|
||||
for i in range(0, nbWidth):
|
||||
for j in range(0, nbHeight):
|
||||
tmp = image.copy(i * self._renderSize, j * self._renderSize, self._renderSize, self._renderSize)
|
||||
#in RDP image or bottom top encoded
|
||||
tmp = tmp.transformed(QtGui.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0))
|
||||
ptr = tmp.bits()
|
||||
ptr.setsize(tmp.byteCount())
|
||||
self._server.sendUpdate(i * self._renderSize + self._dx, j * self._renderSize + self._dy, min((i + 1) * self._renderSize, image.width()) + self._dx - 1, min((j + 1) * self._renderSize, image.height()) + self._dy - 1, tmp.width(), tmp.height(), 16, False, ptr.asstring())
|
||||
|
||||
Reference in New Issue
Block a user