diff --git a/TODO b/TODO index 9d2f614..1258e59 100644 --- a/TODO +++ b/TODO @@ -2,7 +2,6 @@ For 3.2: - write SLP service template for remote desktop protocols (documentation) -- extend VNC to enable/disable desktop wallpaper - enhance RFB with SASL authentication (Kerberos) - encrypted connections (using SASL and/or SSL/TLS) - with kerberos/ssl: display name of remote user in connection dialog, diff --git a/krfb/rfbcontroller.cc b/krfb/rfbcontroller.cc index b3093a3..e47bcc8 100644 --- a/krfb/rfbcontroller.cc +++ b/krfb/rfbcontroller.cc @@ -151,6 +151,11 @@ static void clientGoneHook(rfbClientPtr) self->handleClientGone(); } +static void negotiationFinishedHook(rfbClientPtr cl) +{ + self->handleNegotiationFinished(cl); +} + void ConnectionDialog::closeEvent(QCloseEvent *) @@ -311,6 +316,8 @@ void SessionEstablishedEvent::exec() { RFBController::RFBController(Configuration *c) : allowDesktopControl(false), configuration(c), + disableBackgroundPending(false), + disableBackgroundState(false), closePending(false), forcedClose(false) { @@ -370,9 +377,9 @@ void RFBController::startServer(int inetdFd, bool xtestGrab) if ( server->rfbServerFormat.bitsPerPixel == 8 ) { server->rfbServerFormat.redShift = 0; - server->rfbServerFormat.greenShift = 2; - server->rfbServerFormat.blueShift = 5; - server->rfbServerFormat.redMax = 3; + server->rfbServerFormat.greenShift = 3; + server->rfbServerFormat.blueShift = 6; + server->rfbServerFormat.redMax = 7; server->rfbServerFormat.greenMax = 7; server->rfbServerFormat.blueMax = 3; } else { @@ -485,6 +492,7 @@ void RFBController::refuseConnection() bool RFBController::checkAsyncEvents() { bool closed = false; + bool backgroundActionRequired = false; asyncMutex.lock(); VNCEvent *e; for (e = asyncQueue.first(); e; e = asyncQueue.next()) @@ -495,17 +503,25 @@ bool RFBController::checkAsyncEvents() closed = true; closePending = false; } + if (disableBackgroundPending != disableBackgroundState) + backgroundActionRequired = true; asyncMutex.unlock(); + + if (backgroundActionRequired && (!closed) && !configuration->disableBackground()) + disableBackground(disableBackgroundPending); + return closed; } -void RFBController::restoreBackground() { - if (configuration->disableBackground()) { - DCOPRef ref("kdesktop", "KBackgroundIface"); - ref.setDCOPClient(KApplication::dcopClient()); +void RFBController::disableBackground(bool state) { + if (disableBackgroundState == state) + return; - ref.send("setBackgroundEnabled(bool)", bool(true)); - } + disableBackgroundState = state; + DCOPRef ref("kdesktop", "KBackgroundIface"); + ref.setDCOPClient(KApplication::dcopClient()); + + ref.send("setBackgroundEnabled(bool)", bool(!state)); } void RFBController::connectionClosed() @@ -515,7 +531,7 @@ void RFBController::connectionClosed() .arg(remoteIp)); idleTimer.stop(); - restoreBackground(); + disableBackground(false); state = RFB_WAITING; if (forcedClose) emit quitApp(); @@ -527,7 +543,7 @@ void RFBController::closeConnection() { forcedClose = true; if (state == RFB_CONNECTED) { - restoreBackground(); + disableBackground(false); if (!checkAsyncEvents()) { asyncMutex.lock(); @@ -571,7 +587,7 @@ void RFBController::idleSlot() defaultPtrAddEvent(0, p.x(),p.y(), server->rfbClientHead); asyncMutex.unlock(); - checkAsyncEvents(); + checkAsyncEvents(); // check 2nd time (see 3rd line) } void RFBController::dialogAccepted() @@ -657,6 +673,7 @@ bool RFBController::handleCheckPassword(rfbClientPtr cl, enum rfbNewClientAction RFBController::handleNewClient(rfbClientPtr cl) { int socket = cl->sock; + cl->negotiationFinishedHook = negotiationFinishedHook; QString host, port; KSocketAddress *ksa = KExtendedSocket::peerAddress(socket); @@ -712,6 +729,13 @@ void RFBController::handleClientGone() asyncMutex.unlock(); } +void RFBController::handleNegotiationFinished(rfbClientPtr cl) +{ + asyncMutex.lock(); + disableBackgroundPending = cl->disableBackground; + asyncMutex.unlock(); +} + void RFBController::handleKeyEvent(bool down, KeySym keySym) { if (!allowDesktopControl) return; @@ -747,12 +771,8 @@ void RFBController::sendKNotifyEvent(const QString &n, const QString &d) void RFBController::sendSessionEstablished() { - if (configuration->disableBackground()) { - DCOPRef ref("kdesktop", "KBackgroundIface"); - ref.setDCOPClient(KApplication::dcopClient()); - - ref.send("setBackgroundEnabled(bool)", bool(false)); - } + if (configuration->disableBackground()) + disableBackground(true); emit sessionEstablished(remoteIp); } diff --git a/krfb/rfbcontroller.h b/krfb/rfbcontroller.h index 50fcc89..a4b9830 100644 --- a/krfb/rfbcontroller.h +++ b/krfb/rfbcontroller.h @@ -138,6 +138,7 @@ public: void handlePointerEvent(int button_mask, int x, int y); enum rfbNewClientAction handleNewClient(rfbClientPtr cl); void handleClientGone(); + void handleNegotiationFinished(rfbClientPtr cl); int getPort(); void startServer(int inetdFd = -1, bool xtestGrab = true); @@ -160,7 +161,7 @@ private: void sendKNotifyEvent(const QString &name, const QString &desc); bool checkAsyncEvents(); void sendSessionEstablished(); - void restoreBackground(); + void disableBackground(bool state); QString remoteIp; bool allowDesktopControl; @@ -179,6 +180,8 @@ private: QMutex asyncMutex; QPtrList asyncQueue; + bool disableBackgroundPending; // background, as desired by libvncserver + bool disableBackgroundState; // real background state bool closePending; // set when libvncserver detected close bool forcedClose; // set when user closed connection private slots: diff --git a/libvncserver/rfb.h b/libvncserver/rfb.h index 03131ff..90e66f8 100644 --- a/libvncserver/rfb.h +++ b/libvncserver/rfb.h @@ -391,6 +391,7 @@ typedef struct sraRegion* sraRegionPtr; */ typedef void (*ClientGoneHookPtr)(struct _rfbClientRec* cl); +typedef void (*NegotiationFinishedHookPtr)(struct _rfbClientRec* cl); typedef struct _rfbClientRec { @@ -404,8 +405,12 @@ typedef struct _rfbClientRec { * This is useful if the IO functions have to behave client specific. */ void* clientData; + ClientGoneHookPtr clientGoneHook; + /* negotiationFinishedHook is called when the negotiation phase has ended */ + NegotiationFinishedHookPtr negotiationFinishedHook; + SOCKET sock; char *host; @@ -526,6 +531,7 @@ typedef struct _rfbClientRec { Bool enableLastRectEncoding; /* client supports LastRect encoding */ Bool enableSoftCursorUpdates; /* client supports softcursor updates */ + Bool disableBackground; /* client wants to disable background */ Bool enableCursorShapeUpdates; /* client supports cursor shape updates */ Bool useRichCursorEncoding; /* rfbEncodingRichCursor is preferred */ Bool cursorWasChanged; /* cursor shape update should be sent */ diff --git a/libvncserver/rfbproto.h b/libvncserver/rfbproto.h index 6b4fb35..9f9f6bc 100644 --- a/libvncserver/rfbproto.h +++ b/libvncserver/rfbproto.h @@ -329,6 +329,7 @@ typedef struct { #define rfbEncodingSoftCursor 0xFFFFFF12 #define rfbEncodingLastRect 0xFFFFFF20 +#define rfbEncodingBackground 0xFFFFFF25 #define rfbEncodingQualityLevel0 0xFFFFFFE0 #define rfbEncodingQualityLevel1 0xFFFFFFE1 diff --git a/libvncserver/rfbserver.c b/libvncserver/rfbserver.c index 0d54a45..3184fce 100644 --- a/libvncserver/rfbserver.c +++ b/libvncserver/rfbserver.c @@ -273,6 +273,7 @@ rfbNewTCPOrUDPClient(rfbScreen,sock,isUDP) cl->enableCursorShapeUpdates = FALSE; cl->useRichCursorEncoding = FALSE; cl->enableLastRectEncoding = FALSE; + cl->disableBackground = FALSE; cl->compStreamInited = FALSE; cl->compStream.total_in = 0; @@ -299,6 +300,7 @@ rfbNewTCPOrUDPClient(rfbScreen,sock,isUDP) cl->clientData = NULL; cl->clientGoneHook = doNothingWithClient; + cl->negotiationFinishedHook = doNothingWithClient; switch (cl->screen->newClientHook(cl)) { case RFB_CLIENT_ON_HOLD: cl->onHold = TRUE; @@ -663,6 +665,7 @@ rfbProcessClientNormalMessage(cl) cl->useCopyRect = FALSE; cl->enableCursorShapeUpdates = FALSE; cl->enableLastRectEncoding = FALSE; + cl->disableBackground = FALSE; for (i = 0; i < msg.se.nEncodings; i++) { if ((n = ReadExact(cl, (char *)&enc, 4)) <= 0) { @@ -749,6 +752,11 @@ rfbProcessClientNormalMessage(cl) cl->enableLastRectEncoding = TRUE; } break; + case rfbEncodingBackground: + rfbLog("Disabling background for client " + "%s\n", cl->host); + cl->disableBackground = TRUE; + break; #ifdef BACKCHANNEL case rfbEncodingBackChannel: if (!cl->enableBackChannel) { @@ -780,6 +788,8 @@ rfbProcessClientNormalMessage(cl) cl->preferredEncoding = rfbEncodingRaw; } + cl->negotiationFinishedHook(cl); + return; }