Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for notifying clients about pointer movements #1198

Merged
merged 1 commit into from
Mar 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion common/rfb/ClientParams.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ ClientParams::ClientParams()
compressLevel(2), qualityLevel(-1), fineQualityLevel(-1),
subsampling(subsampleUndefined),
width_(0), height_(0), name_(0),
ledState_(ledUnknown)
cursorPos_(0, 0), ledState_(ledUnknown)
{
setName("");

Expand Down Expand Up @@ -85,6 +85,11 @@ void ClientParams::setCursor(const Cursor& other)
cursor_ = new Cursor(other);
}

void ClientParams::setCursorPos(const Point& pos)
{
cursorPos_ = pos;
}

bool ClientParams::supportsEncoding(rdr::S32 encoding) const
{
return encodings_.count(encoding) != 0;
Expand Down Expand Up @@ -182,6 +187,13 @@ bool ClientParams::supportsLocalCursor() const
return false;
}

bool ClientParams::supportsCursorPosition() const
{
if (supportsEncoding(pseudoEncodingVMwareCursorPosition))
return true;
return false;
}

bool ClientParams::supportsDesktopSize() const
{
if (supportsEncoding(pseudoEncodingExtendedDesktopSize))
Expand Down
5 changes: 5 additions & 0 deletions common/rfb/ClientParams.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ namespace rfb {
const Cursor& cursor() const { return *cursor_; }
void setCursor(const Cursor& cursor);

const Point& cursorPos() const { return cursorPos_; }
void setCursorPos(const Point& pos);

bool supportsEncoding(rdr::S32 encoding) const;

void setEncodings(int nEncodings, const rdr::S32* encodings);
Expand All @@ -91,6 +94,7 @@ namespace rfb {
// Wrappers to check for functionality rather than specific
// encodings
bool supportsLocalCursor() const;
bool supportsCursorPosition() const;
bool supportsDesktopSize() const;
bool supportsLEDState() const;
bool supportsFence() const;
Expand All @@ -110,6 +114,7 @@ namespace rfb {
PixelFormat pf_;
char* name_;
Cursor* cursor_;
Point cursorPos_;
std::set<rdr::S32> encodings_;
unsigned int ledState_;
rdr::U32 clipFlags;
Expand Down
41 changes: 40 additions & 1 deletion common/rfb/SMsgWriter.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ SMsgWriter::SMsgWriter(ClientParams* client_, rdr::OutStream* os_)
: client(client_), os(os_),
nRectsInUpdate(0), nRectsInHeader(0),
needSetDesktopName(false), needCursor(false),
needLEDState(false), needQEMUKeyEvent(false)
needCursorPos(false), needLEDState(false),
needQEMUKeyEvent(false)
{
}

Expand Down Expand Up @@ -269,6 +270,14 @@ void SMsgWriter::writeCursor()
needCursor = true;
}

void SMsgWriter::writeCursorPos()
{
if (!client->supportsEncoding(pseudoEncodingVMwareCursorPosition))
throw Exception("Client does not support cursor position");

needCursorPos = true;
}

void SMsgWriter::writeLEDState()
{
if (!client->supportsEncoding(pseudoEncodingLEDState) &&
Expand All @@ -294,6 +303,8 @@ bool SMsgWriter::needFakeUpdate()
return true;
if (needCursor)
return true;
if (needCursorPos)
return true;
if (needLEDState)
return true;
if (needQEMUKeyEvent)
Expand Down Expand Up @@ -340,6 +351,8 @@ void SMsgWriter::writeFramebufferUpdateStart(int nRects)
nRects++;
if (needCursor)
nRects++;
if (needCursorPos)
nRects++;
if (needLEDState)
nRects++;
if (needQEMUKeyEvent)
Expand Down Expand Up @@ -455,6 +468,18 @@ void SMsgWriter::writePseudoRects()
needCursor = false;
}

if (needCursorPos) {
const Point& cursorPos = client->cursorPos();

if (client->supportsEncoding(pseudoEncodingVMwareCursorPosition)) {
writeSetVMwareCursorPositionRect(cursorPos.x, cursorPos.y);
} else {
throw Exception("Client does not support cursor position");
}

needCursorPos = false;
}

if (needSetDesktopName) {
writeSetDesktopNameRect(client->name());
needSetDesktopName = false;
Expand Down Expand Up @@ -650,6 +675,20 @@ void SMsgWriter::writeSetVMwareCursorRect(int width, int height,
os->writeBytes(data, width*height*4);
}

void SMsgWriter::writeSetVMwareCursorPositionRect(int hotspotX, int hotspotY)
{
if (!client->supportsEncoding(pseudoEncodingVMwareCursorPosition))
throw Exception("Client does not support cursor position");
if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
throw Exception("SMsgWriter::writeSetVMwareCursorRect: nRects out of sync");

os->writeS16(hotspotX);
os->writeS16(hotspotY);
os->writeU16(0);
os->writeU16(0);
os->writeU32(pseudoEncodingVMwareCursorPosition);
}

void SMsgWriter::writeLEDStateRect(rdr::U8 state)
{
if (!client->supportsEncoding(pseudoEncodingLEDState) &&
Expand Down
5 changes: 5 additions & 0 deletions common/rfb/SMsgWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ namespace rfb {
// immediately.
void writeCursor();

// Notifies the client that the cursor pointer was moved by the server.
void writeCursorPos();

// Same for LED state message
void writeLEDState();

Expand Down Expand Up @@ -141,6 +144,7 @@ namespace rfb {
void writeSetVMwareCursorRect(int width, int height,
int hotspotX, int hotspotY,
const rdr::U8* data);
void writeSetVMwareCursorPositionRect(int hotspotX, int hotspotY);
void writeLEDStateRect(rdr::U8 state);
void writeQEMUKeyEventRect();

Expand All @@ -152,6 +156,7 @@ namespace rfb {

bool needSetDesktopName;
bool needCursor;
bool needCursorPos;
bool needLEDState;
bool needQEMUKeyEvent;

Expand Down
24 changes: 24 additions & 0 deletions common/rfb/VNCSConnectionST.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,15 @@ void VNCSConnectionST::renderedCursorChange()
}
}

// cursorPositionChange() is called whenever the cursor has changed position by
// the server. If the client supports being informed about these changes then
// it will arrange for the new cursor position to be sent to the client.

void VNCSConnectionST::cursorPositionChange()
{
setCursorPos();
}

// needRenderedCursor() returns true if this client needs the server-side
// rendered cursor. This may be because it does not support local cursor or
// because the current cursor position has not been set by this client.
Expand Down Expand Up @@ -1123,6 +1132,21 @@ void VNCSConnectionST::setCursor()
writer()->writeCursor();
}

// setCursorPos() is called whenever the cursor has changed position by the
// server. If the client supports being informed about these changes then it
// will arrange for the new cursor position to be sent to the client.

void VNCSConnectionST::setCursorPos()
{
if (state() != RFBSTATE_NORMAL)
return;

if (client.supportsCursorPosition()) {
client.setCursorPos(server->getCursorPos());
writer()->writeCursorPos();
}
}

void VNCSConnectionST::setDesktopName(const char *name)
{
client.setName(name);
Expand Down
6 changes: 6 additions & 0 deletions common/rfb/VNCSConnectionST.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ namespace rfb {
// cursor.
void renderedCursorChange();

// cursorPositionChange() is called whenever the cursor has changed position by
// the server. If the client supports being informed about these changes then
// it will arrange for the new cursor position to be sent to the client.
void cursorPositionChange();

// needRenderedCursor() returns true if this client needs the server-side
// rendered cursor. This may be because it does not support local cursor
// or because the current cursor position has not been set by this client.
Expand Down Expand Up @@ -155,6 +160,7 @@ namespace rfb {

void screenLayoutChange(rdr::U16 reason);
void setCursor();
void setCursorPos();
void setDesktopName(const char *name);
void setLEDState(unsigned int state);

Expand Down
6 changes: 4 additions & 2 deletions common/rfb/VNCServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,10 @@ namespace rfb {
virtual void setCursor(int width, int height, const Point& hotspot,
const rdr::U8* cursorData) = 0;

// setCursorPos() tells the server the current position of the cursor.
virtual void setCursorPos(const Point& p) = 0;
// setCursorPos() tells the server the current position of the cursor, and
// whether the server initiated that change (e.g. through another X11
// client calling XWarpPointer()).
virtual void setCursorPos(const Point& p, bool warped) = 0;

// setName() tells the server what desktop title to supply to clients
virtual void setName(const char* name) = 0;
Expand Down
7 changes: 5 additions & 2 deletions common/rfb/VNCServerST.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -429,14 +429,17 @@ void VNCServerST::setCursor(int width, int height, const Point& newHotspot,
}
}

void VNCServerST::setCursorPos(const Point& pos)
void VNCServerST::setCursorPos(const Point& pos, bool warped)
{
if (!cursorPos.equals(pos)) {
cursorPos = pos;
renderedCursorInvalid = true;
std::list<VNCSConnectionST*>::iterator ci;
for (ci = clients.begin(); ci != clients.end(); ci++)
for (ci = clients.begin(); ci != clients.end(); ci++) {
(*ci)->renderedCursorChange();
if (warped)
(*ci)->cursorPositionChange();
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion common/rfb/VNCServerST.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ namespace rfb {
virtual void add_copied(const Region &dest, const Point &delta);
virtual void setCursor(int width, int height, const Point& hotspot,
const rdr::U8* data);
virtual void setCursorPos(const Point& p);
virtual void setCursorPos(const Point& p, bool warped);
virtual void setName(const char* name_);
virtual void setLEDState(unsigned state);

Expand Down
1 change: 1 addition & 0 deletions common/rfb/encodings.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ namespace rfb {

// VMware-specific
const int pseudoEncodingVMwareCursor = 0x574d5664;
const int pseudoEncodingVMwareCursorPosition = 0x574d5666;
const int pseudoEncodingVMwareLEDState = 0x574d5668;

// UltraVNC-specific
Expand Down
2 changes: 1 addition & 1 deletion unix/x0vncserver/XDesktop.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ void XDesktop::poll() {
&x, &y, &wx, &wy, &mask);
x -= geometry->offsetLeft();
y -= geometry->offsetTop();
server->setCursorPos(rfb::Point(x, y));
server->setCursorPos(rfb::Point(x, y), false);
}
}

Expand Down
11 changes: 10 additions & 1 deletion unix/xserver/hw/vnc/XserverDesktop.cc
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,15 @@ void XserverDesktop::setCursor(int width, int height, int hotX, int hotY,
delete [] cursorData;
}

void XserverDesktop::setCursorPos(int x, int y, bool warped)
{
try {
server->setCursorPos(Point(x, y), warped);
} catch (rdr::Exception& e) {
vlog.error("XserverDesktop::setCursorPos: %s",e.str());
}
}

void XserverDesktop::add_changed(const rfb::Region &region)
{
try {
Expand Down Expand Up @@ -377,7 +386,7 @@ void XserverDesktop::blockHandler(int* timeout)
if (oldCursorPos.x != cursorX || oldCursorPos.y != cursorY) {
oldCursorPos.x = cursorX;
oldCursorPos.y = cursorY;
server->setCursorPos(oldCursorPos);
server->setCursorPos(oldCursorPos, false);
}

// Trigger timers and check when the next will expire
Expand Down
1 change: 1 addition & 0 deletions unix/xserver/hw/vnc/XserverDesktop.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class XserverDesktop : public rfb::SDesktop, public rfb::FullFramePixelBuffer,
void setDesktopName(const char* name);
void setCursor(int width, int height, int hotX, int hotY,
const unsigned char *rgbaData);
void setCursorPos(int x, int y, bool warped);
void add_changed(const rfb::Region &region);
void add_copied(const rfb::Region &dest, const rfb::Point &delta);
void handleSocketEvent(int fd, bool read, bool write);
Expand Down
5 changes: 5 additions & 0 deletions unix/xserver/hw/vnc/vncExtInit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,11 @@ void vncSetCursor(int width, int height, int hotX, int hotY,
desktop[scr]->setCursor(width, height, hotX, hotY, rgbaData);
}

void vncSetCursorPos(int scrIdx, int x, int y)
{
desktop[scrIdx]->setCursorPos(x, y, true);
}

void vncPreScreenResize(int scrIdx)
{
// We need to prevent the RFB core from accessing the framebuffer
Expand Down
1 change: 1 addition & 0 deletions unix/xserver/hw/vnc/vncExtInit.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ void vncAddCopied(int scrIdx, int nRects,

void vncSetCursor(int width, int height, int hotX, int hotY,
const unsigned char *rgbaData);
void vncSetCursorPos(int scrIdx, int x, int y);

void vncPreScreenResize(int scrIdx);
void vncPostScreenResize(int scrIdx, int success, int width, int height);
Expand Down
26 changes: 26 additions & 0 deletions unix/xserver/hw/vnc/vncHooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ typedef struct _vncHooksScreenRec {
CopyWindowProcPtr CopyWindow;
ClearToBackgroundProcPtr ClearToBackground;
DisplayCursorProcPtr DisplayCursor;
#if XORG >= 119
CursorWarpedToProcPtr CursorWarpedTo;
#endif
ScreenBlockHandlerProcPtr BlockHandler;
#ifdef RENDER
CompositeProcPtr Composite;
Expand Down Expand Up @@ -113,6 +116,12 @@ static void vncHooksClearToBackground(WindowPtr pWin, int x, int y, int w,
int h, Bool generateExposures);
static Bool vncHooksDisplayCursor(DeviceIntPtr pDev,
ScreenPtr pScreen, CursorPtr cursor);
#if XORG >= 119
static void vncHooksCursorWarpedTo(DeviceIntPtr pDev,
ScreenPtr pScreen_, ClientPtr pClient,
WindowPtr pWindow, SpritePtr pSprite,
int x, int y);
#endif
#if XORG <= 118
static void vncHooksBlockHandler(ScreenPtr pScreen, void * pTimeout,
void * pReadmask);
Expand Down Expand Up @@ -271,6 +280,9 @@ int vncHooksInit(int scrIdx)
wrap(vncHooksScreen, pScreen, CopyWindow, vncHooksCopyWindow);
wrap(vncHooksScreen, pScreen, ClearToBackground, vncHooksClearToBackground);
wrap(vncHooksScreen, pScreen, DisplayCursor, vncHooksDisplayCursor);
#if XORG >= 119
wrap(vncHooksScreen, pScreen, CursorWarpedTo, vncHooksCursorWarpedTo);
#endif
wrap(vncHooksScreen, pScreen, BlockHandler, vncHooksBlockHandler);
#ifdef RENDER
ps = GetPictureScreenIfSet(pScreen);
Expand Down Expand Up @@ -631,6 +643,20 @@ static Bool vncHooksDisplayCursor(DeviceIntPtr pDev,
return ret;
}

// CursorWarpedTo - notify that the cursor was warped

#if XORG >= 119
static void vncHooksCursorWarpedTo(DeviceIntPtr pDev,
ScreenPtr pScreen_, ClientPtr pClient,
WindowPtr pWindow, SpritePtr pSprite,
int x, int y)
{
SCREEN_PROLOGUE(pScreen_, CursorWarpedTo);
vncSetCursorPos(pScreen->myNum, x, y);
SCREEN_EPILOGUE(CursorWarpedTo);
}
#endif

// BlockHandler - ignore any changes during the block handler - it's likely
// these are just drawing the cursor.

Expand Down
Loading