From 83065da33d51ca976a7350acd2db26e77b66e991 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 9 Aug 2024 15:56:35 +0200 Subject: [PATCH] Convert screen layout change request to signals --- common/rfb/SConnection.cxx | 21 +++++++++++++++++++++ common/rfb/SConnection.h | 11 +++++++++++ common/rfb/SDesktop.h | 5 ----- common/rfb/VNCSConnectionST.cxx | 18 ------------------ common/rfb/VNCSConnectionST.h | 2 -- common/rfb/VNCServer.h | 3 +++ common/rfb/VNCServerST.cxx | 17 +++++++++++------ common/rfb/VNCServerST.h | 9 ++++----- unix/x0vncserver/XDesktop.cxx | 22 +++++++++++++--------- unix/x0vncserver/XDesktop.h | 4 ++-- unix/xserver/hw/vnc/XserverDesktop.cc | 13 +++++++++---- unix/xserver/hw/vnc/XserverDesktop.h | 5 +++-- win/rfb_win32/SDisplay.cxx | 6 ++++-- win/rfb_win32/SDisplay.h | 4 ++-- 14 files changed, 83 insertions(+), 57 deletions(-) diff --git a/common/rfb/SConnection.cxx b/common/rfb/SConnection.cxx index 8ea2b702e..ccd1657e3 100644 --- a/common/rfb/SConnection.cxx +++ b/common/rfb/SConnection.cxx @@ -71,6 +71,8 @@ SConnection::SConnection(AccessRights accessRights_) registerSignal("clipboardannounce"); registerSignal("clipboarddata"); + registerSignal("layoutrequest"); + defaultMajorVersion = 3; defaultMinorVersion = 8; if (rfb::Server::protocol3_3) @@ -539,6 +541,25 @@ void SConnection::handleClipboardProvide(uint32_t flags, emitSignal("clipboarddata", clientClipboard.c_str()); } +void SConnection::setDesktopSize(int fb_width, int fb_height, + const ScreenSet& layout) +{ + char buffer[2048]; + + vlog.debug("Got request for framebuffer resize to %dx%d", + fb_width, fb_height); + layout.print(buffer, sizeof(buffer)); + vlog.debug("%s", buffer); + + if (!accessCheck(AccessSetDesktopSize)) { + vlog.debug("Rejecting unauthorized framebuffer resize request"); + writer()->writeDesktopSize(reasonClient, resultProhibited); + } else { + emitSignal("layoutrequest", + LayoutEvent({fb_width, fb_height, layout})); + } +} + void SConnection::supportsLocalCursor() { } diff --git a/common/rfb/SConnection.h b/common/rfb/SConnection.h index 62dc52308..f4cbc50a1 100644 --- a/common/rfb/SConnection.h +++ b/common/rfb/SConnection.h @@ -50,6 +50,11 @@ namespace rfb { uint8_t buttonMask; }; + struct LayoutEvent { + int width, height; + ScreenSet layout; + }; + class SConnection : public core::Object, public SMsgHandler { public: @@ -180,6 +185,9 @@ namespace rfb { // client received the request. A const char* string is included // that contains the actual clipboard contents. + // "layoutrequest" is emitted whenever the client requests the to + // reconfigure the framebuffer and/or the layout of screens. + protected: // Overridden from SMsgHandler @@ -201,6 +209,9 @@ namespace rfb { void handleClipboardProvide(uint32_t flags, const size_t* lengths, const uint8_t* const* data) override; + void setDesktopSize(int fb_width, int fb_height, + const ScreenSet& layout) override; + // Methods to be overridden in a derived class // supportsLocalCursor() is called whenever the status of diff --git a/common/rfb/SDesktop.h b/common/rfb/SDesktop.h index d0b899973..9192c1537 100644 --- a/common/rfb/SDesktop.h +++ b/common/rfb/SDesktop.h @@ -61,11 +61,6 @@ namespace rfb { virtual void queryConnection(network::Socket* sock, const char* userName) = 0; - // setScreenLayout() requests to reconfigure the framebuffer and/or - // the layout of screens. - virtual void setScreenLayout(int fb_width, int fb_height, - const ScreenSet& layout) = 0; - protected: virtual ~SDesktop() {} }; diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx index 6347546b3..cbdb599be 100644 --- a/common/rfb/VNCSConnectionST.cxx +++ b/common/rfb/VNCSConnectionST.cxx @@ -671,24 +671,6 @@ void VNCSConnectionST::framebufferUpdateRequest(const core::Rect& r,bool increme } } -void VNCSConnectionST::setDesktopSize(int fb_width, int fb_height, - const ScreenSet& layout) -{ - char buffer[2048]; - - vlog.debug("Got request for framebuffer resize to %dx%d", - fb_width, fb_height); - layout.print(buffer, sizeof(buffer)); - vlog.debug("%s", buffer); - - if (!accessCheck(AccessSetDesktopSize)) { - vlog.debug("Rejecting unauthorized framebuffer resize request"); - setDesktopSizeFailure(resultProhibited); - } else { - server->setDesktopSize(this, fb_width, fb_height, layout); - } -} - void VNCSConnectionST::fence(uint32_t flags, unsigned len, const uint8_t data[]) { uint8_t type; diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h index 6fee4c529..f496d84a1 100644 --- a/common/rfb/VNCSConnectionST.h +++ b/common/rfb/VNCSConnectionST.h @@ -135,8 +135,6 @@ namespace rfb { bool down) override; void framebufferUpdateRequest(const core::Rect& r, bool incremental) override; - void setDesktopSize(int fb_width, int fb_height, - const ScreenSet& layout) override; void fence(uint32_t flags, unsigned len, const uint8_t data[]) override; void enableContinuousUpdates(bool enable, diff --git a/common/rfb/VNCServer.h b/common/rfb/VNCServer.h index e51b6c1a7..0c8857a53 100644 --- a/common/rfb/VNCServer.h +++ b/common/rfb/VNCServer.h @@ -198,6 +198,9 @@ namespace rfb { // client received the request. A const char* string is included // that contains the actual clipboard contents. + // "layoutrequest" is emitted whenever the client requests the to + // reconfigure the framebuffer and/or the layout of screens. + // "frame" is emitted whenever a frame update has been processed, // signalling that a good time to render new data }; diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx index 653da58df..bcdc31247 100644 --- a/common/rfb/VNCServerST.cxx +++ b/common/rfb/VNCServerST.cxx @@ -108,6 +108,8 @@ VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_) registerSignal("clipboardannounce"); registerSignal("clipboarddata"); + registerSignal("layoutrequest"); + registerSignal("frame"); idleTimer.connectSignal("timer", this, @@ -206,6 +208,9 @@ void VNCServerST::addSocket(network::Socket* sock, bool outgoing, AccessRights a client->connectSignal("clipboarddata", this, &VNCServerST::handleClipboardData); + client->connectSignal("layoutrequest", this, + &VNCServerST::handleLayoutRequest); + client->init(); } @@ -622,9 +627,9 @@ void VNCServerST::pointerEvent(VNCSConnectionST* client, emitSignal(evname, event); } -void VNCServerST::setDesktopSize(VNCSConnectionST* requester, - int fb_width, int fb_height, - const ScreenSet& layout) +void VNCServerST::handleLayoutRequest(VNCSConnectionST* requester, + const char* evname, + LayoutEvent event) { std::list::iterator ci; @@ -635,14 +640,14 @@ void VNCServerST::setDesktopSize(VNCSConnectionST* requester, // We can't handle a framebuffer larger than this, so don't let a // client set one (see PixelBuffer.cxx) - if ((fb_width > 16384) || (fb_height > 16384)) { + if ((event.width > 16384) || (event.height > 16384)) { slog.error("Rejecting too large framebuffer resize request"); requester->setDesktopSizeFailureOrClose(resultProhibited); return; } // Don't bother the desktop with an invalid configuration - if (!layout.validate(fb_width, fb_height)) { + if (!event.layout.validate(event.width, event.height)) { slog.error("Invalid screen layout requested by client"); requester->setDesktopSizeFailureOrClose(resultInvalid); return; @@ -661,7 +666,7 @@ void VNCServerST::setDesktopSize(VNCSConnectionST* requester, // FIXME: the desktop will call back to VNCServerST and an extra set // of ExtendedDesktopSize messages will be sent. This is okay // protocol-wise, but unnecessary. - desktop->setScreenLayout(fb_width, fb_height, layout); + emitSignal(evname, event); } // Other public methods diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h index ec0050c27..792263295 100644 --- a/common/rfb/VNCServerST.h +++ b/common/rfb/VNCServerST.h @@ -118,11 +118,6 @@ namespace rfb { const char* getName() const { return name.c_str(); } unsigned getLEDState() const { return ledState; } - // Event handlers - void setDesktopSize(VNCSConnectionST* requester, - int fb_width, int fb_height, - const ScreenSet& layout); - // closeClients() closes all RFB sessions, except the specified one (if // any), and logs the specified reason for closure. void closeClients(const char* reason, network::Socket* sock); @@ -162,6 +157,10 @@ namespace rfb { void handleClipboardData(VNCSConnectionST* client, const char*, const char* data); + void handleLayoutRequest(VNCSConnectionST* client, + const char* name, + LayoutEvent event); + // Timer callbacks void frameTimeout(core::Timer*, const char*); void idleTimeout(core::Timer*, const char*); diff --git a/unix/x0vncserver/XDesktop.cxx b/unix/x0vncserver/XDesktop.cxx index 22590dd56..138f3e9a7 100644 --- a/unix/x0vncserver/XDesktop.cxx +++ b/unix/x0vncserver/XDesktop.cxx @@ -249,6 +249,9 @@ void XDesktop::init(VNCServer* vs) server->connectSignal("keydown", this, &XDesktop::keyEvent); server->connectSignal("keyup", this, &XDesktop::keyEvent); server->connectSignal("pointer", this, &XDesktop::pointerEvent); + + server->connectSignal("layoutrequest", this, + &XDesktop::layoutRequest); } void XDesktop::start(VNCServer*, const char*) @@ -685,8 +688,8 @@ static void GetSmallerMode(XRRScreenResources *res, } #endif /* HAVE_XRANDR */ -void XDesktop::setScreenLayout(int fb_width, int fb_height, - const rfb::ScreenSet& layout) +void XDesktop::layoutRequest(rfb::VNCServer*, const char*, + rfb::LayoutEvent event) { #ifdef HAVE_XRANDR unsigned int ret; @@ -707,15 +710,16 @@ void XDesktop::setScreenLayout(int fb_width, int fb_height, cases, we first call tryScreenLayout. If this fails, we try to adjust the request to one screen with a smaller mode. */ vlog.debug("Testing screen layout"); - ret = ::tryScreenLayout(fb_width, fb_height, layout, &outputIdMap); + ret = ::tryScreenLayout(event.width, event.height, + event.layout, &outputIdMap); if (ret == rfb::resultSuccess) { - adjustedWidth = fb_width; - adjustedHeight = fb_height; - adjustedLayout = layout; + adjustedWidth = event.width; + adjustedHeight = event.height; + adjustedLayout = event.layout; } else { vlog.debug("Impossible layout - trying to adjust"); - ScreenSet::const_iterator firstscreen = layout.begin(); + ScreenSet::const_iterator firstscreen = event.layout.begin(); adjustedLayout.add_screen(*firstscreen); ScreenSet::iterator iter = adjustedLayout.begin(); RROutput outputId = None; @@ -837,7 +841,7 @@ void XDesktop::setScreenLayout(int fb_width, int fb_height, VNCSConnectionST::setDesktopSize. Another ExtendedDesktopSize with reason=0 will be sent in response to the changes seen by the event handler. */ - if (adjustedLayout != layout) { + if (adjustedLayout != event.layout) { server->rejectScreenLayout(rfb::resultInvalid); return; } @@ -847,7 +851,7 @@ void XDesktop::setScreenLayout(int fb_width, int fb_height, server->setScreenLayout(computeScreenLayout()); if (ret == rfb::resultSuccess) - server->acceptScreenLayout(fb_width, fb_height, layout); + server->acceptScreenLayout(event.width, event.height, event.layout); else server->rejectScreenLayout(rfb::resultInvalid); diff --git a/unix/x0vncserver/XDesktop.h b/unix/x0vncserver/XDesktop.h index ebffeca75..163d7d6e4 100644 --- a/unix/x0vncserver/XDesktop.h +++ b/unix/x0vncserver/XDesktop.h @@ -57,8 +57,6 @@ class XDesktop : public rfb::SDesktop, bool isRunning(); void queryConnection(network::Socket* sock, const char* userName) override; - void setScreenLayout(int fb_width, int fb_height, - const rfb::ScreenSet& layout) override; // -=- TXGlobalEventHandler interface bool handleGlobalEvent(XEvent* ev) override; @@ -75,6 +73,8 @@ class XDesktop : public rfb::SDesktop, rfb::PointerEvent event); void keyEvent(rfb::VNCServer*, const char* name, rfb::KeyEvent event); + void layoutRequest(rfb::VNCServer*, const char*, + rfb::LayoutEvent event); protected: Display* dpy; diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc index eacbc0dee..6c24ed85a 100644 --- a/unix/xserver/hw/vnc/XserverDesktop.cc +++ b/unix/xserver/hw/vnc/XserverDesktop.cc @@ -98,6 +98,9 @@ XserverDesktop::XserverDesktop(int screenIndex_, server->connectSignal("clipboarddata", this, &XserverDesktop::handleClipboardData); + server->connectSignal("layoutrequest", this, + &XserverDesktop::layoutRequest); + setFramebuffer(width, height, fbptr, stride_); queryConnectTimer.connectSignal("timer", this, @@ -481,20 +484,22 @@ void XserverDesktop::pointerEvent(rfb::VNCServerST*, const char*, vncPointerButtonAction(event.buttonMask); } -void XserverDesktop::setScreenLayout(int fb_width, int fb_height, - const rfb::ScreenSet& layout) +void XserverDesktop::layoutRequest(rfb::VNCServerST*, const char*, + rfb::LayoutEvent event) { unsigned int result; vncSetGlueContext(screenIndex); - result = ::setScreenLayout(fb_width, fb_height, layout, &outputIdMap); + result = ::setScreenLayout(event.width, event.height, + event.layout, &outputIdMap); // Explicitly update the server state with the result as there // can be corner cases where we don't get feedback from the X core refreshScreenLayout(); if (result == rfb::resultSuccess) - server->acceptScreenLayout(fb_width, fb_height, layout); + server->acceptScreenLayout(event.width, event.height, + event.layout); else server->rejectScreenLayout(result); } diff --git a/unix/xserver/hw/vnc/XserverDesktop.h b/unix/xserver/hw/vnc/XserverDesktop.h index 8996c5eab..445fdec26 100644 --- a/unix/xserver/hw/vnc/XserverDesktop.h +++ b/unix/xserver/hw/vnc/XserverDesktop.h @@ -95,8 +95,6 @@ class XserverDesktop : public rfb::SDesktop, void init(rfb::VNCServer* vs) override; void queryConnection(network::Socket* sock, const char* userName) override; - void setScreenLayout(int fb_width, int fb_height, - const rfb::ScreenSet& layout) override; // rfb::PixelBuffer callbacks void grabRegion(const core::Region& r) override; @@ -113,6 +111,9 @@ class XserverDesktop : public rfb::SDesktop, void handleClipboardData(rfb::VNCServerST*, const char*, const char* data); + void layoutRequest(rfb::VNCServerST*, const char*, + rfb::LayoutEvent event) ; + void frameTick(rfb::VNCServerST*, const char*); bool handleListenerEvent(int fd, diff --git a/win/rfb_win32/SDisplay.cxx b/win/rfb_win32/SDisplay.cxx index a7bbc229f..f548a4f25 100644 --- a/win/rfb_win32/SDisplay.cxx +++ b/win/rfb_win32/SDisplay.cxx @@ -117,6 +117,9 @@ void SDisplay::init(VNCServer* vs) &SDisplay::handleClipboardAnnounce); server->connectSignal("clipboarddata", this, &SDisplay::handleClipboardData); + + server->connectSignal("layoutrequest", this, + &SDisplay::layoutRequest); } void SDisplay::start(VNCServer*, const char*) @@ -180,8 +183,7 @@ void SDisplay::queryConnection(network::Socket* sock, } -void SDisplay::setScreenLayout(int /*fb_width*/, int /*fb_height*/, - const ScreenSet& /*layout*/) +void SDisplay::layoutRequest(VNCServer*, const char*, LayoutEvent) { assert(server != nullptr); server->rejectScreenLayout(rfb::resultProhibited); diff --git a/win/rfb_win32/SDisplay.h b/win/rfb_win32/SDisplay.h index 0def130bd..b572d10ff 100644 --- a/win/rfb_win32/SDisplay.h +++ b/win/rfb_win32/SDisplay.h @@ -74,8 +74,6 @@ namespace rfb { void init(VNCServer* vs) override; void queryConnection(network::Socket* sock, const char* userName) override; - void setScreenLayout(int fb_width, int fb_height, - const ScreenSet& layout) override; // -=- Clipboard events @@ -132,6 +130,8 @@ namespace rfb { void handleClipboardData(VNCServer*, const char*, const char* data); + void layoutRequest(VNCServer*, const char*, LayoutEvent); + VNCServer* server; // -=- Display pixel buffer