This avoid a lot of unnecessary middle men. This also pushes the responsibility for pixel format conversion into the encoders and decoders. The new bufferFromBuffer() is used for direct conversion, rather than PixelTransformer/TransImageGetter.tags/v1.3.90
virtual void bell() = 0; | virtual void bell() = 0; | ||||
virtual void serverCutText(const char* str, rdr::U32 len) = 0; | virtual void serverCutText(const char* str, rdr::U32 len) = 0; | ||||
virtual void fillRect(const Rect& r, Pixel pix) = 0; | |||||
virtual void imageRect(const Rect& r, void* pixels) = 0; | |||||
virtual void copyRect(const Rect& r, int srcX, int srcY) = 0; | |||||
virtual rdr::U8* getRawBufferRW(const Rect& r, int* stride) = 0; | |||||
virtual void releaseRawBuffer(const Rect& r) = 0; | |||||
virtual const PixelFormat &getPreferredPF(void) = 0; | |||||
ConnParams cp; | ConnParams cp; | ||||
}; | }; | ||||
} | } |
*/ | */ | ||||
#include <rdr/InStream.h> | #include <rdr/InStream.h> | ||||
#include <rfb/CConnection.h> | #include <rfb/CConnection.h> | ||||
#include <rfb/CMsgHandler.h> | |||||
#include <rfb/PixelBuffer.h> | #include <rfb/PixelBuffer.h> | ||||
#include <rfb/CopyRectDecoder.h> | #include <rfb/CopyRectDecoder.h> | ||||
{ | { | ||||
} | } | ||||
void CopyRectDecoder::readRect(const Rect& r, CMsgHandler* handler) | |||||
void CopyRectDecoder::readRect(const Rect& r, ModifiablePixelBuffer* pb) | |||||
{ | { | ||||
int srcX = conn->getInStream()->readU16(); | int srcX = conn->getInStream()->readU16(); | ||||
int srcY = conn->getInStream()->readU16(); | int srcY = conn->getInStream()->readU16(); | ||||
handler->copyRect(r, srcX, srcY); | |||||
pb->copyRect(r, Point(r.tl.x-srcX, r.tl.y-srcY)); | |||||
} | } |
public: | public: | ||||
CopyRectDecoder(CConnection* conn); | CopyRectDecoder(CConnection* conn); | ||||
virtual ~CopyRectDecoder(); | virtual ~CopyRectDecoder(); | ||||
virtual void readRect(const Rect& r, CMsgHandler* handler); | |||||
virtual void readRect(const Rect& r, ModifiablePixelBuffer* pb); | |||||
}; | }; | ||||
} | } | ||||
#endif | #endif |
namespace rfb { | namespace rfb { | ||||
class CConnection; | class CConnection; | ||||
class CMsgHandler; | |||||
class ModifiablePixelBuffer; | |||||
class Decoder { | class Decoder { | ||||
public: | public: | ||||
Decoder(CConnection* conn); | Decoder(CConnection* conn); | ||||
virtual ~Decoder(); | virtual ~Decoder(); | ||||
virtual void readRect(const Rect& r, CMsgHandler* handler)=0; | |||||
// readRect() is the main interface that decodes the given rectangle | |||||
// with data from the CConnection, given at decoder creation, onto | |||||
// the ModifiablePixelBuffer. The PixelFormat of the PixelBuffer might | |||||
// not match the ConnParams and it is up to the decoder to do | |||||
// any necessary conversion. | |||||
virtual void readRect(const Rect& r, ModifiablePixelBuffer* pb)=0; | |||||
static bool supported(int encoding); | static bool supported(int encoding); | ||||
static Decoder* createDecoder(int encoding, CConnection* conn); | static Decoder* createDecoder(int encoding, CConnection* conn); |
#define __RFB_ENCODER_H__ | #define __RFB_ENCODER_H__ | ||||
#include <rfb/Rect.h> | #include <rfb/Rect.h> | ||||
#include <rfb/TransImageGetter.h> | |||||
namespace rfb { | namespace rfb { | ||||
class SConnection; | class SConnection; | ||||
class TransImageGetter; | |||||
class PixelBuffer; | |||||
class Encoder { | class Encoder { | ||||
public: | public: | ||||
virtual int getNumRects(const Rect &r) { return 1; } | virtual int getNumRects(const Rect &r) { return 1; } | ||||
// writeRect() is the main interface that encodes the given rectangle | // writeRect() is the main interface that encodes the given rectangle | ||||
// with data from the ImageGetter onto the SMsgWriter given at | |||||
// encoder creation. | |||||
virtual void writeRect(const Rect& r, TransImageGetter* ig)=0; | |||||
// with data from the PixelBuffer onto the SConnection given at | |||||
// encoder creation. The PixelFormat of the PixelBuffer might not | |||||
// match the ConnParams and it is up ot the encoder to do | |||||
// any necessary conversion. | |||||
virtual void writeRect(const Rect& r, PixelBuffer* pb)=0; | |||||
static bool supported(int encoding); | static bool supported(int encoding); | ||||
static Encoder* createEncoder(int encoding, SConnection* conn); | static Encoder* createEncoder(int encoding, SConnection* conn); |
*/ | */ | ||||
#include <rfb/CMsgReader.h> | #include <rfb/CMsgReader.h> | ||||
#include <rfb/CConnection.h> | #include <rfb/CConnection.h> | ||||
#include <rfb/CMsgHandler.h> | |||||
#include <rfb/PixelBuffer.h> | |||||
#include <rfb/HextileDecoder.h> | #include <rfb/HextileDecoder.h> | ||||
using namespace rfb; | using namespace rfb; | ||||
{ | { | ||||
} | } | ||||
void HextileDecoder::readRect(const Rect& r, CMsgHandler* handler) | |||||
void HextileDecoder::readRect(const Rect& r, ModifiablePixelBuffer* pb) | |||||
{ | { | ||||
rdr::InStream* is = conn->getInStream(); | rdr::InStream* is = conn->getInStream(); | ||||
rdr::U8* buf = conn->reader()->getImageBuf(16 * 16 * 4); | rdr::U8* buf = conn->reader()->getImageBuf(16 * 16 * 4); | ||||
switch (conn->cp.pf().bpp) { | |||||
case 8: hextileDecode8 (r, is, (rdr::U8*) buf, handler); break; | |||||
case 16: hextileDecode16(r, is, (rdr::U16*)buf, handler); break; | |||||
case 32: hextileDecode32(r, is, (rdr::U32*)buf, handler); break; | |||||
const PixelFormat& pf = conn->cp.pf(); | |||||
switch (pf.bpp) { | |||||
case 8: hextileDecode8 (r, is, (rdr::U8*) buf, pf, pb); break; | |||||
case 16: hextileDecode16(r, is, (rdr::U16*)buf, pf, pb); break; | |||||
case 32: hextileDecode32(r, is, (rdr::U32*)buf, pf, pb); break; | |||||
} | } | ||||
} | } |
public: | public: | ||||
HextileDecoder(CConnection* conn); | HextileDecoder(CConnection* conn); | ||||
virtual ~HextileDecoder(); | virtual ~HextileDecoder(); | ||||
virtual void readRect(const Rect& r, CMsgHandler* handler); | |||||
virtual void readRect(const Rect& r, ModifiablePixelBuffer* pb); | |||||
}; | }; | ||||
} | } | ||||
#endif | #endif |
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | ||||
* USA. | * USA. | ||||
*/ | */ | ||||
#include <rfb/TransImageGetter.h> | |||||
#include <rfb/encodings.h> | #include <rfb/encodings.h> | ||||
#include <rfb/SMsgWriter.h> | #include <rfb/SMsgWriter.h> | ||||
#include <rfb/SConnection.h> | #include <rfb/SConnection.h> | ||||
#include <rfb/HextileEncoder.h> | #include <rfb/HextileEncoder.h> | ||||
#include <rfb/PixelFormat.h> | |||||
#include <rfb/PixelBuffer.h> | |||||
#include <rfb/Configuration.h> | #include <rfb/Configuration.h> | ||||
using namespace rfb; | using namespace rfb; | ||||
{ | { | ||||
} | } | ||||
void HextileEncoder::writeRect(const Rect& r, TransImageGetter* ig) | |||||
void HextileEncoder::writeRect(const Rect& r, PixelBuffer* pb) | |||||
{ | { | ||||
conn->writer()->startRect(r, encodingHextile); | conn->writer()->startRect(r, encodingHextile); | ||||
rdr::OutStream* os = conn->getOutStream(); | rdr::OutStream* os = conn->getOutStream(); | ||||
switch (conn->cp.pf().bpp) { | |||||
const PixelFormat& pf = conn->cp.pf(); | |||||
switch (pf.bpp) { | |||||
case 8: | case 8: | ||||
if (improvedHextile) { | if (improvedHextile) { | ||||
hextileEncodeBetter8(r, os, ig); | |||||
hextileEncodeBetter8(r, os, pf, pb); | |||||
} else { | } else { | ||||
hextileEncode8(r, os, ig); | |||||
hextileEncode8(r, os, pf, pb); | |||||
} | } | ||||
break; | break; | ||||
case 16: | case 16: | ||||
if (improvedHextile) { | if (improvedHextile) { | ||||
hextileEncodeBetter16(r, os, ig); | |||||
hextileEncodeBetter16(r, os, pf, pb); | |||||
} else { | } else { | ||||
hextileEncode16(r, os, ig); | |||||
hextileEncode16(r, os, pf, pb); | |||||
} | } | ||||
break; | break; | ||||
case 32: | case 32: | ||||
if (improvedHextile) { | if (improvedHextile) { | ||||
hextileEncodeBetter32(r, os, ig); | |||||
hextileEncodeBetter32(r, os, pf, pb); | |||||
} else { | } else { | ||||
hextileEncode32(r, os, ig); | |||||
hextileEncode32(r, os, pf, pb); | |||||
} | } | ||||
break; | break; | ||||
} | } |
public: | public: | ||||
HextileEncoder(SConnection* conn); | HextileEncoder(SConnection* conn); | ||||
virtual ~HextileEncoder(); | virtual ~HextileEncoder(); | ||||
virtual void writeRect(const Rect& r, TransImageGetter* ig); | |||||
virtual void writeRect(const Rect& r, PixelBuffer* pb); | |||||
}; | }; | ||||
} | } | ||||
#endif | #endif |
*/ | */ | ||||
#include <rfb/CMsgReader.h> | #include <rfb/CMsgReader.h> | ||||
#include <rfb/CConnection.h> | #include <rfb/CConnection.h> | ||||
#include <rfb/CMsgHandler.h> | |||||
#include <rfb/PixelBuffer.h> | |||||
#include <rfb/RREDecoder.h> | #include <rfb/RREDecoder.h> | ||||
using namespace rfb; | using namespace rfb; | ||||
{ | { | ||||
} | } | ||||
void RREDecoder::readRect(const Rect& r, CMsgHandler* handler) | |||||
void RREDecoder::readRect(const Rect& r, ModifiablePixelBuffer* pb) | |||||
{ | { | ||||
rdr::InStream* is = conn->getInStream(); | rdr::InStream* is = conn->getInStream(); | ||||
switch (conn->cp.pf().bpp) { | |||||
case 8: rreDecode8 (r, is, handler); break; | |||||
case 16: rreDecode16(r, is, handler); break; | |||||
case 32: rreDecode32(r, is, handler); break; | |||||
const PixelFormat& pf = conn->cp.pf(); | |||||
switch (pf.bpp) { | |||||
case 8: rreDecode8 (r, is, pf, pb); break; | |||||
case 16: rreDecode16(r, is, pf, pb); break; | |||||
case 32: rreDecode32(r, is, pf, pb); break; | |||||
} | } | ||||
} | } |
public: | public: | ||||
RREDecoder(CConnection* conn); | RREDecoder(CConnection* conn); | ||||
virtual ~RREDecoder(); | virtual ~RREDecoder(); | ||||
virtual void readRect(const Rect& r, CMsgHandler* handler); | |||||
virtual void readRect(const Rect& r, ModifiablePixelBuffer* pb); | |||||
}; | }; | ||||
} | } | ||||
#endif | #endif |
* USA. | * USA. | ||||
*/ | */ | ||||
#include <rdr/OutStream.h> | #include <rdr/OutStream.h> | ||||
#include <rfb/TransImageGetter.h> | |||||
#include <rfb/encodings.h> | #include <rfb/encodings.h> | ||||
#include <rfb/SMsgWriter.h> | #include <rfb/SMsgWriter.h> | ||||
#include <rfb/SConnection.h> | #include <rfb/SConnection.h> | ||||
#include <rfb/PixelFormat.h> | |||||
#include <rfb/PixelBuffer.h> | |||||
#include <rfb/RREEncoder.h> | #include <rfb/RREEncoder.h> | ||||
using namespace rfb; | using namespace rfb; | ||||
{ | { | ||||
} | } | ||||
void RREEncoder::writeRect(const Rect& r, TransImageGetter* ig) | |||||
void RREEncoder::writeRect(const Rect& r, PixelBuffer* pb) | |||||
{ | { | ||||
int w = r.width(); | int w = r.width(); | ||||
int h = r.height(); | int h = r.height(); | ||||
rdr::U8* imageBuf = conn->writer()->getImageBuf(w*h); | rdr::U8* imageBuf = conn->writer()->getImageBuf(w*h); | ||||
ig->getImage(imageBuf, r); | |||||
pb->getImage(conn->cp.pf(), imageBuf, r); | |||||
mos.clear(); | mos.clear(); | ||||
} | } | ||||
if (nSubrects < 0) { | if (nSubrects < 0) { | ||||
RawEncoder::writeRect(r, ig); | |||||
RawEncoder::writeRect(r, pb); | |||||
return; | return; | ||||
} | } | ||||
public: | public: | ||||
RREEncoder(SConnection* conn); | RREEncoder(SConnection* conn); | ||||
virtual ~RREEncoder(); | virtual ~RREEncoder(); | ||||
virtual void writeRect(const Rect& r, TransImageGetter* ig); | |||||
virtual void writeRect(const Rect& r, PixelBuffer* pb); | |||||
private: | private: | ||||
rdr::MemOutStream mos; | rdr::MemOutStream mos; | ||||
}; | }; |
#include <rdr/InStream.h> | #include <rdr/InStream.h> | ||||
#include <rfb/CMsgReader.h> | #include <rfb/CMsgReader.h> | ||||
#include <rfb/CConnection.h> | #include <rfb/CConnection.h> | ||||
#include <rfb/CMsgHandler.h> | |||||
#include <rfb/PixelBuffer.h> | |||||
#include <rfb/RawDecoder.h> | #include <rfb/RawDecoder.h> | ||||
using namespace rfb; | using namespace rfb; | ||||
{ | { | ||||
} | } | ||||
void RawDecoder::readRect(const Rect& r, CMsgHandler* handler) | |||||
void RawDecoder::readRect(const Rect& r, ModifiablePixelBuffer* pb) | |||||
{ | { | ||||
int x = r.tl.x; | int x = r.tl.x; | ||||
int y = r.tl.y; | int y = r.tl.y; | ||||
int h = r.height(); | int h = r.height(); | ||||
int nPixels; | int nPixels; | ||||
rdr::U8* imageBuf = conn->reader()->getImageBuf(w, w*h, &nPixels); | rdr::U8* imageBuf = conn->reader()->getImageBuf(w, w*h, &nPixels); | ||||
int bytesPerRow = w * (conn->cp.pf().bpp / 8); | |||||
const PixelFormat& pf = conn->cp.pf(); | |||||
int bytesPerRow = w * (pf.bpp / 8); | |||||
while (h > 0) { | while (h > 0) { | ||||
int nRows = nPixels / w; | int nRows = nPixels / w; | ||||
if (nRows > h) nRows = h; | if (nRows > h) nRows = h; | ||||
conn->getInStream()->readBytes(imageBuf, nRows * bytesPerRow); | conn->getInStream()->readBytes(imageBuf, nRows * bytesPerRow); | ||||
handler->imageRect(Rect(x, y, x+w, y+nRows), imageBuf); | |||||
pb->imageRect(pf, Rect(x, y, x+w, y+nRows), imageBuf); | |||||
h -= nRows; | h -= nRows; | ||||
y += nRows; | y += nRows; | ||||
} | } |
public: | public: | ||||
RawDecoder(CConnection* conn); | RawDecoder(CConnection* conn); | ||||
virtual ~RawDecoder(); | virtual ~RawDecoder(); | ||||
virtual void readRect(const Rect& r, CMsgHandler* handler); | |||||
virtual void readRect(const Rect& r, ModifiablePixelBuffer* pb); | |||||
}; | }; | ||||
} | } | ||||
#endif | #endif |
* USA. | * USA. | ||||
*/ | */ | ||||
#include <rdr/OutStream.h> | #include <rdr/OutStream.h> | ||||
#include <rfb/TransImageGetter.h> | |||||
#include <rfb/encodings.h> | #include <rfb/encodings.h> | ||||
#include <rfb/SMsgWriter.h> | #include <rfb/SMsgWriter.h> | ||||
#include <rfb/SConnection.h> | #include <rfb/SConnection.h> | ||||
#include <rfb/PixelBuffer.h> | |||||
#include <rfb/RawEncoder.h> | #include <rfb/RawEncoder.h> | ||||
using namespace rfb; | using namespace rfb; | ||||
{ | { | ||||
} | } | ||||
void RawEncoder::writeRect(const Rect& r, TransImageGetter* ig) | |||||
void RawEncoder::writeRect(const Rect& r, PixelBuffer* pb) | |||||
{ | { | ||||
int x = r.tl.x; | |||||
int y = r.tl.y; | |||||
int w = r.width(); | |||||
int h = r.height(); | |||||
int nPixels; | |||||
rdr::U8* imageBuf = conn->writer()->getImageBuf(w, w*h, &nPixels); | |||||
int bytesPerRow = w * (conn->cp.pf().bpp / 8); | |||||
rdr::U8* buf = conn->writer()->getImageBuf(r.area()); | |||||
pb->getImage(conn->cp.pf(), buf, r); | |||||
conn->writer()->startRect(r, encodingRaw); | conn->writer()->startRect(r, encodingRaw); | ||||
while (h > 0) { | |||||
int nRows = nPixels / w; | |||||
if (nRows > h) nRows = h; | |||||
ig->getImage(imageBuf, Rect(x, y, x+w, y+nRows)); | |||||
conn->getOutStream()->writeBytes(imageBuf, nRows * bytesPerRow); | |||||
h -= nRows; | |||||
y += nRows; | |||||
} | |||||
conn->getOutStream()->writeBytes(buf, r.area() * conn->cp.pf().bpp/8); | |||||
conn->writer()->endRect(); | conn->writer()->endRect(); | ||||
} | } |
public: | public: | ||||
RawEncoder(SConnection* conn); | RawEncoder(SConnection* conn); | ||||
virtual ~RawEncoder(); | virtual ~RawEncoder(); | ||||
virtual void writeRect(const Rect& r, TransImageGetter* ig); | |||||
virtual void writeRect(const Rect& r, PixelBuffer* pb); | |||||
}; | }; | ||||
} | } | ||||
#endif | #endif |
*/ | */ | ||||
#include <rfb/CMsgReader.h> | #include <rfb/CMsgReader.h> | ||||
#include <rfb/CConnection.h> | #include <rfb/CConnection.h> | ||||
#include <rfb/CMsgHandler.h> | |||||
#include <rfb/PixelBuffer.h> | |||||
#include <rfb/TightDecoder.h> | #include <rfb/TightDecoder.h> | ||||
using namespace rfb; | using namespace rfb; | ||||
{ | { | ||||
} | } | ||||
void TightDecoder::readRect(const Rect& r, CMsgHandler* handler) | |||||
void TightDecoder::readRect(const Rect& r, ModifiablePixelBuffer* pb) | |||||
{ | { | ||||
is = conn->getInStream(); | is = conn->getInStream(); | ||||
this->handler = handler; | |||||
clientpf = handler->getPreferredPF(); | |||||
serverpf = handler->cp.pf(); | |||||
this->pb = pb; | |||||
clientpf = pb->getPF(); | |||||
serverpf = conn->cp.pf(); | |||||
if (clientpf.equal(serverpf)) { | if (clientpf.equal(serverpf)) { | ||||
/* Decode directly into the framebuffer (fast path) */ | /* Decode directly into the framebuffer (fast path) */ |
public: | public: | ||||
TightDecoder(CConnection* conn); | TightDecoder(CConnection* conn); | ||||
virtual ~TightDecoder(); | virtual ~TightDecoder(); | ||||
virtual void readRect(const Rect& r, CMsgHandler* handler); | |||||
virtual void readRect(const Rect& r, ModifiablePixelBuffer* pb); | |||||
private: | private: | ||||
rdr::U32 readCompact(rdr::InStream* is); | rdr::U32 readCompact(rdr::InStream* is); | ||||
void directFillRect16(const Rect& r, Pixel pix); | void directFillRect16(const Rect& r, Pixel pix); | ||||
void directFillRect32(const Rect& r, Pixel pix); | void directFillRect32(const Rect& r, Pixel pix); | ||||
CMsgHandler* handler; | |||||
ModifiablePixelBuffer* pb; | |||||
rdr::InStream* is; | rdr::InStream* is; | ||||
rdr::ZlibInStream zis[4]; | rdr::ZlibInStream zis[4]; | ||||
JpegDecompressor jd; | JpegDecompressor jd; |
* USA. | * USA. | ||||
*/ | */ | ||||
#include <rdr/OutStream.h> | #include <rdr/OutStream.h> | ||||
#include <rfb/TransImageGetter.h> | |||||
#include <rfb/PixelBuffer.h> | #include <rfb/PixelBuffer.h> | ||||
#include <rfb/encodings.h> | #include <rfb/encodings.h> | ||||
#include <rfb/ConnParams.h> | #include <rfb/ConnParams.h> | ||||
} | } | ||||
} | } | ||||
void TightEncoder::writeRect(const Rect& _r, TransImageGetter* _ig) | |||||
void TightEncoder::writeRect(const Rect& _r, PixelBuffer* _pb) | |||||
{ | { | ||||
ig = _ig; | |||||
serverpf = ig->getPixelBuffer()->getPF(); | |||||
pb = _pb; | |||||
serverpf = pb->getPF(); | |||||
ConnParams* cp = &conn->cp; | ConnParams* cp = &conn->cp; | ||||
clientpf = cp->pf(); | clientpf = cp->pf(); | ||||
} | } | ||||
if (bestr.tl.x != x) { | if (bestr.tl.x != x) { | ||||
sr.setXYWH(x, bestr.tl.y, bestr.tl.x - x, bestr.height()); | sr.setXYWH(x, bestr.tl.y, bestr.tl.x - x, bestr.height()); | ||||
writeRect(sr, _ig); | |||||
writeRect(sr, _pb); | |||||
} | } | ||||
// Send solid-color rectangle. | // Send solid-color rectangle. | ||||
if (bestr.br.x != r.br.x) { | if (bestr.br.x != r.br.x) { | ||||
sr.setXYWH(bestr.br.x, bestr.tl.y, r.br.x - bestr.br.x, | sr.setXYWH(bestr.br.x, bestr.tl.y, r.br.x - bestr.br.x, | ||||
bestr.height()); | bestr.height()); | ||||
writeRect(sr, _ig); | |||||
writeRect(sr, _pb); | |||||
} | } | ||||
if (bestr.br.y != r.br.y) { | if (bestr.br.y != r.br.y) { | ||||
sr.setXYWH(x, bestr.br.y, w, r.br.y - bestr.br.y); | sr.setXYWH(x, bestr.br.y, w, r.br.y - bestr.br.y); | ||||
writeRect(sr, _ig); | |||||
writeRect(sr, _pb); | |||||
} | } | ||||
return; | return; |
namespace rfb { | namespace rfb { | ||||
class TransImageGetter; | |||||
class PixelBuffer; | |||||
struct TIGHT_CONF { | struct TIGHT_CONF { | ||||
unsigned int maxRectSize, maxRectWidth; | unsigned int maxRectSize, maxRectWidth; | ||||
virtual void setQualityLevel(int level); | virtual void setQualityLevel(int level); | ||||
virtual void setFineQualityLevel(int quality, int subsampling); | virtual void setFineQualityLevel(int quality, int subsampling); | ||||
virtual int getNumRects(const Rect &r); | virtual int getNumRects(const Rect &r); | ||||
virtual void writeRect(const Rect& r, TransImageGetter* ig); | |||||
virtual void writeRect(const Rect& r, PixelBuffer* pb); | |||||
private: | private: | ||||
bool checkSolidTile(Rect& r, rdr::U32* colorPtr, bool needSameColor); | bool checkSolidTile(Rect& r, rdr::U32* colorPtr, bool needSameColor); | ||||
rdr::MemOutStream mos; | rdr::MemOutStream mos; | ||||
rdr::ZlibOutStream zos[4]; | rdr::ZlibOutStream zos[4]; | ||||
JpegCompressor jc; | JpegCompressor jc; | ||||
TransImageGetter *ig; | |||||
PixelBuffer *pb; | |||||
PixelFormat serverpf, clientpf; | PixelFormat serverpf, clientpf; | ||||
bool pack24; | bool pack24; |
fenceDataLen(0), fenceData(NULL), | fenceDataLen(0), fenceData(NULL), | ||||
baseRTT(-1), minRTT(-1), seenCongestion(false), pingCounter(0), | baseRTT(-1), minRTT(-1), seenCongestion(false), pingCounter(0), | ||||
ackedOffset(0), sentOffset(0), congWindow(0), congestionTimer(this), | ackedOffset(0), sentOffset(0), congWindow(0), congestionTimer(this), | ||||
server(server_), | |||||
updates(false), image_getter(server->useEconomicTranslate), | |||||
server(server_), updates(false), | |||||
drawRenderedCursor(false), removeRenderedCursor(false), | drawRenderedCursor(false), removeRenderedCursor(false), | ||||
continuousUpdates(false), | continuousUpdates(false), | ||||
updateTimer(this), pointerEventTime(0), | updateTimer(this), pointerEventTime(0), | ||||
// work out what's actually changed. | // work out what's actually changed. | ||||
updates.clear(); | updates.clear(); | ||||
updates.add_changed(server->pb->getRect()); | updates.add_changed(server->pb->getRect()); | ||||
vlog.debug("pixel buffer changed - re-initialising image getter"); | |||||
image_getter.init(server->pb, cp.pf(), writer()); | |||||
writeFramebufferUpdate(); | writeFramebufferUpdate(); | ||||
} catch(rdr::Exception &e) { | } catch(rdr::Exception &e) { | ||||
close(e.str()); | close(e.str()); | ||||
char buffer[256]; | char buffer[256]; | ||||
cp.pf().print(buffer, 256); | cp.pf().print(buffer, 256); | ||||
vlog.info("Server default pixel format %s", buffer); | vlog.info("Server default pixel format %s", buffer); | ||||
image_getter.init(server->pb, cp.pf(), 0); | |||||
// - Mark the entire display as "dirty" | // - Mark the entire display as "dirty" | ||||
updates.add_changed(server->pb->getRect()); | updates.add_changed(server->pb->getRect()); | ||||
char buffer[256]; | char buffer[256]; | ||||
pf.print(buffer, 256); | pf.print(buffer, 256); | ||||
vlog.info("Client pixel format %s", buffer); | vlog.info("Client pixel format %s", buffer); | ||||
image_getter.init(server->pb, pf, writer()); | |||||
setCursor(); | setCursor(); | ||||
} | } | ||||
std::vector<Rect>::const_iterator i; | std::vector<Rect>::const_iterator i; | ||||
int encoding; | int encoding; | ||||
Encoder* encoder; | |||||
PixelBuffer* pb; | |||||
// Make sure the encoder has the latest settings | // Make sure the encoder has the latest settings | ||||
encoding = cp.currentEncoding(); | encoding = cp.currentEncoding(); | ||||
if (!encoders[encoding]) | if (!encoders[encoding]) | ||||
encoders[encoding] = Encoder::createEncoder(encoding, this); | encoders[encoding] = Encoder::createEncoder(encoding, this); | ||||
encoders[encoding]->setCompressLevel(cp.compressLevel); | |||||
encoders[encoding]->setQualityLevel(cp.qualityLevel); | |||||
encoders[encoding]->setFineQualityLevel(cp.fineQualityLevel, | |||||
cp.subsampling); | |||||
encoder = encoders[encoding]; | |||||
encoder->setCompressLevel(cp.compressLevel); | |||||
encoder->setQualityLevel(cp.qualityLevel); | |||||
encoder->setFineQualityLevel(cp.fineQualityLevel, cp.subsampling); | |||||
// Compute the number of rectangles. Tight encoder makes the things more | // Compute the number of rectangles. Tight encoder makes the things more | ||||
// complicated as compared to the original VNC4. | // complicated as compared to the original VNC4. | ||||
ui.changed.get_rects(&rects); | ui.changed.get_rects(&rects); | ||||
for (i = rects.begin(); i != rects.end(); i++) { | for (i = rects.begin(); i != rects.end(); i++) { | ||||
if (i->width() && i->height()) { | if (i->width() && i->height()) { | ||||
int nUpdateRects = encoders[encoding]->getNumRects(*i); | |||||
int nUpdateRects = encoder->getNumRects(*i); | |||||
if (nUpdateRects == 0 && cp.currentEncoding() == encodingTight) { | if (nUpdateRects == 0 && cp.currentEncoding() == encodingTight) { | ||||
// With Tight encoding and LastRect support, the client does not | // With Tight encoding and LastRect support, the client does not | ||||
// care about the number of rectangles in the update - it will | // care about the number of rectangles in the update - it will | ||||
writer()->writeCopyRect(*i, i->tl.x - ui.copy_delta.x, | writer()->writeCopyRect(*i, i->tl.x - ui.copy_delta.x, | ||||
i->tl.y - ui.copy_delta.y); | i->tl.y - ui.copy_delta.y); | ||||
pb = server->getPixelBuffer(); | |||||
ui.changed.get_rects(&rects); | ui.changed.get_rects(&rects); | ||||
for (i = rects.begin(); i != rects.end(); i++) | for (i = rects.begin(); i != rects.end(); i++) | ||||
encoders[encoding]->writeRect(*i, &image_getter); | |||||
encoder->writeRect(*i, pb); | |||||
if (drawRenderedCursor) { | if (drawRenderedCursor) { | ||||
image_getter.setPixelBuffer(&server->renderedCursor); | |||||
encoders[encoding]->writeRect(renderedCursorRect, &image_getter); | |||||
image_getter.setPixelBuffer(server->pb); | |||||
renderedCursorRect = server->renderedCursor.getEffectiveRect(); | |||||
encoder->writeRect(renderedCursorRect, &server->renderedCursor); | |||||
drawRenderedCursor = false; | drawRenderedCursor = false; | ||||
} | } |
#include <set> | #include <set> | ||||
#include <rfb/SConnection.h> | #include <rfb/SConnection.h> | ||||
#include <rfb/SMsgWriter.h> | #include <rfb/SMsgWriter.h> | ||||
#include <rfb/TransImageGetter.h> | |||||
#include <rfb/VNCServerST.h> | #include <rfb/VNCServerST.h> | ||||
#include <rfb/Timer.h> | #include <rfb/Timer.h> | ||||
VNCServerST* server; | VNCServerST* server; | ||||
SimpleUpdateTracker updates; | SimpleUpdateTracker updates; | ||||
TransImageGetter image_getter; | |||||
Region requested; | Region requested; | ||||
bool drawRenderedCursor, removeRenderedCursor; | bool drawRenderedCursor, removeRenderedCursor; | ||||
Rect renderedCursorRect; | Rect renderedCursorRect; |
name(strDup(name_)), pointerClient(0), comparer(0), | name(strDup(name_)), pointerClient(0), comparer(0), | ||||
renderedCursorInvalid(false), | renderedCursorInvalid(false), | ||||
queryConnectionHandler(0), keyRemapper(&KeyRemapper::defInstance), | queryConnectionHandler(0), keyRemapper(&KeyRemapper::defInstance), | ||||
useEconomicTranslate(false), | |||||
lastConnectionTime(0), disableclients(false), | lastConnectionTime(0), disableclients(false), | ||||
deferTimer(this), deferPending(false) | deferTimer(this), deferPending(false) | ||||
{ | { |
// Blacklist to be shared by multiple VNCServerST instances. | // Blacklist to be shared by multiple VNCServerST instances. | ||||
void setBlacklist(Blacklist* bl) {blHosts = bl ? bl : &blacklist;} | void setBlacklist(Blacklist* bl) {blHosts = bl ? bl : &blacklist;} | ||||
// setEconomicTranslate() determines (for new connections) whether pixels | |||||
// should be translated for <=16bpp clients using a large lookup table | |||||
// (fast) or separate, smaller R, G and B tables (slower). If set to true, | |||||
// small tables are used, to save memory. | |||||
void setEconomicTranslate(bool et) { useEconomicTranslate = et; } | |||||
// setKeyRemapper() replaces the VNCServerST's default key remapper. | // setKeyRemapper() replaces the VNCServerST's default key remapper. | ||||
// NB: A null pointer is valid here. | // NB: A null pointer is valid here. | ||||
void setKeyRemapper(KeyRemapper* kr) { keyRemapper = kr; } | void setKeyRemapper(KeyRemapper* kr) { keyRemapper = kr; } | ||||
QueryConnectionHandler* queryConnectionHandler; | QueryConnectionHandler* queryConnectionHandler; | ||||
KeyRemapper* keyRemapper; | KeyRemapper* keyRemapper; | ||||
bool useEconomicTranslate; | |||||
time_t lastUserInputTime; | time_t lastUserInputTime; | ||||
time_t lastDisconnectTime; | time_t lastDisconnectTime; | ||||
time_t lastConnectionTime; | time_t lastConnectionTime; |
*/ | */ | ||||
#include <rfb/CMsgReader.h> | #include <rfb/CMsgReader.h> | ||||
#include <rfb/CConnection.h> | #include <rfb/CConnection.h> | ||||
#include <rfb/CMsgHandler.h> | |||||
#include <rfb/PixelBuffer.h> | |||||
#include <rfb/ZRLEDecoder.h> | #include <rfb/ZRLEDecoder.h> | ||||
using namespace rfb; | using namespace rfb; | ||||
{ | { | ||||
} | } | ||||
void ZRLEDecoder::readRect(const Rect& r, CMsgHandler* handler) | |||||
void ZRLEDecoder::readRect(const Rect& r, ModifiablePixelBuffer* pb) | |||||
{ | { | ||||
rdr::InStream* is = conn->getInStream(); | rdr::InStream* is = conn->getInStream(); | ||||
rdr::U8* buf = conn->reader()->getImageBuf(64 * 64 * 4); | rdr::U8* buf = conn->reader()->getImageBuf(64 * 64 * 4); | ||||
switch (conn->cp.pf().bpp) { | |||||
case 8: zrleDecode8 (r, is, &zis, (rdr::U8*) buf, handler); break; | |||||
case 16: zrleDecode16(r, is, &zis, (rdr::U16*)buf, handler); break; | |||||
const rfb::PixelFormat& pf = conn->cp.pf(); | |||||
switch (pf.bpp) { | |||||
case 8: zrleDecode8 (r, is, &zis, (rdr::U8*) buf, pf, pb); break; | |||||
case 16: zrleDecode16(r, is, &zis, (rdr::U16*)buf, pf, pb); break; | |||||
case 32: | case 32: | ||||
{ | { | ||||
const rfb::PixelFormat& pf = handler->cp.pf(); | |||||
Pixel maxPixel = pf.pixelFromRGB((rdr::U16)-1, (rdr::U16)-1, (rdr::U16)-1); | Pixel maxPixel = pf.pixelFromRGB((rdr::U16)-1, (rdr::U16)-1, (rdr::U16)-1); | ||||
bool fitsInLS3Bytes = maxPixel < (1<<24); | bool fitsInLS3Bytes = maxPixel < (1<<24); | ||||
bool fitsInMS3Bytes = (maxPixel & 0xff) == 0; | bool fitsInMS3Bytes = (maxPixel & 0xff) == 0; | ||||
if ((fitsInLS3Bytes && pf.isLittleEndian()) || | if ((fitsInLS3Bytes && pf.isLittleEndian()) || | ||||
(fitsInMS3Bytes && pf.isBigEndian())) | (fitsInMS3Bytes && pf.isBigEndian())) | ||||
{ | { | ||||
zrleDecode24A(r, is, &zis, (rdr::U32*)buf, handler); | |||||
zrleDecode24A(r, is, &zis, (rdr::U32*)buf, pf, pb); | |||||
} | } | ||||
else if ((fitsInLS3Bytes && pf.isBigEndian()) || | else if ((fitsInLS3Bytes && pf.isBigEndian()) || | ||||
(fitsInMS3Bytes && pf.isLittleEndian())) | (fitsInMS3Bytes && pf.isLittleEndian())) | ||||
{ | { | ||||
zrleDecode24B(r, is, &zis, (rdr::U32*)buf, handler); | |||||
zrleDecode24B(r, is, &zis, (rdr::U32*)buf, pf, pb); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
zrleDecode32(r, is, &zis, (rdr::U32*)buf, handler); | |||||
zrleDecode32(r, is, &zis, (rdr::U32*)buf, pf, pb); | |||||
} | } | ||||
break; | break; | ||||
} | } |
public: | public: | ||||
ZRLEDecoder(CConnection* conn); | ZRLEDecoder(CConnection* conn); | ||||
virtual ~ZRLEDecoder(); | virtual ~ZRLEDecoder(); | ||||
virtual void readRect(const Rect& r, CMsgHandler* handler); | |||||
virtual void readRect(const Rect& r, ModifiablePixelBuffer* pb); | |||||
private: | private: | ||||
rdr::ZlibInStream zis; | rdr::ZlibInStream zis; | ||||
}; | }; |
*/ | */ | ||||
#include <rdr/OutStream.h> | #include <rdr/OutStream.h> | ||||
#include <rfb/Exception.h> | #include <rfb/Exception.h> | ||||
#include <rfb/TransImageGetter.h> | |||||
#include <rfb/encodings.h> | #include <rfb/encodings.h> | ||||
#include <rfb/ConnParams.h> | #include <rfb/ConnParams.h> | ||||
#include <rfb/SMsgWriter.h> | #include <rfb/SMsgWriter.h> | ||||
{ | { | ||||
} | } | ||||
void ZRLEEncoder::writeRect(const Rect& r, TransImageGetter* ig) | |||||
void ZRLEEncoder::writeRect(const Rect& r, PixelBuffer* pb) | |||||
{ | { | ||||
const PixelFormat& pf = conn->cp.pf(); | |||||
rdr::U8* imageBuf = conn->writer()->getImageBuf(64 * 64 * 4 + 4); | rdr::U8* imageBuf = conn->writer()->getImageBuf(64 * 64 * 4 + 4); | ||||
mos.clear(); | mos.clear(); | ||||
switch (conn->cp.pf().bpp) { | |||||
switch (pf.bpp) { | |||||
case 8: | case 8: | ||||
zrleEncode8(r, &mos, &zos, imageBuf, ig); | |||||
zrleEncode8(r, &mos, &zos, imageBuf, pf, pb); | |||||
break; | break; | ||||
case 16: | case 16: | ||||
zrleEncode16(r, &mos, &zos, imageBuf, ig); | |||||
zrleEncode16(r, &mos, &zos, imageBuf, pf, pb); | |||||
break; | break; | ||||
case 32: | case 32: | ||||
{ | { | ||||
const PixelFormat& pf = conn->cp.pf(); | |||||
Pixel maxPixel = pf.pixelFromRGB((rdr::U16)-1, (rdr::U16)-1, (rdr::U16)-1); | Pixel maxPixel = pf.pixelFromRGB((rdr::U16)-1, (rdr::U16)-1, (rdr::U16)-1); | ||||
bool fitsInLS3Bytes = maxPixel < (1<<24); | bool fitsInLS3Bytes = maxPixel < (1<<24); | ||||
bool fitsInMS3Bytes = (maxPixel & 0xff) == 0; | bool fitsInMS3Bytes = (maxPixel & 0xff) == 0; | ||||
if ((fitsInLS3Bytes && pf.isLittleEndian()) || | if ((fitsInLS3Bytes && pf.isLittleEndian()) || | ||||
(fitsInMS3Bytes && pf.isBigEndian())) | (fitsInMS3Bytes && pf.isBigEndian())) | ||||
{ | { | ||||
zrleEncode24A(r, &mos, &zos, imageBuf, ig); | |||||
zrleEncode24A(r, &mos, &zos, imageBuf, pf, pb); | |||||
} | } | ||||
else if ((fitsInLS3Bytes && pf.isBigEndian()) || | else if ((fitsInLS3Bytes && pf.isBigEndian()) || | ||||
(fitsInMS3Bytes && pf.isLittleEndian())) | (fitsInMS3Bytes && pf.isLittleEndian())) | ||||
{ | { | ||||
zrleEncode24B(r, &mos, &zos, imageBuf, ig); | |||||
zrleEncode24B(r, &mos, &zos, imageBuf, pf, pb); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
zrleEncode32(r, &mos, &zos, imageBuf, ig); | |||||
zrleEncode32(r, &mos, &zos, imageBuf, pf, pb); | |||||
} | } | ||||
break; | break; | ||||
} | } |
public: | public: | ||||
ZRLEEncoder(SConnection* conn); | ZRLEEncoder(SConnection* conn); | ||||
virtual ~ZRLEEncoder(); | virtual ~ZRLEEncoder(); | ||||
virtual void writeRect(const Rect& r, TransImageGetter* ig); | |||||
virtual void writeRect(const Rect& r, PixelBuffer* pb); | |||||
private: | private: | ||||
rdr::ZlibOutStream zos; | rdr::ZlibOutStream zos; | ||||
rdr::MemOutStream mos; | rdr::MemOutStream mos; |
#define HEXTILE_DECODE CONCAT2E(hextileDecode,BPP) | #define HEXTILE_DECODE CONCAT2E(hextileDecode,BPP) | ||||
void HEXTILE_DECODE (const Rect& r, rdr::InStream* is, PIXEL_T* buf, | void HEXTILE_DECODE (const Rect& r, rdr::InStream* is, PIXEL_T* buf, | ||||
CMsgHandler* handler) | |||||
const PixelFormat& pf, ModifiablePixelBuffer* pb) | |||||
{ | { | ||||
Rect t; | Rect t; | ||||
PIXEL_T bg = 0; | PIXEL_T bg = 0; | ||||
if (tileType & hextileRaw) { | if (tileType & hextileRaw) { | ||||
is->readBytes(buf, t.area() * (BPP/8)); | is->readBytes(buf, t.area() * (BPP/8)); | ||||
handler->imageRect(t, buf); | |||||
pb->imageRect(pf, t, buf); | |||||
continue; | continue; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
handler->imageRect(t, buf); | |||||
pb->imageRect(pf, t, buf); | |||||
} | } | ||||
} | } | ||||
} | } |
int HEXTILE_ENCODE_TILE (PIXEL_T* data, int w, int h, int tileType, | int HEXTILE_ENCODE_TILE (PIXEL_T* data, int w, int h, int tileType, | ||||
rdr::U8* encoded, PIXEL_T bg); | rdr::U8* encoded, PIXEL_T bg); | ||||
void HEXTILE_ENCODE(const Rect& r, rdr::OutStream* os, TransImageGetter *ig) | |||||
void HEXTILE_ENCODE(const Rect& r, rdr::OutStream* os, | |||||
const PixelFormat& pf, PixelBuffer* pb) | |||||
{ | { | ||||
Rect t; | Rect t; | ||||
PIXEL_T buf[256]; | PIXEL_T buf[256]; | ||||
t.br.x = __rfbmin(r.br.x, t.tl.x + 16); | t.br.x = __rfbmin(r.br.x, t.tl.x + 16); | ||||
ig->getImage(buf, t); | |||||
pb->getImage(pf, buf, t); | |||||
PIXEL_T bg = 0, fg = 0; | PIXEL_T bg = 0, fg = 0; | ||||
int tileType = TEST_TILE_TYPE(buf, t.width(), t.height(), &bg, &fg); | int tileType = TEST_TILE_TYPE(buf, t.width(), t.height(), &bg, &fg); | ||||
encoded, bg); | encoded, bg); | ||||
if (encodedLen < 0) { | if (encodedLen < 0) { | ||||
ig->getImage(buf, t); | |||||
pb->getImage(pf, buf, t); | |||||
os->writeU8(hextileRaw); | os->writeU8(hextileRaw); | ||||
os->writeBytes(buf, t.width() * t.height() * (BPP/8)); | os->writeBytes(buf, t.width() * t.height() * (BPP/8)); | ||||
oldBgValid = oldFgValid = false; | oldBgValid = oldFgValid = false; |
// Main encoding function. | // Main encoding function. | ||||
// | // | ||||
void HEXTILE_ENCODE(const Rect& r, rdr::OutStream* os, TransImageGetter *ig) | |||||
void HEXTILE_ENCODE(const Rect& r, rdr::OutStream* os, | |||||
const PixelFormat& pf, PixelBuffer* pb) | |||||
{ | { | ||||
Rect t; | Rect t; | ||||
PIXEL_T buf[256]; | PIXEL_T buf[256]; | ||||
t.br.x = __rfbmin(r.br.x, t.tl.x + 16); | t.br.x = __rfbmin(r.br.x, t.tl.x + 16); | ||||
ig->getImage(buf, t); | |||||
pb->getImage(pf, buf, t); | |||||
tile.newTile(buf, t.width(), t.height()); | tile.newTile(buf, t.width(), t.height()); | ||||
int tileType = tile.getFlags(); | int tileType = tile.getFlags(); |
#define READ_PIXEL CONCAT2E(readOpaque,BPP) | #define READ_PIXEL CONCAT2E(readOpaque,BPP) | ||||
#define RRE_DECODE CONCAT2E(rreDecode,BPP) | #define RRE_DECODE CONCAT2E(rreDecode,BPP) | ||||
void RRE_DECODE (const Rect& r, rdr::InStream* is, CMsgHandler* handler) | |||||
void RRE_DECODE (const Rect& r, rdr::InStream* is, | |||||
const PixelFormat& pf, ModifiablePixelBuffer* pb) | |||||
{ | { | ||||
int nSubrects = is->readU32(); | int nSubrects = is->readU32(); | ||||
PIXEL_T bg = is->READ_PIXEL(); | PIXEL_T bg = is->READ_PIXEL(); | ||||
handler->fillRect(r, bg); | |||||
pb->fillRect(pf, r, bg); | |||||
for (int i = 0; i < nSubrects; i++) { | for (int i = 0; i < nSubrects; i++) { | ||||
PIXEL_T pix = is->READ_PIXEL(); | PIXEL_T pix = is->READ_PIXEL(); | ||||
int y = is->readU16(); | int y = is->readU16(); | ||||
int w = is->readU16(); | int w = is->readU16(); | ||||
int h = is->readU16(); | int h = is->readU16(); | ||||
handler->fillRect(Rect(r.tl.x+x, r.tl.y+y, r.tl.x+x+w, r.tl.y+y+h), pix); | |||||
pb->fillRect(pf, Rect(r.tl.x+x, r.tl.y+y, r.tl.x+x+w, r.tl.y+y+h), pix); | |||||
} | } | ||||
} | } | ||||
} else { | } else { | ||||
pix = is->READ_PIXEL(); | pix = is->READ_PIXEL(); | ||||
} | } | ||||
handler->fillRect(r, pix); | |||||
pb->fillRect(serverpf, r, pix); | |||||
return; | return; | ||||
} | } | ||||
PIXEL_T *buf; | PIXEL_T *buf; | ||||
int stride = r.width(); | int stride = r.width(); | ||||
if (directDecode) buf = (PIXEL_T *)handler->getRawBufferRW(r, &stride); | |||||
if (directDecode) buf = (PIXEL_T *)pb->getBufferRW(r, &stride); | |||||
else buf = (PIXEL_T *)conn->reader()->getImageBuf(r.area()); | else buf = (PIXEL_T *)conn->reader()->getImageBuf(r.area()); | ||||
if (palSize == 0) { | if (palSize == 0) { | ||||
} | } | ||||
} | } | ||||
if (directDecode) handler->releaseRawBuffer(r); | |||||
else handler->imageRect(r, buf); | |||||
if (directDecode) pb->commitBufferRW(r); | |||||
else pb->imageRect(serverpf, r, buf); | |||||
delete [] netbuf; | delete [] netbuf; | ||||
// We always use direct decoding with JPEG images | // We always use direct decoding with JPEG images | ||||
int stride; | int stride; | ||||
rdr::U8 *buf = handler->getRawBufferRW(r, &stride); | |||||
rdr::U8 *buf = pb->getBufferRW(r, &stride); | |||||
jd.decompress(netbuf, compressedLen, buf, stride, r, clientpf); | jd.decompress(netbuf, compressedLen, buf, stride, r, clientpf); | ||||
handler->releaseRawBuffer(r); | |||||
pb->commitBufferRW(r); | |||||
delete [] netbuf; | delete [] netbuf; | ||||
} | } |
{ | { | ||||
int stride; | int stride; | ||||
rdr::U32 solidColor; | rdr::U32 solidColor; | ||||
const PIXEL_T *rawPixels = (const PIXEL_T *)ig->getRawBufferR(r, &stride); | |||||
const PIXEL_T *rawPixels = (const PIXEL_T *)pb->getBuffer(r, &stride); | |||||
PIXEL_T *pixels = NULL; | PIXEL_T *pixels = NULL; | ||||
bool grayScaleJPEG = (jpegSubsampling == subsampleGray && jpegQuality != -1); | bool grayScaleJPEG = (jpegSubsampling == subsampleGray && jpegQuality != -1); | ||||
if (forceSolid) { | if (forceSolid) { | ||||
// Subrectangle has already been determined to be solid. | // Subrectangle has already been determined to be solid. | ||||
ig->translatePixels(rawPixels, &solidColor, 1); | |||||
clientpf.bufferFromBuffer((rdr::U8*)&solidColor, serverpf, | |||||
(const rdr::U8*)rawPixels, 1); | |||||
pixels = (PIXEL_T *)&solidColor; | pixels = (PIXEL_T *)&solidColor; | ||||
palette.clear(); | palette.clear(); | ||||
palette.insert(solidColor, 1); | palette.insert(solidColor, 1); | ||||
if(palette.size() != 0 || jpegQuality == -1) { | if(palette.size() != 0 || jpegQuality == -1) { | ||||
pixels = (PIXEL_T *)conn->writer()->getImageBuf(r.area()); | pixels = (PIXEL_T *)conn->writer()->getImageBuf(r.area()); | ||||
stride = r.width(); | stride = r.width(); | ||||
ig->getImage(pixels, r); | |||||
pb->getImage(clientpf, pixels, r); | |||||
} | } | ||||
} else { | } else { | ||||
// Pixel translation will be required, so create an intermediate buffer, | // Pixel translation will be required, so create an intermediate buffer, | ||||
// translate the raw pixels into it, and count its colors. | // translate the raw pixels into it, and count its colors. | ||||
pixels = (PIXEL_T *)conn->writer()->getImageBuf(r.area()); | pixels = (PIXEL_T *)conn->writer()->getImageBuf(r.area()); | ||||
stride = r.width(); | stride = r.width(); | ||||
ig->getImage(pixels, r); | |||||
pb->getImage(clientpf, pixels, r); | |||||
if (grayScaleJPEG) palette.clear(); | if (grayScaleJPEG) palette.clear(); | ||||
else FILL_PALETTE(pixels, r.area()); | else FILL_PALETTE(pixels, r.area()); | ||||
int w = r.width(), h = r.height(); | int w = r.width(), h = r.height(); | ||||
const PIXEL_T *rowptr, *colptr, *rowptr2, *colptr2, | const PIXEL_T *rowptr, *colptr, *rowptr2, *colptr2, | ||||
*dataend = &data[stride * h]; | *dataend = &data[stride * h]; | ||||
bool willTransform = ig->willTransform(); | |||||
bool willTransform = !serverpf.equal(clientpf); | |||||
serverpf.bufferFromPixel((rdr::U8*)&mask, ~0); | serverpf.bufferFromPixel((rdr::U8*)&mask, ~0); | ||||
monodone: | monodone: | ||||
if (willTransform) { | if (willTransform) { | ||||
ig->translatePixels(&c0, &c0t, 1); | |||||
ig->translatePixels(&c1, &c1t, 1); | |||||
clientpf.bufferFromBuffer((rdr::U8*)&c0t, serverpf, (rdr::U8*)&c0, 1); | |||||
clientpf.bufferFromBuffer((rdr::U8*)&c1t, serverpf, (rdr::U8*)&c1, 1); | |||||
} | } | ||||
else { | else { | ||||
c0t = c0; c1t = c1; | c0t = c0; c1t = c1; | ||||
ni++; | ni++; | ||||
} else { | } else { | ||||
if (willTransform) | if (willTransform) | ||||
ig->translatePixels(&ci, &cit, 1); | |||||
clientpf.bufferFromBuffer((rdr::U8*)&cit, serverpf, (rdr::U8*)&ci, 1); | |||||
else | else | ||||
cit = ci; | cit = ci; | ||||
if (!palette.insert (cit, ni) || (palette.size() > palMaxColors)) { | if (!palette.insert (cit, ni) || (palette.size() > palMaxColors)) { | ||||
rowptr += stride; | rowptr += stride; | ||||
colptr = rowptr; | colptr = rowptr; | ||||
} | } | ||||
ig->translatePixels(&ci, &cit, 1); | |||||
clientpf.bufferFromBuffer((rdr::U8*)&cit, serverpf, (rdr::U8*)&ci, 1); | |||||
if (!palette.insert (cit, ni) || (palette.size() > palMaxColors)) | if (!palette.insert (cit, ni) || (palette.size() > palMaxColors)) | ||||
palette.clear(); | palette.clear(); | ||||
} | } | ||||
int w = r.width(), h = r.height(); | int w = r.width(), h = r.height(); | ||||
int stride = w; | int stride = w; | ||||
buf = (const PIXEL_T *)ig->getRawBufferR(r, &stride); | |||||
buf = (const PIXEL_T *)pb->getBuffer(r, &stride); | |||||
colorValue = *buf; | colorValue = *buf; | ||||
if (needSameColor && (rdr::U32)colorValue != *colorPtr) | if (needSameColor && (rdr::U32)colorValue != *colorPtr) |
void ZRLE_DECODE (const Rect& r, rdr::InStream* is, | void ZRLE_DECODE (const Rect& r, rdr::InStream* is, | ||||
rdr::ZlibInStream* zis, PIXEL_T* buf, | rdr::ZlibInStream* zis, PIXEL_T* buf, | ||||
CMsgHandler* handler) | |||||
const PixelFormat& pf, ModifiablePixelBuffer* pb) | |||||
{ | { | ||||
int length = is->readU32(); | int length = is->readU32(); | ||||
zis->setUnderlying(is, length); | zis->setUnderlying(is, length); | ||||
if (palSize == 1) { | if (palSize == 1) { | ||||
PIXEL_T pix = palette[0]; | PIXEL_T pix = palette[0]; | ||||
handler->fillRect(t, pix); | |||||
pb->fillRect(pf, t, pix); | |||||
continue; | continue; | ||||
} | } | ||||
//fprintf(stderr,"copying data to screen %dx%d at %d,%d\n", | //fprintf(stderr,"copying data to screen %dx%d at %d,%d\n", | ||||
//t.width(),t.height(),t.tl.x,t.tl.y); | //t.width(),t.height(),t.tl.x,t.tl.y); | ||||
handler->imageRect(t, buf); | |||||
pb->imageRect(pf, t, buf); | |||||
} | } | ||||
} | } | ||||
#include <rdr/OutStream.h> | #include <rdr/OutStream.h> | ||||
#include <rdr/ZlibOutStream.h> | #include <rdr/ZlibOutStream.h> | ||||
#include <rfb/Palette.h> | #include <rfb/Palette.h> | ||||
#include <rfb/PixelBuffer.h> | |||||
#include <assert.h> | #include <assert.h> | ||||
namespace rfb { | namespace rfb { | ||||
void ZRLE_ENCODE (const Rect& r, rdr::OutStream* os, | void ZRLE_ENCODE (const Rect& r, rdr::OutStream* os, | ||||
rdr::ZlibOutStream* zos, void* buf, | rdr::ZlibOutStream* zos, void* buf, | ||||
TransImageGetter *ig) | |||||
const PixelFormat& pf, PixelBuffer* pb) | |||||
{ | { | ||||
zos->setUnderlying(os); | zos->setUnderlying(os); | ||||
// RLE overhead is at worst 1 byte per 64x64 (4Kpixel) block | // RLE overhead is at worst 1 byte per 64x64 (4Kpixel) block | ||||
t.br.x = __rfbmin(r.br.x, t.tl.x + 64); | t.br.x = __rfbmin(r.br.x, t.tl.x + 64); | ||||
ig->getImage(buf, t); | |||||
pb->getImage(pf, buf, t); | |||||
ZRLE_ENCODE_TILE((PIXEL_T*)buf, t.width(), t.height(), zos); | ZRLE_ENCODE_TILE((PIXEL_T*)buf, t.width(), t.height(), zos); | ||||
} | } |
// This initial update request is a bit of a corner case, so we need | // This initial update request is a bit of a corner case, so we need | ||||
// to help out setting the correct format here. | // to help out setting the correct format here. | ||||
assert(pendingPFChange); | assert(pendingPFChange); | ||||
desktop->setServerPF(pendingPF); | |||||
cp.setPF(pendingPF); | cp.setPF(pendingPF); | ||||
pendingPFChange = false; | pendingPFChange = false; | ||||
} | } | ||||
// A format change has been scheduled and we are now past the update | // A format change has been scheduled and we are now past the update | ||||
// with the old format. Time to active the new one. | // with the old format. Time to active the new one. | ||||
if (pendingPFChange) { | if (pendingPFChange) { | ||||
desktop->setServerPF(pendingPF); | |||||
cp.setPF(pendingPF); | cp.setPF(pendingPF); | ||||
pendingPFChange = false; | pendingPFChange = false; | ||||
} | } | ||||
throw Exception("Unknown rect encoding"); | throw Exception("Unknown rect encoding"); | ||||
} | } | ||||
} | } | ||||
decoders[encoding]->readRect(r, this); | |||||
decoders[encoding]->readRect(r, desktop->getFramebuffer()); | |||||
sock->inStream().stopTiming(); | sock->inStream().stopTiming(); | ||||
} | } | ||||
void CConn::fillRect(const rfb::Rect& r, rfb::Pixel p) | |||||
{ | |||||
desktop->fillRect(r,p); | |||||
} | |||||
void CConn::imageRect(const rfb::Rect& r, void* p) | |||||
{ | |||||
desktop->imageRect(r,p); | |||||
} | |||||
void CConn::copyRect(const rfb::Rect& r, int sx, int sy) | |||||
{ | |||||
desktop->copyRect(r,sx,sy); | |||||
} | |||||
void CConn::setCursor(int width, int height, const Point& hotspot, | void CConn::setCursor(int width, int height, const Point& hotspot, | ||||
void* data, void* mask) | void* data, void* mask) | ||||
{ | { | ||||
pf.read(&memStream); | pf.read(&memStream); | ||||
desktop->setServerPF(pf); | |||||
cp.setPF(pf); | cp.setPF(pf); | ||||
} | } | ||||
} | } | ||||
rdr::U8* CConn::getRawBufferRW(const rfb::Rect& r, int* stride) { | |||||
return desktop->getBufferRW(r, stride); | |||||
} | |||||
void CConn::releaseRawBuffer(const rfb::Rect& r) { | |||||
desktop->commitBufferRW(r); | |||||
} | |||||
////////////////////// Internal methods ////////////////////// | ////////////////////// Internal methods ////////////////////// | ||||
void framebufferUpdateStart(); | void framebufferUpdateStart(); | ||||
void framebufferUpdateEnd(); | void framebufferUpdateEnd(); | ||||
void dataRect(const rfb::Rect& r, int encoding); | void dataRect(const rfb::Rect& r, int encoding); | ||||
void fillRect(const rfb::Rect& r, rfb::Pixel p); | |||||
void imageRect(const rfb::Rect& r, void* p); | |||||
void copyRect(const rfb::Rect& r, int sx, int sy); | |||||
rdr::U8* getRawBufferRW(const rfb::Rect& r, int* stride); | |||||
void releaseRawBuffer(const rfb::Rect& r); | |||||
const rfb::PixelFormat &getPreferredPF() { return fullColourPF; } | |||||
void setCursor(int width, int height, const rfb::Point& hotspot, | void setCursor(int width, int height, const rfb::Point& hotspot, | ||||
void* data, void* mask); | void* data, void* mask); | ||||
} | } | ||||
void DesktopWindow::setServerPF(const rfb::PixelFormat& pf) | |||||
{ | |||||
viewport->setServerPF(pf); | |||||
} | |||||
const rfb::PixelFormat &DesktopWindow::getPreferredPF() | const rfb::PixelFormat &DesktopWindow::getPreferredPF() | ||||
{ | { | ||||
return viewport->getPreferredPF(); | return viewport->getPreferredPF(); | ||||
} | } | ||||
void DesktopWindow::fillRect(const rfb::Rect& r, rfb::Pixel pix) { | |||||
viewport->fillRect(r, pix); | |||||
} | |||||
void DesktopWindow::imageRect(const rfb::Rect& r, void* pixels) { | |||||
viewport->imageRect(r, pixels); | |||||
} | |||||
void DesktopWindow::copyRect(const rfb::Rect& r, int srcX, int srcY) { | |||||
viewport->copyRect(r, srcX, srcY); | |||||
} | |||||
rdr::U8* DesktopWindow::getBufferRW(const rfb::Rect& r, int* stride) { | |||||
return viewport->getBufferRW(r, stride); | |||||
} | |||||
void DesktopWindow::commitBufferRW(const rfb::Rect& r) { | |||||
viewport->commitBufferRW(r); | |||||
rfb::ModifiablePixelBuffer* DesktopWindow::getFramebuffer(void) | |||||
{ | |||||
return viewport->getFramebuffer(); | |||||
} | } | ||||
#include <FL/Fl_Window.H> | #include <FL/Fl_Window.H> | ||||
namespace rfb { class ModifiablePixelBuffer; } | |||||
class CConn; | class CConn; | ||||
class Viewport; | class Viewport; | ||||
const rfb::PixelFormat& serverPF, CConn* cc_); | const rfb::PixelFormat& serverPF, CConn* cc_); | ||||
~DesktopWindow(); | ~DesktopWindow(); | ||||
// PixelFormat of incoming write operations | |||||
void setServerPF(const rfb::PixelFormat& pf); | |||||
// Most efficient format (from DesktopWindow's point of view) | // Most efficient format (from DesktopWindow's point of view) | ||||
const rfb::PixelFormat &getPreferredPF(); | const rfb::PixelFormat &getPreferredPF(); | ||||
// Flush updates to screen | // Flush updates to screen | ||||
void updateWindow(); | void updateWindow(); | ||||
// Methods forwarded from CConn | |||||
// Updated session title | |||||
void setName(const char *name); | void setName(const char *name); | ||||
void fillRect(const rfb::Rect& r, rfb::Pixel pix); | |||||
void imageRect(const rfb::Rect& r, void* pixels); | |||||
void copyRect(const rfb::Rect& r, int srcX, int srcY); | |||||
rdr::U8* getBufferRW(const rfb::Rect& r, int* stride); | |||||
void commitBufferRW(const rfb::Rect& r); | |||||
// Return a pointer to the framebuffer for decoders to write into | |||||
rfb::ModifiablePixelBuffer* getFramebuffer(void); | |||||
// Resize the current framebuffer, but retain the contents | |||||
void resizeFramebuffer(int new_w, int new_h); | void resizeFramebuffer(int new_w, int new_h); | ||||
// New image for the locally rendered cursor | |||||
void setCursor(int width, int height, const rfb::Point& hotspot, | void setCursor(int width, int height, const rfb::Point& hotspot, | ||||
void* data, void* mask); | void* data, void* mask); | ||||
FullFramePixelBuffer(pf, width, height, data, stride) | FullFramePixelBuffer(pf, width, height, data, stride) | ||||
{ | { | ||||
} | } | ||||
void PlatformPixelBuffer::commitBufferRW(const rfb::Rect& r) | |||||
{ | |||||
FullFramePixelBuffer::commitBufferRW(r); | |||||
damage.assign_union(rfb::Region(r)); | |||||
} | |||||
rfb::Rect PlatformPixelBuffer::getDamage(void) | |||||
{ | |||||
rfb::Rect r; | |||||
r = damage.get_bounding_rect(); | |||||
damage.clear(); | |||||
return r; | |||||
} |
#define __PLATFORMPIXELBUFFER_H__ | #define __PLATFORMPIXELBUFFER_H__ | ||||
#include <rfb/PixelBuffer.h> | #include <rfb/PixelBuffer.h> | ||||
#include <rfb/Region.h> | |||||
class PlatformPixelBuffer: public rfb::FullFramePixelBuffer { | class PlatformPixelBuffer: public rfb::FullFramePixelBuffer { | ||||
public: | public: | ||||
PlatformPixelBuffer(const rfb::PixelFormat& pf, int width, int height, | PlatformPixelBuffer(const rfb::PixelFormat& pf, int width, int height, | ||||
rdr::U8* data, int stride); | rdr::U8* data, int stride); | ||||
virtual void commitBufferRW(const rfb::Rect& r); | |||||
virtual void draw(int src_x, int src_y, int x, int y, int w, int h) = 0; | virtual void draw(int src_x, int src_y, int x, int y, int w, int h) = 0; | ||||
rfb::Rect getDamage(void); | |||||
protected: | |||||
rfb::Region damage; | |||||
}; | }; | ||||
#endif | #endif |
#include <rfb/CMsgWriter.h> | #include <rfb/CMsgWriter.h> | ||||
#include <rfb/LogWriter.h> | #include <rfb/LogWriter.h> | ||||
#include <rfb/PixelTransformer.h> | |||||
// FLTK can pull in the X11 headers on some systems | // FLTK can pull in the X11 headers on some systems | ||||
#ifndef XK_VoidSymbol | #ifndef XK_VoidSymbol | ||||
ID_REFRESH, ID_OPTIONS, ID_INFO, ID_ABOUT, ID_DISMISS }; | ID_REFRESH, ID_OPTIONS, ID_INFO, ID_ABOUT, ID_DISMISS }; | ||||
Viewport::Viewport(int w, int h, const rfb::PixelFormat& serverPF, CConn* cc_) | Viewport::Viewport(int w, int h, const rfb::PixelFormat& serverPF, CConn* cc_) | ||||
: Fl_Widget(0, 0, w, h), cc(cc_), frameBuffer(NULL), pixelTrans(NULL), | |||||
: Fl_Widget(0, 0, w, h), cc(cc_), frameBuffer(NULL), | |||||
lastPointerPos(0, 0), lastButtonMask(0), | lastPointerPos(0, 0), lastButtonMask(0), | ||||
cursor(NULL), menuCtrlKey(false), menuAltKey(false) | cursor(NULL), menuCtrlKey(false), menuAltKey(false) | ||||
{ | { | ||||
frameBuffer = createFramebuffer(w, h); | frameBuffer = createFramebuffer(w, h); | ||||
assert(frameBuffer); | assert(frameBuffer); | ||||
setServerPF(serverPF); | |||||
contextMenu = new Fl_Menu_Button(0, 0, 0, 0); | contextMenu = new Fl_Menu_Button(0, 0, 0, 0); | ||||
// Setting box type to FL_NO_BOX prevents it from trying to draw the | // Setting box type to FL_NO_BOX prevents it from trying to draw the | ||||
// button component (which we don't want) | // button component (which we don't want) | ||||
{ | { | ||||
// Unregister all timeouts in case they get a change tro trigger | // Unregister all timeouts in case they get a change tro trigger | ||||
// again later when this object is already gone. | // again later when this object is already gone. | ||||
Fl::remove_timeout(handleUpdateTimeout, this); | |||||
Fl::remove_timeout(handlePointerTimeout, this); | Fl::remove_timeout(handlePointerTimeout, this); | ||||
#ifdef HAVE_FLTK_CLIPBOARD | #ifdef HAVE_FLTK_CLIPBOARD | ||||
delete frameBuffer; | delete frameBuffer; | ||||
if (pixelTrans) | |||||
delete pixelTrans; | |||||
if (cursor) { | if (cursor) { | ||||
if (!cursor->alloc_array) | if (!cursor->alloc_array) | ||||
delete [] cursor->array; | delete [] cursor->array; | ||||
} | } | ||||
void Viewport::setServerPF(const rfb::PixelFormat& pf) | |||||
{ | |||||
if (pixelTrans) | |||||
delete pixelTrans; | |||||
pixelTrans = NULL; | |||||
if (pf.equal(getPreferredPF())) | |||||
return; | |||||
pixelTrans = new PixelTransformer(); | |||||
// FIXME: This is an ugly (temporary) hack to get around a corner | |||||
// case during startup. The conversion routines cannot handle | |||||
// non-native source formats, and we can sometimes get that | |||||
// as the initial format. We will switch to a better format | |||||
// before getting any updates, but we need something for now. | |||||
// Our old client used something completely bogus and just | |||||
// hoped nothing would ever go wrong. We try to at least match | |||||
// the pixel size so that we don't get any memory access issues | |||||
// should a stray update appear. | |||||
static rdr::U32 endianTest = 1; | |||||
static bool nativeBigEndian = *(rdr::U8*)(&endianTest) != 1; | |||||
if ((pf.bpp > 8) && (pf.bigEndian != nativeBigEndian)) { | |||||
PixelFormat fake_pf(pf.bpp, pf.depth, nativeBigEndian, pf.trueColour, | |||||
pf.redMax, pf.greenMax, pf.blueMax, | |||||
pf.redShift, pf.greenShift, pf.blueShift); | |||||
pixelTrans->init(fake_pf, getPreferredPF()); | |||||
return; | |||||
} | |||||
pixelTrans->init(pf, getPreferredPF()); | |||||
} | |||||
const rfb::PixelFormat &Viewport::getPreferredPF() | const rfb::PixelFormat &Viewport::getPreferredPF() | ||||
{ | { | ||||
return frameBuffer->getPF(); | return frameBuffer->getPF(); | ||||
// Copy the areas of the framebuffer that have been changed (damaged) | // Copy the areas of the framebuffer that have been changed (damaged) | ||||
// to the displayed window. | // to the displayed window. | ||||
// FIXME: Make sure this gets called on slow updates | |||||
void Viewport::updateWindow() | void Viewport::updateWindow() | ||||
{ | { | ||||
Rect r; | Rect r; | ||||
Fl::remove_timeout(handleUpdateTimeout, this); | |||||
r = damage.get_bounding_rect(); | |||||
Fl_Widget::damage(FL_DAMAGE_USER1, r.tl.x + x(), r.tl.y + y(), r.width(), r.height()); | |||||
damage.clear(); | |||||
} | |||||
void Viewport::fillRect(const rfb::Rect& r, rfb::Pixel pix) { | |||||
if (pixelTrans) { | |||||
rfb::Pixel pix2; | |||||
pixelTrans->translatePixels(&pix, &pix2, 1); | |||||
pix = pix2; | |||||
} | |||||
frameBuffer->fillRect(r, pix); | |||||
damageRect(r); | |||||
r = frameBuffer->getDamage(); | |||||
damage(FL_DAMAGE_USER1, r.tl.x + x(), r.tl.y + y(), r.width(), r.height()); | |||||
} | } | ||||
void Viewport::imageRect(const rfb::Rect& r, void* pixels) { | |||||
if (pixelTrans) { | |||||
rdr::U8* buffer; | |||||
int stride; | |||||
buffer = frameBuffer->getBufferRW(r, &stride); | |||||
pixelTrans->translateRect(pixels, r.width(), | |||||
rfb::Rect(0, 0, r.width(), r.height()), | |||||
buffer, stride, rfb::Point(0, 0)); | |||||
frameBuffer->commitBufferRW(r); | |||||
} else { | |||||
frameBuffer->imageRect(r, pixels); | |||||
} | |||||
damageRect(r); | |||||
} | |||||
void Viewport::copyRect(const rfb::Rect& r, int srcX, int srcY) { | |||||
frameBuffer->copyRect(r, rfb::Point(r.tl.x-srcX, r.tl.y-srcY)); | |||||
damageRect(r); | |||||
} | |||||
rdr::U8* Viewport::getBufferRW(const rfb::Rect& r, int* stride) { | |||||
return frameBuffer->getBufferRW(r, stride); | |||||
} | |||||
void Viewport::commitBufferRW(const rfb::Rect& r) { | |||||
frameBuffer->commitBufferRW(r); | |||||
damageRect(r); | |||||
rfb::ModifiablePixelBuffer* Viewport::getFramebuffer(void) | |||||
{ | |||||
return frameBuffer; | |||||
} | } | ||||
void Viewport::damageRect(const rfb::Rect& r) { | |||||
damage.assign_union(rfb::Region(r)); | |||||
if (!Fl::has_timeout(handleUpdateTimeout, this)) | |||||
Fl::add_timeout(0.500, handleUpdateTimeout, this); | |||||
}; | |||||
#ifdef HAVE_FLTK_CURSOR | #ifdef HAVE_FLTK_CURSOR | ||||
static const char * dotcursor_xpm[] = { | static const char * dotcursor_xpm[] = { | ||||
"5 5 2 1", | "5 5 2 1", | ||||
const PixelFormat *pf; | const PixelFormat *pf; | ||||
if (pixelTrans) | |||||
pf = &pixelTrans->getInPF(); | |||||
else | |||||
pf = &frameBuffer->getPF(); | |||||
pf = &cc->cp.pf(); | |||||
i = (U8*)data; | i = (U8*)data; | ||||
o = buffer; | o = buffer; | ||||
} | } | ||||
void Viewport::handleUpdateTimeout(void *data) | |||||
{ | |||||
Viewport *self = (Viewport *)data; | |||||
assert(self); | |||||
self->updateWindow(); | |||||
} | |||||
void Viewport::handleClipboardChange(int source, void *data) | void Viewport::handleClipboardChange(int source, void *data) | ||||
{ | { | ||||
Viewport *self = (Viewport *)data; | Viewport *self = (Viewport *)data; |
#include <map> | #include <map> | ||||
#include <FL/Fl_Widget.H> | |||||
namespace rfb { class ModifiablePixelBuffer; } | |||||
#include <rfb/Region.h> | |||||
#include <rfb/Pixel.h> | |||||
#include <FL/Fl_Widget.H> | |||||
class Fl_Menu_Button; | class Fl_Menu_Button; | ||||
class Fl_RGB_Image; | class Fl_RGB_Image; | ||||
Viewport(int w, int h, const rfb::PixelFormat& serverPF, CConn* cc_); | Viewport(int w, int h, const rfb::PixelFormat& serverPF, CConn* cc_); | ||||
~Viewport(); | ~Viewport(); | ||||
// PixelFormat of incoming write operations | |||||
void setServerPF(const rfb::PixelFormat& pf); | |||||
// Most efficient format (from Viewport's point of view) | // Most efficient format (from Viewport's point of view) | ||||
const rfb::PixelFormat &getPreferredPF(); | const rfb::PixelFormat &getPreferredPF(); | ||||
// Flush updates to screen | // Flush updates to screen | ||||
void updateWindow(); | void updateWindow(); | ||||
// Methods forwarded from CConn | |||||
void fillRect(const rfb::Rect& r, rfb::Pixel pix); | |||||
void imageRect(const rfb::Rect& r, void* pixels); | |||||
void copyRect(const rfb::Rect& r, int srcX, int srcY); | |||||
rdr::U8* getBufferRW(const rfb::Rect& r, int* stride); | |||||
void commitBufferRW(const rfb::Rect& r); | |||||
// Return a pointer to the framebuffer for decoders to write into | |||||
rfb::ModifiablePixelBuffer* getFramebuffer(void); | |||||
// New image for the locally rendered cursor | |||||
void setCursor(int width, int height, const rfb::Point& hotspot, | void setCursor(int width, int height, const rfb::Point& hotspot, | ||||
void* data, void* mask); | void* data, void* mask); | ||||
private: | private: | ||||
void damageRect(const rfb::Rect& r); | |||||
PlatformPixelBuffer* createFramebuffer(int w, int h); | PlatformPixelBuffer* createFramebuffer(int w, int h); | ||||
static void handleUpdateTimeout(void *data); | |||||
static void handleClipboardChange(int source, void *data); | static void handleClipboardChange(int source, void *data); | ||||
void handlePointerEvent(const rfb::Point& pos, int buttonMask); | void handlePointerEvent(const rfb::Point& pos, int buttonMask); | ||||
CConn* cc; | CConn* cc; | ||||
PlatformPixelBuffer* frameBuffer; | PlatformPixelBuffer* frameBuffer; | ||||
rfb::PixelTransformer *pixelTrans; | |||||
rfb::Region damage; | |||||
rfb::Point lastPointerPos; | rfb::Point lastPointerPos; | ||||
int lastButtonMask; | int lastButtonMask; |