Skip to content

Commit

Permalink
Make setScreenLayout() asynchronous
Browse files Browse the repository at this point in the history
Allows more flexibility in how things are implemented and connected.
  • Loading branch information
CendioOssman committed Aug 13, 2024
1 parent 2804ea1 commit 9ad90df
Show file tree
Hide file tree
Showing 10 changed files with 112 additions and 43 deletions.
7 changes: 2 additions & 5 deletions common/rfb/SDesktop.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,8 @@ namespace rfb {

// setScreenLayout() requests to reconfigure the framebuffer and/or
// the layout of screens.
virtual unsigned int setScreenLayout(int /*fb_width*/,
int /*fb_height*/,
const ScreenSet& /*layout*/) {
return resultProhibited;
}
virtual void setScreenLayout(int fb_width, int fb_height,
const ScreenSet& layout) = 0;

protected:
virtual ~SDesktop() {}
Expand Down
10 changes: 10 additions & 0 deletions common/rfb/VNCServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,16 @@ namespace rfb {
// the pixelbuffer. Clients will be notified of the new layout.
virtual void setScreenLayout(const ScreenSet& layout) = 0;

// acceptScreenLayout() accepts a request by a client to change the
// screen layout and informs both the requesting client, and any
// other connected clients.
virtual void acceptScreenLayout(int fb_width, int fb_height,
const ScreenSet& layout) = 0;

// rejectScreenLayout() rejects a request by a client to change the
// screen layout.
virtual void rejectScreenLayout(unsigned int reason) = 0;

// getPixelBuffer() returns a pointer to the PixelBuffer object.
virtual const PixelBuffer* getPixelBuffer() const = 0;

Expand Down
71 changes: 52 additions & 19 deletions common/rfb/VNCServerST.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_)
: blHosts(&blacklist), desktop(desktop_), desktopStarted(false),
blockCounter(0), pb(nullptr), ledState(ledUnknown),
name(name_), pointerClient(nullptr), clipboardClient(nullptr),
pointerClientTime(0), comparer(nullptr),
pointerClientTime(0), layoutClient(nullptr), comparer(nullptr),
cursor(new Cursor(0, 0, core::Point(), nullptr)),
renderedCursorInvalid(false),
keyRemapper(&KeyRemapper::defInstance),
Expand Down Expand Up @@ -220,6 +220,8 @@ void VNCServerST::removeSocket(network::Socket* sock) {
if (clipboardClient == *ci)
handleClipboardAnnounce(*ci, "", false);
clipboardRequestors.remove(*ci);
if (layoutClient == *ci)
layoutClient = nullptr;

std::string peer((*ci)->getPeerEndpoint());

Expand Down Expand Up @@ -389,6 +391,45 @@ void VNCServerST::setScreenLayout(const ScreenSet& layout)
(*ci)->screenLayoutChangeOrClose(reasonServer);
}

void VNCServerST::acceptScreenLayout(int fb_width, int fb_height,
const ScreenSet& layout)
{
if (layoutClient == nullptr) {
slog.debug("Unexpected or late acception of screen layout");
return;
}

// Sanity check
if (!pb)
throw Exception("acceptScreenLayout: no PixelBuffer");
if ((fb_width != pb->width()) || (fb_height != pb->height()))
throw Exception("Desktop configured a different screen layout than requested");
if (screenLayout != layout)
throw Exception("Desktop configured a different screen layout than requested");

// Notify other clients
std::list<VNCSConnectionST*>::iterator ci;
for (ci = clients.begin(); ci != clients.end(); ++ci) {
if ((*ci) == layoutClient)
continue;
(*ci)->screenLayoutChangeOrClose(reasonOtherClient);
}

layoutClient->screenLayoutChangeOrClose(reasonClient);
layoutClient = nullptr;
}

void VNCServerST::rejectScreenLayout(unsigned int reason)
{
if (layoutClient == nullptr) {
slog.debug("Unexpected or late rejection of screen layout");
return;
}

layoutClient->setDesktopSizeFailureOrClose(reason);
layoutClient = nullptr;
}

void VNCServerST::requestClipboard()
{
if (!rfb::Server::acceptCutText)
Expand Down Expand Up @@ -585,7 +626,6 @@ void VNCServerST::setDesktopSize(VNCSConnectionST* requester,
int fb_width, int fb_height,
const ScreenSet& layout)
{
unsigned int result;
std::list<VNCSConnectionST*>::iterator ci;

if (!rfb::Server::acceptSetDesktopSize) {
Expand All @@ -608,27 +648,20 @@ void VNCServerST::setDesktopSize(VNCSConnectionST* requester,
return;
}

// 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.
result = desktop->setScreenLayout(fb_width, fb_height, layout);
if (result != resultSuccess) {
requester->setDesktopSizeFailureOrClose(result);
// We don't bother with a queue, so just reject the second client if
// we happen to have overlapping requests
if (layoutClient != nullptr) {
slog.error("Rejecting concurrent screen layout requests");
requester->setDesktopSizeFailureOrClose(resultProhibited);
return;
}

// Sanity check
if (screenLayout != layout)
throw Exception("Desktop configured a different screen layout than requested");

// Notify other clients
for (ci = clients.begin(); ci != clients.end(); ++ci) {
if ((*ci) == requester)
continue;
(*ci)->screenLayoutChangeOrClose(reasonOtherClient);
}
layoutClient = requester;

requester->screenLayoutChangeOrClose(reasonClient);
// 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);
}

// Other public methods
Expand Down
5 changes: 5 additions & 0 deletions common/rfb/VNCServerST.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ namespace rfb {
void setPixelBuffer(PixelBuffer* pb, const ScreenSet& layout) override;
void setPixelBuffer(PixelBuffer* pb) override;
void setScreenLayout(const ScreenSet& layout) override;
void acceptScreenLayout(int fb_width, int fb_height,
const ScreenSet& layout) override;
void rejectScreenLayout(unsigned int reason) override;
const PixelBuffer* getPixelBuffer() const override { return pb; }

void requestClipboard() override;
Expand Down Expand Up @@ -201,6 +204,8 @@ namespace rfb {

time_t pointerClientTime;

VNCSConnectionST* layoutClient;

ComparingUpdateTracker* comparer;

core::Point cursorPos;
Expand Down
35 changes: 23 additions & 12 deletions unix/x0vncserver/XDesktop.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -685,14 +685,15 @@ static void GetSmallerMode(XRRScreenResources *res,
}
#endif /* HAVE_XRANDR */

unsigned int XDesktop::setScreenLayout(int fb_width, int fb_height,
const rfb::ScreenSet& layout)
void XDesktop::setScreenLayout(int fb_width, int fb_height,
const rfb::ScreenSet& layout)
{
#ifdef HAVE_XRANDR
XRRScreenResources *res = XRRGetScreenResources(dpy, DefaultRootWindow(dpy));
if (!res) {
vlog.error("XRRGetScreenResources failed");
return rfb::resultProhibited;
server->rejectScreenLayout(rfb::resultProhibited);
return;
}
vncSetGlueContext(dpy, res);

Expand Down Expand Up @@ -739,26 +740,30 @@ unsigned int XDesktop::setScreenLayout(int fb_width, int fb_height,
if (outputId == None) {
vlog.debug("Resize adjust: Could not find corresponding screen");
XRRFreeScreenResources(res);
return rfb::resultInvalid;
server->rejectScreenLayout(rfb::resultInvalid);
return;
}
XRROutputInfo *output = XRRGetOutputInfo(dpy, res, outputId);
if (!output) {
vlog.debug("Resize adjust: XRRGetOutputInfo failed");
XRRFreeScreenResources(res);
return rfb::resultInvalid;
server->rejectScreenLayout(rfb::resultInvalid);
return;
}
if (!output->crtc) {
vlog.debug("Resize adjust: Selected output has no CRTC");
XRRFreeScreenResources(res);
XRRFreeOutputInfo(output);
return rfb::resultInvalid;
server->rejectScreenLayout(rfb::resultInvalid);
return;
}
XRRCrtcInfo *crtc = XRRGetCrtcInfo(dpy, res, output->crtc);
if (!crtc) {
vlog.debug("Resize adjust: XRRGetCrtcInfo failed");
XRRFreeScreenResources(res);
XRRFreeOutputInfo(output);
return rfb::resultInvalid;
server->rejectScreenLayout(rfb::resultInvalid);
return;
}

unsigned int swidth = iter->dimensions.width();
Expand Down Expand Up @@ -795,7 +800,8 @@ unsigned int XDesktop::setScreenLayout(int fb_width, int fb_height,
} else {
vlog.error("Failed to find smaller or equal screen size");
XRRFreeScreenResources(res);
return rfb::resultInvalid;
server->rejectScreenLayout(rfb::resultInvalid);
return;
}
}

Expand Down Expand Up @@ -825,20 +831,25 @@ unsigned int 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)
return rfb::resultInvalid;
if (adjustedLayout != layout) {
server->rejectScreenLayout(rfb::resultInvalid);
return;
}

// Explicitly update the server state with the result as there
// can be corner cases where we don't get feedback from the X server
server->setScreenLayout(computeScreenLayout());

return ret;
if (ret == rfb::resultSuccess)
server->acceptScreenLayout(fb_width, fb_height, layout);
else
server->rejectScreenLayout(rfb::resultInvalid);

#else
(void)fb_width;
(void)fb_height;
(void)layout;
return rfb::resultProhibited;
server->rejectScreenLayout(rfb::resultProhibited);
#endif /* HAVE_XRANDR */
}

Expand Down
4 changes: 2 additions & 2 deletions unix/x0vncserver/XDesktop.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ class XDesktop : public rfb::SDesktop,
bool isRunning();
void queryConnection(network::Socket* sock,
const char* userName) override;
unsigned int setScreenLayout(int fb_width, int fb_height,
const rfb::ScreenSet& layout) override;
void setScreenLayout(int fb_width, int fb_height,
const rfb::ScreenSet& layout) override;

// -=- TXGlobalEventHandler interface
bool handleGlobalEvent(XEvent* ev) override;
Expand Down
9 changes: 6 additions & 3 deletions unix/xserver/hw/vnc/XserverDesktop.cc
Original file line number Diff line number Diff line change
Expand Up @@ -481,8 +481,8 @@ void XserverDesktop::pointerEvent(rfb::VNCServerST*, const char*,
vncPointerButtonAction(event.buttonMask);
}

unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height,
const rfb::ScreenSet& layout)
void XserverDesktop::setScreenLayout(int fb_width, int fb_height,
const rfb::ScreenSet& layout)
{
unsigned int result;

Expand All @@ -493,7 +493,10 @@ unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height,
// can be corner cases where we don't get feedback from the X core
refreshScreenLayout();

return result;
if (result == rfb::resultSuccess)
server->acceptScreenLayout(fb_width, fb_height, layout);
else
server->rejectScreenLayout(result);
}

void XserverDesktop::frameTick(rfb::VNCServerST*, const char*)
Expand Down
4 changes: 2 additions & 2 deletions unix/xserver/hw/vnc/XserverDesktop.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ class XserverDesktop : public rfb::SDesktop,
void init(rfb::VNCServer* vs) override;
void queryConnection(network::Socket* sock,
const char* userName) override;
unsigned int setScreenLayout(int fb_width, int fb_height,
const rfb::ScreenSet& layout) override;
void setScreenLayout(int fb_width, int fb_height,
const rfb::ScreenSet& layout) override;

// rfb::PixelBuffer callbacks
void grabRegion(const core::Region& r) override;
Expand Down
8 changes: 8 additions & 0 deletions win/rfb_win32/SDisplay.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,14 @@ void SDisplay::queryConnection(network::Socket* sock,
}


void SDisplay::setScreenLayout(int /*fb_width*/, int /*fb_height*/,
const ScreenSet& /*layout*/)
{
assert(server != nullptr);
server->rejectScreenLayout(rfb::resultProhibited);
}


void SDisplay::startCore() {

// Currently, we just check whether we're in the console session, and
Expand Down
2 changes: 2 additions & 0 deletions win/rfb_win32/SDisplay.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ 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

Expand Down

0 comments on commit 9ad90df

Please sign in to comment.