updating the desktop name on the fly. Tested in ThinLinc since 2008-01-07. git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@3549 3789f03b-4d11-0410-bbf8-ca57d06f2519tags/v0.0.90
handler->setCursor(width, height, hotspot, data.buf, mask.buf); | handler->setCursor(width, height, hotspot, data.buf, mask.buf); | ||||
} | } | ||||
void CMsgReader::readSetDesktopName(int x, int y, int w, int h) | |||||
{ | |||||
char* name = is->readString(); | |||||
if (x || y || w || h) { | |||||
fprintf(stderr, "Ignoring DesktopName rect with non-zero position/size\n"); | |||||
} else { | |||||
handler->setName(name); | |||||
} | |||||
delete [] name; | |||||
} | |||||
rdr::U8* CMsgReader::getImageBuf(int required, int requested, int* nPixels) | rdr::U8* CMsgReader::getImageBuf(int required, int requested, int* nPixels) | ||||
{ | { | ||||
int requiredBytes = required * (handler->cp.pf().bpp / 8); | int requiredBytes = required * (handler->cp.pf().bpp / 8); |
virtual void readCopyRect(const Rect& r); | virtual void readCopyRect(const Rect& r); | ||||
virtual void readSetCursor(int width, int height, const Point& hotspot); | virtual void readSetCursor(int width, int height, const Point& hotspot); | ||||
virtual void readSetDesktopName(int x, int y, int w, int h); | |||||
CMsgReader(CMsgHandler* handler, rdr::InStream* is); | CMsgReader(CMsgHandler* handler, rdr::InStream* is); | ||||
case pseudoEncodingDesktopSize: | case pseudoEncodingDesktopSize: | ||||
handler->setDesktopSize(w, h); | handler->setDesktopSize(w, h); | ||||
break; | break; | ||||
case pseudoEncodingDesktopName: | |||||
readSetDesktopName(x, y, w, h); | |||||
break; | |||||
case pseudoEncodingCursor: | case pseudoEncodingCursor: | ||||
readSetCursor(w, h, Point(x,y)); | readSetCursor(w, h, Point(x,y)); | ||||
break; | break; |
encodings[nEncodings++] = pseudoEncodingCursor; | encodings[nEncodings++] = pseudoEncodingCursor; | ||||
if (cp->supportsDesktopResize) | if (cp->supportsDesktopResize) | ||||
encodings[nEncodings++] = pseudoEncodingDesktopSize; | encodings[nEncodings++] = pseudoEncodingDesktopSize; | ||||
if (cp->supportsDesktopRename) | |||||
encodings[nEncodings++] = pseudoEncodingDesktopName; | |||||
if (Decoder::supported(preferredEncoding)) { | if (Decoder::supported(preferredEncoding)) { | ||||
encodings[nEncodings++] = preferredEncoding; | encodings[nEncodings++] = preferredEncoding; | ||||
} | } |
ConnParams::ConnParams() | ConnParams::ConnParams() | ||||
: majorVersion(0), minorVersion(0), tightExtensionsEnabled(false), | : majorVersion(0), minorVersion(0), tightExtensionsEnabled(false), | ||||
width(0), height(0), useCopyRect(false), | width(0), height(0), useCopyRect(false), | ||||
supportsLocalCursor(false), supportsLocalXCursor(false), supportsDesktopResize(true), | |||||
supportsLocalCursor(false), supportsLocalXCursor(false), supportsDesktopResize(true), supportsDesktopRename(false), | |||||
supportsLastRect(false), customCompressLevel(false), compressLevel(6), | supportsLastRect(false), customCompressLevel(false), compressLevel(6), | ||||
noJpeg(false), qualityLevel(-1), | noJpeg(false), qualityLevel(-1), | ||||
name_(0), nEncodings_(0), encodings_(0), | name_(0), nEncodings_(0), encodings_(0), | ||||
supportsLocalXCursor = true; | supportsLocalXCursor = true; | ||||
else if (encodings[i] == pseudoEncodingDesktopSize) | else if (encodings[i] == pseudoEncodingDesktopSize) | ||||
supportsDesktopResize = true; | supportsDesktopResize = true; | ||||
else if (encodings[i] == pseudoEncodingDesktopName) | |||||
supportsDesktopRename = true; | |||||
else if (encodings[i] == pseudoEncodingLastRect) | else if (encodings[i] == pseudoEncodingLastRect) | ||||
supportsLastRect = true; | supportsLastRect = true; | ||||
else if (encodings[i] >= pseudoEncodingCompressLevel0 && | else if (encodings[i] >= pseudoEncodingCompressLevel0 && |
bool supportsLocalCursor; | bool supportsLocalCursor; | ||||
bool supportsLocalXCursor; | bool supportsLocalXCursor; | ||||
bool supportsDesktopResize; | bool supportsDesktopResize; | ||||
bool supportsDesktopRename; | |||||
bool supportsLastRect; | bool supportsLastRect; | ||||
bool customCompressLevel; | bool customCompressLevel; |
// but will write the relevant pseudo-rectangle as part of the next update. | // but will write the relevant pseudo-rectangle as part of the next update. | ||||
virtual bool writeSetDesktopSize()=0; | virtual bool writeSetDesktopSize()=0; | ||||
virtual bool writeSetDesktopName()=0; | |||||
// Like setDesktopSize, we can't just write out a setCursor message | // Like setDesktopSize, we can't just write out a setCursor message | ||||
// immediately on a V3 writer. Instead of calling writeSetCursor() | // immediately on a V3 writer. Instead of calling writeSetCursor() | ||||
// directly, you must call cursorChange(), and then invoke writeSetCursor() | // directly, you must call cursorChange(), and then invoke writeSetCursor() |
SMsgWriterV3::SMsgWriterV3(ConnParams* cp, rdr::OutStream* os) | SMsgWriterV3::SMsgWriterV3(ConnParams* cp, rdr::OutStream* os) | ||||
: SMsgWriter(cp, os), updateOS(0), realOS(os), nRectsInUpdate(0), | : SMsgWriter(cp, os), updateOS(0), realOS(os), nRectsInUpdate(0), | ||||
nRectsInHeader(0), wsccb(0), | nRectsInHeader(0), wsccb(0), | ||||
needSetDesktopSize(false) | |||||
needSetDesktopSize(false), needSetDesktopName(false) | |||||
{ | { | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool SMsgWriterV3::writeSetDesktopName() { | |||||
if (!cp->supportsDesktopRename) return false; | |||||
needSetDesktopName = true; | |||||
return true; | |||||
} | |||||
void SMsgWriterV3::cursorChange(WriteSetCursorCallback* cb) | void SMsgWriterV3::cursorChange(WriteSetCursorCallback* cb) | ||||
{ | { | ||||
wsccb = cb; | wsccb = cb; | ||||
os->pad(1); | os->pad(1); | ||||
if (wsccb) nRects++; | if (wsccb) nRects++; | ||||
if (needSetDesktopSize) nRects++; | if (needSetDesktopSize) nRects++; | ||||
if (needSetDesktopName) nRects++; | |||||
os->writeU16(nRects); | os->writeU16(nRects); | ||||
nRectsInUpdate = 0; | nRectsInUpdate = 0; | ||||
nRectsInHeader = nRects; | nRectsInHeader = nRects; | ||||
needSetDesktopSize = false; | needSetDesktopSize = false; | ||||
} | } | ||||
if (needSetDesktopName) { | |||||
if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) | |||||
throw Exception("SMsgWriterV3 setDesktopName: nRects out of sync"); | |||||
os->writeS16(0); | |||||
os->writeS16(0); | |||||
os->writeU16(0); | |||||
os->writeU16(0); | |||||
os->writeU32(pseudoEncodingDesktopName); | |||||
os->writeString(cp->name()); | |||||
needSetDesktopName = false; | |||||
} | |||||
if (nRectsInUpdate != nRectsInHeader && nRectsInHeader) | if (nRectsInUpdate != nRectsInHeader && nRectsInHeader) | ||||
throw Exception("SMsgWriterV3::writeFramebufferUpdateEnd: " | throw Exception("SMsgWriterV3::writeFramebufferUpdateEnd: " | ||||
"nRects out of sync"); | "nRects out of sync"); | ||||
bool SMsgWriterV3::needFakeUpdate() | bool SMsgWriterV3::needFakeUpdate() | ||||
{ | { | ||||
return wsccb || needSetDesktopSize; | |||||
return wsccb || needSetDesktopSize || needSetDesktopName; | |||||
} | } | ||||
void SMsgWriterV3::startRect(const Rect& r, unsigned int encoding) | void SMsgWriterV3::startRect(const Rect& r, unsigned int encoding) |
virtual void startMsg(int type); | virtual void startMsg(int type); | ||||
virtual void endMsg(); | virtual void endMsg(); | ||||
virtual bool writeSetDesktopSize(); | virtual bool writeSetDesktopSize(); | ||||
virtual bool writeSetDesktopName(); | |||||
virtual void cursorChange(WriteSetCursorCallback* cb); | virtual void cursorChange(WriteSetCursorCallback* cb); | ||||
virtual void writeSetCursor(int width, int height, const Point& hotspot, | virtual void writeSetCursor(int width, int height, const Point& hotspot, | ||||
void* data, void* mask); | void* data, void* mask); | ||||
int nRectsInHeader; | int nRectsInHeader; | ||||
WriteSetCursorCallback* wsccb; | WriteSetCursorCallback* wsccb; | ||||
bool needSetDesktopSize; | bool needSetDesktopSize; | ||||
bool needSetDesktopName; | |||||
bool needLastRect; | bool needLastRect; | ||||
}; | }; | ||||
} | } |
} | } | ||||
} | } | ||||
void VNCSConnectionST::setDesktopName(const char *name) | |||||
{ | |||||
cp.setName(name); | |||||
try { | |||||
if (state() == RFBSTATE_NORMAL) { | |||||
if (!writer()->writeSetDesktopName()) { | |||||
fprintf(stderr, "Client does not support desktop rename\n"); | |||||
} | |||||
} | |||||
} catch(rdr::Exception& e) { | |||||
close(e.str()); | |||||
} | |||||
} | |||||
void VNCSConnectionST::setCursorOrClose() | void VNCSConnectionST::setCursorOrClose() | ||||
{ | { | ||||
try { | try { |
void setColourMapEntriesOrClose(int firstColour, int nColours); | void setColourMapEntriesOrClose(int firstColour, int nColours); | ||||
void bell(); | void bell(); | ||||
void serverCutText(const char *str, int len); | void serverCutText(const char *str, int len); | ||||
void setDesktopName(const char *name); | |||||
void setCursorOrClose(); | void setCursorOrClose(); | ||||
// checkIdleTimeout() returns the number of milliseconds left until the | // checkIdleTimeout() returns the number of milliseconds left until the |
} | } | ||||
} | } | ||||
void VNCServerST::setName(const char* name_) | |||||
{ | |||||
name.replaceBuf(strDup(name_)); | |||||
std::list<VNCSConnectionST*>::iterator ci, ci_next; | |||||
for (ci = clients.begin(); ci != clients.end(); ci = ci_next) { | |||||
ci_next = ci; ci_next++; | |||||
(*ci)->setDesktopName(name_); | |||||
} | |||||
} | |||||
void VNCServerST::add_changed(const Region& region) | void VNCServerST::add_changed(const Region& region) | ||||
{ | { | ||||
if (comparer != 0) { | if (comparer != 0) { |
// setName() specifies the desktop name that the server should provide to | // setName() specifies the desktop name that the server should provide to | ||||
// clients | // clients | ||||
void setName(const char* name_) {name.replaceBuf(strDup(name_));} | |||||
virtual void setName(const char* name_); | |||||
// A QueryConnectionHandler, if supplied, is passed details of incoming | // A QueryConnectionHandler, if supplied, is passed details of incoming | ||||
// connections to approve, reject, or query the user about. | // connections to approve, reject, or query the user about. |
const unsigned int pseudoEncodingXCursor = 0xffffff10; | const unsigned int pseudoEncodingXCursor = 0xffffff10; | ||||
const unsigned int pseudoEncodingCursor = 0xffffff11; | const unsigned int pseudoEncodingCursor = 0xffffff11; | ||||
const unsigned int pseudoEncodingDesktopSize = 0xffffff21; | const unsigned int pseudoEncodingDesktopSize = 0xffffff21; | ||||
const unsigned int pseudoEncodingDesktopName = 0xfffffecdl; | |||||
// TightVNC-specific | // TightVNC-specific | ||||
const unsigned int pseudoEncodingLastRect = 0xFFFFFF20; | const unsigned int pseudoEncodingLastRect = 0xFFFFFF20; |
addEventMask(StructureNotifyMask); | addEventMask(StructureNotifyMask); | ||||
} | } | ||||
void TXWindow::setName(const char* name) | |||||
{ | |||||
XStoreName(dpy, win(), name); | |||||
} | |||||
void TXWindow::setMaxSize(int w, int h) | void TXWindow::setMaxSize(int w, int h) | ||||
{ | { | ||||
sizeHints.flags |= PMaxSize; | sizeHints.flags |= PMaxSize; |
void setGeometry(const char* geom, int x, int y, int w, int h); | void setGeometry(const char* geom, int x, int y, int w, int h); | ||||
void setName(const char* name); | |||||
// setTransientFor() tells the window manager that this window is "owned" by | // setTransientFor() tells the window manager that this window is "owned" by | ||||
// the given window. The window manager can use this information as it sees | // the given window. The window manager can use this information as it sees | ||||
// fit. | // fit. |
currentEncoding = encNum; | currentEncoding = encNum; | ||||
} | } | ||||
cp.supportsDesktopResize = true; | cp.supportsDesktopResize = true; | ||||
cp.supportsDesktopRename = true; | |||||
cp.supportsLocalCursor = useLocalCursor; | cp.supportsLocalCursor = useLocalCursor; | ||||
cp.customCompressLevel = customCompressLevel; | cp.customCompressLevel = customCompressLevel; | ||||
cp.compressLevel = compressLevel; | cp.compressLevel = compressLevel; | ||||
} | } | ||||
} | } | ||||
// setName() is called when the desktop name changes | |||||
void CConn::setName(const char* name) { | |||||
CConnection::setName(name); | |||||
if (viewport) { | |||||
viewport->setName(name); | |||||
} | |||||
} | |||||
// framebufferUpdateEnd() is called at the end of an update. | // framebufferUpdateEnd() is called at the end of an update. | ||||
// For each rectangle, the FdInStream will have timed the speed | // For each rectangle, the FdInStream will have timed the speed | ||||
// of the connection, allowing us to select format and encoding | // of the connection, allowing us to select format and encoding |
rfb::CSecurity* getCSecurity(int secType); | rfb::CSecurity* getCSecurity(int secType); | ||||
void serverInit(); | void serverInit(); | ||||
void setDesktopSize(int w, int h); | void setDesktopSize(int w, int h); | ||||
void setName(const char* name); | |||||
void setColourMapEntries(int firstColour, int nColours, rdr::U16* rgbs); | void setColourMapEntries(int firstColour, int nColours, rdr::U16* rgbs); | ||||
void bell(); | void bell(); | ||||
void serverCutText(const char* str, int len); | void serverCutText(const char* str, int len); |
} | } | ||||
} | } | ||||
void XserverDesktop::setDesktopName(const char* name) | |||||
{ | |||||
try { | |||||
server->setName(name); | |||||
} catch (rdr::Exception& e) { | |||||
vlog.error("XserverDesktop::setDesktopName: %s",e.str()); | |||||
} | |||||
} | |||||
void XserverDesktop::setCursor(CursorPtr cursor) | void XserverDesktop::setCursor(CursorPtr cursor) | ||||
{ | { | ||||
try { | try { |
void setColourMapEntries(ColormapPtr pColormap, int ndef, xColorItem* pdef); | void setColourMapEntries(ColormapPtr pColormap, int ndef, xColorItem* pdef); | ||||
void bell(); | void bell(); | ||||
void serverCutText(const char* str, int len); | void serverCutText(const char* str, int len); | ||||
void setDesktopName(const char* name); | |||||
void setCursor(CursorPtr cursor); | void setCursor(CursorPtr cursor); | ||||
void add_changed(RegionPtr reg); | void add_changed(RegionPtr reg); | ||||
void add_copied(RegionPtr dst, int dx, int dy); | void add_copied(RegionPtr dst, int dx, int dy); |
rep.type = X_Reply; | rep.type = X_Reply; | ||||
rep.length = 0; | rep.length = 0; | ||||
rep.sequenceNumber = client->sequence; | rep.sequenceNumber = client->sequence; | ||||
// Retrieve desktop name before setting | |||||
char* value1 = 0; | |||||
rfb::VoidParameter* desktop1 = rfb::Configuration::getParam("desktop"); | |||||
if (desktop1) | |||||
value1 = desktop1->getValueStr(); | |||||
rep.success = rfb::Configuration::setParam(param.buf); | rep.success = rfb::Configuration::setParam(param.buf); | ||||
// Send DesktopName update if desktop name has been changed | |||||
char* value2 = 0; | |||||
rfb::VoidParameter* desktop2 = rfb::Configuration::getParam("desktop"); | |||||
if (desktop2) | |||||
value2 = desktop2->getValueStr(); | |||||
if (value1 && value2 && strcmp(value1, value2)) { | |||||
for (int scr = 0; scr < screenInfo.numScreens; scr++) { | |||||
if (desktop[scr]) { | |||||
desktop[scr]->setDesktopName(value2); | |||||
} | |||||
} | |||||
} | |||||
if (value1) | |||||
delete [] value1; | |||||
if (value2) | |||||
delete [] value2; | |||||
if (client->swapped) { | if (client->swapped) { | ||||
swaps(&rep.sequenceNumber, n); | swaps(&rep.sequenceNumber, n); | ||||
swapl(&rep.length, n); | swapl(&rep.length, n); |
// - Set optional features in ConnParams | // - Set optional features in ConnParams | ||||
cp.supportsLocalCursor = options.useLocalCursor; | cp.supportsLocalCursor = options.useLocalCursor; | ||||
cp.supportsDesktopResize = options.useDesktopResize; | cp.supportsDesktopResize = options.useDesktopResize; | ||||
cp.supportsDesktopRename = true; | |||||
cp.customCompressLevel = options.customCompressLevel; | cp.customCompressLevel = options.customCompressLevel; | ||||
cp.compressLevel = options.compressLevel; | cp.compressLevel = options.compressLevel; | ||||
cp.noJpeg = options.noJpeg; | cp.noJpeg = options.noJpeg; |