aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/rfb/CConnection.cxx7
-rw-r--r--common/rfb/CConnection.h1
-rw-r--r--common/rfb/CMsgHandler.h1
-rw-r--r--common/rfb/CMsgReader.cxx4
-rw-r--r--common/rfb/ClientParams.cxx14
-rw-r--r--common/rfb/ClientParams.h5
-rw-r--r--common/rfb/SMsgWriter.cxx41
-rw-r--r--common/rfb/SMsgWriter.h5
-rw-r--r--common/rfb/VNCSConnectionST.cxx24
-rw-r--r--common/rfb/VNCSConnectionST.h6
-rw-r--r--common/rfb/VNCServer.h6
-rw-r--r--common/rfb/VNCServerST.cxx7
-rw-r--r--common/rfb/VNCServerST.h2
-rw-r--r--common/rfb/encodings.h1
-rw-r--r--tests/perf/decperf.cxx5
-rw-r--r--tests/perf/encperf.cxx5
-rw-r--r--unix/x0vncserver/XDesktop.cxx2
-rw-r--r--unix/xserver/hw/vnc/XserverDesktop.cc11
-rw-r--r--unix/xserver/hw/vnc/XserverDesktop.h1
-rw-r--r--unix/xserver/hw/vnc/vncExtInit.cc5
-rw-r--r--unix/xserver/hw/vnc/vncExtInit.h1
-rw-r--r--unix/xserver/hw/vnc/vncHooks.c26
-rw-r--r--vncviewer/CConn.cxx6
-rw-r--r--vncviewer/CConn.h1
-rw-r--r--vncviewer/DesktopWindow.cxx32
-rw-r--r--vncviewer/DesktopWindow.h3
-rw-r--r--win/rfb_win32/SDisplay.cxx2
27 files changed, 212 insertions, 12 deletions
diff --git a/common/rfb/CConnection.cxx b/common/rfb/CConnection.cxx
index 9a9593e2..1c949009 100644
--- a/common/rfb/CConnection.cxx
+++ b/common/rfb/CConnection.cxx
@@ -43,8 +43,8 @@ static LogWriter vlog("CConnection");
CConnection::CConnection()
: csecurity(0),
- supportsLocalCursor(false), supportsDesktopResize(false),
- supportsLEDState(false),
+ supportsLocalCursor(false), supportsCursorPosition(false),
+ supportsDesktopResize(false), supportsLEDState(false),
is(0), os(0), reader_(0), writer_(0),
shared(false),
state_(RFBSTATE_UNINITIALISED),
@@ -805,6 +805,9 @@ void CConnection::updateEncodings()
encodings.push_back(pseudoEncodingCursor);
encodings.push_back(pseudoEncodingXCursor);
}
+ if (supportsCursorPosition) {
+ encodings.push_back(pseudoEncodingVMwareCursorPosition);
+ }
if (supportsDesktopResize) {
encodings.push_back(pseudoEncodingDesktopSize);
encodings.push_back(pseudoEncodingExtendedDesktopSize);
diff --git a/common/rfb/CConnection.h b/common/rfb/CConnection.h
index deab50ae..d5d07ca0 100644
--- a/common/rfb/CConnection.h
+++ b/common/rfb/CConnection.h
@@ -239,6 +239,7 @@ namespace rfb {
// Optional capabilities that a subclass is expected to set to true
// if supported
bool supportsLocalCursor;
+ bool supportsCursorPosition;
bool supportsDesktopResize;
bool supportsLEDState;
diff --git a/common/rfb/CMsgHandler.h b/common/rfb/CMsgHandler.h
index 5b14806a..43d8df24 100644
--- a/common/rfb/CMsgHandler.h
+++ b/common/rfb/CMsgHandler.h
@@ -52,6 +52,7 @@ namespace rfb {
const ScreenSet& layout);
virtual void setCursor(int width, int height, const Point& hotspot,
const rdr::U8* data) = 0;
+ virtual void setCursorPos(const Point& pos) = 0;
virtual void setPixelFormat(const PixelFormat& pf);
virtual void setName(const char* name);
virtual void fence(rdr::U32 flags, unsigned len, const char data[]);
diff --git a/common/rfb/CMsgReader.cxx b/common/rfb/CMsgReader.cxx
index f69e21de..2c823d56 100644
--- a/common/rfb/CMsgReader.cxx
+++ b/common/rfb/CMsgReader.cxx
@@ -165,6 +165,10 @@ bool CMsgReader::readMsg()
case pseudoEncodingVMwareCursor:
ret = readSetVMwareCursor(dataRect.width(), dataRect.height(), dataRect.tl);
break;
+ case pseudoEncodingVMwareCursorPosition:
+ handler->setCursorPos(dataRect.tl);
+ ret = true;
+ break;
case pseudoEncodingDesktopName:
ret = readSetDesktopName(dataRect.tl.x, dataRect.tl.y,
dataRect.width(), dataRect.height());
diff --git a/common/rfb/ClientParams.cxx b/common/rfb/ClientParams.cxx
index 6f075a24..c0cc3641 100644
--- a/common/rfb/ClientParams.cxx
+++ b/common/rfb/ClientParams.cxx
@@ -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("");
@@ -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;
@@ -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))
diff --git a/common/rfb/ClientParams.h b/common/rfb/ClientParams.h
index 3894ef2d..202cef4e 100644
--- a/common/rfb/ClientParams.h
+++ b/common/rfb/ClientParams.h
@@ -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);
@@ -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;
@@ -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;
diff --git a/common/rfb/SMsgWriter.cxx b/common/rfb/SMsgWriter.cxx
index a29ed9d8..2f40c0a6 100644
--- a/common/rfb/SMsgWriter.cxx
+++ b/common/rfb/SMsgWriter.cxx
@@ -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)
{
}
@@ -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) &&
@@ -294,6 +303,8 @@ bool SMsgWriter::needFakeUpdate()
return true;
if (needCursor)
return true;
+ if (needCursorPos)
+ return true;
if (needLEDState)
return true;
if (needQEMUKeyEvent)
@@ -340,6 +351,8 @@ void SMsgWriter::writeFramebufferUpdateStart(int nRects)
nRects++;
if (needCursor)
nRects++;
+ if (needCursorPos)
+ nRects++;
if (needLEDState)
nRects++;
if (needQEMUKeyEvent)
@@ -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;
@@ -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) &&
diff --git a/common/rfb/SMsgWriter.h b/common/rfb/SMsgWriter.h
index 2cea44d1..49381bad 100644
--- a/common/rfb/SMsgWriter.h
+++ b/common/rfb/SMsgWriter.h
@@ -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();
@@ -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();
@@ -152,6 +156,7 @@ namespace rfb {
bool needSetDesktopName;
bool needCursor;
+ bool needCursorPos;
bool needLEDState;
bool needQEMUKeyEvent;
diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
index 668bae0e..a966e66c 100644
--- a/common/rfb/VNCSConnectionST.cxx
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -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.
@@ -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);
diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h
index 6d95008d..72b0c529 100644
--- a/common/rfb/VNCSConnectionST.h
+++ b/common/rfb/VNCSConnectionST.h
@@ -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.
@@ -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);
diff --git a/common/rfb/VNCServer.h b/common/rfb/VNCServer.h
index 5d04da53..4535b562 100644
--- a/common/rfb/VNCServer.h
+++ b/common/rfb/VNCServer.h
@@ -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;
diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx
index b32cac59..39cdde1f 100644
--- a/common/rfb/VNCServerST.cxx
+++ b/common/rfb/VNCServerST.cxx
@@ -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();
+ }
}
}
diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h
index fd20cc37..159e3a4b 100644
--- a/common/rfb/VNCServerST.h
+++ b/common/rfb/VNCServerST.h
@@ -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);
diff --git a/common/rfb/encodings.h b/common/rfb/encodings.h
index cf0c8572..f7ad7890 100644
--- a/common/rfb/encodings.h
+++ b/common/rfb/encodings.h
@@ -61,6 +61,7 @@ namespace rfb {
// VMware-specific
const int pseudoEncodingVMwareCursor = 0x574d5664;
+ const int pseudoEncodingVMwareCursorPosition = 0x574d5666;
const int pseudoEncodingVMwareLEDState = 0x574d5668;
// UltraVNC-specific
diff --git a/tests/perf/decperf.cxx b/tests/perf/decperf.cxx
index a6c65a22..23f3fe24 100644
--- a/tests/perf/decperf.cxx
+++ b/tests/perf/decperf.cxx
@@ -66,6 +66,7 @@ public:
virtual void initDone();
virtual void setPixelFormat(const rfb::PixelFormat& pf);
virtual void setCursor(int, int, const rfb::Point&, const rdr::U8*);
+ virtual void setCursorPos(const rfb::Point&);
virtual void framebufferUpdateStart();
virtual void framebufferUpdateEnd();
virtual void setColourMapEntries(int, int, rdr::U16*);
@@ -144,6 +145,10 @@ void CConn::setCursor(int, int, const rfb::Point&, const rdr::U8*)
{
}
+void CConn::setCursorPos(const rfb::Point&)
+{
+}
+
void CConn::framebufferUpdateStart()
{
CConnection::framebufferUpdateStart();
diff --git a/tests/perf/encperf.cxx b/tests/perf/encperf.cxx
index 9f30cab7..69121ffa 100644
--- a/tests/perf/encperf.cxx
+++ b/tests/perf/encperf.cxx
@@ -95,6 +95,7 @@ public:
virtual void initDone() {};
virtual void resizeFramebuffer();
virtual void setCursor(int, int, const rfb::Point&, const rdr::U8*);
+ virtual void setCursorPos(const rfb::Point&);
virtual void framebufferUpdateStart();
virtual void framebufferUpdateEnd();
virtual bool dataRect(const rfb::Rect&, int);
@@ -216,6 +217,10 @@ void CConn::setCursor(int, int, const rfb::Point&, const rdr::U8*)
{
}
+void CConn::setCursorPos(const rfb::Point&)
+{
+}
+
void CConn::framebufferUpdateStart()
{
CConnection::framebufferUpdateStart();
diff --git a/unix/x0vncserver/XDesktop.cxx b/unix/x0vncserver/XDesktop.cxx
index eb36467e..e8e74fa7 100644
--- a/unix/x0vncserver/XDesktop.cxx
+++ b/unix/x0vncserver/XDesktop.cxx
@@ -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);
}
}
diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc
index 6f707299..7ebad353 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.cc
+++ b/unix/xserver/hw/vnc/XserverDesktop.cc
@@ -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 {
@@ -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
diff --git a/unix/xserver/hw/vnc/XserverDesktop.h b/unix/xserver/hw/vnc/XserverDesktop.h
index cc50f9e9..383e0bbf 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.h
+++ b/unix/xserver/hw/vnc/XserverDesktop.h
@@ -67,6 +67,7 @@ public:
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);
diff --git a/unix/xserver/hw/vnc/vncExtInit.cc b/unix/xserver/hw/vnc/vncExtInit.cc
index a45c5bde..6c4612d1 100644
--- a/unix/xserver/hw/vnc/vncExtInit.cc
+++ b/unix/xserver/hw/vnc/vncExtInit.cc
@@ -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
diff --git a/unix/xserver/hw/vnc/vncExtInit.h b/unix/xserver/hw/vnc/vncExtInit.h
index 23c0c669..36e52032 100644
--- a/unix/xserver/hw/vnc/vncExtInit.h
+++ b/unix/xserver/hw/vnc/vncExtInit.h
@@ -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);
diff --git a/unix/xserver/hw/vnc/vncHooks.c b/unix/xserver/hw/vnc/vncHooks.c
index a8ab917b..d206e342 100644
--- a/unix/xserver/hw/vnc/vncHooks.c
+++ b/unix/xserver/hw/vnc/vncHooks.c
@@ -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;
@@ -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);
@@ -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);
@@ -631,6 +643,20 @@ out:
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.
diff --git a/vncviewer/CConn.cxx b/vncviewer/CConn.cxx
index 4894ddf7..e1f5f70a 100644
--- a/vncviewer/CConn.cxx
+++ b/vncviewer/CConn.cxx
@@ -84,6 +84,7 @@ CConn::CConn(const char* vncServerName, network::Socket* socket=NULL)
sock = socket;
supportsLocalCursor = true;
+ supportsCursorPosition = true;
supportsDesktopResize = true;
supportsLEDState = false;
@@ -430,6 +431,11 @@ void CConn::setCursor(int width, int height, const Point& hotspot,
desktop->setCursor(width, height, hotspot, data);
}
+void CConn::setCursorPos(const Point& pos)
+{
+ desktop->setCursorPos(pos);
+}
+
void CConn::fence(rdr::U32 flags, unsigned len, const char data[])
{
CMsgHandler::fence(flags, len, data);
diff --git a/vncviewer/CConn.h b/vncviewer/CConn.h
index ad3fb797..e662ec87 100644
--- a/vncviewer/CConn.h
+++ b/vncviewer/CConn.h
@@ -63,6 +63,7 @@ public:
void setCursor(int width, int height, const rfb::Point& hotspot,
const rdr::U8* data);
+ void setCursorPos(const rfb::Point& pos);
void fence(rdr::U32 flags, unsigned len, const char data[]);
diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx
index 6dc85f4a..5401b191 100644
--- a/vncviewer/DesktopWindow.cxx
+++ b/vncviewer/DesktopWindow.cxx
@@ -51,6 +51,7 @@
#ifdef __APPLE__
#include "cocoa.h"
+#include <Carbon/Carbon.h>
#endif
#define EDGE_SCROLL_SIZE 32
@@ -186,6 +187,14 @@ DesktopWindow::DesktopWindow(int w, int h, const char *name,
// Show hint about menu key
Fl::add_timeout(0.5, menuOverlay, this);
+
+ // By default we get a slight delay when we warp the pointer, something
+ // we don't want or we'll get jerky movement
+#ifdef __APPLE__
+ CGEventSourceRef event = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState);
+ CGEventSourceSetLocalEventsSuppressionInterval(event, 0);
+ CFRelease(event);
+#endif
}
@@ -322,6 +331,29 @@ void DesktopWindow::setCursor(int width, int height,
}
+void DesktopWindow::setCursorPos(const rfb::Point& pos)
+{
+ if (!mouseGrabbed) {
+ // Do nothing if we do not have the mouse captured.
+ return;
+ }
+#if defined(WIN32)
+ SetCursorPos(pos.x + x_root() + viewport->x(),
+ pos.y + y_root() + viewport->y());
+#elif defined(__APPLE__)
+ CGPoint new_pos;
+ new_pos.x = pos.x + x_root() + viewport->x();
+ new_pos.y = pos.y + y_root() + viewport->y();
+ CGWarpMouseCursorPosition(new_pos);
+#else // Assume this is Xlib
+ Window rootwindow = DefaultRootWindow(fl_display);
+ XWarpPointer(fl_display, rootwindow, rootwindow, 0, 0, 0, 0,
+ pos.x + x_root() + viewport->x(),
+ pos.y + y_root() + viewport->y());
+#endif
+}
+
+
void DesktopWindow::show()
{
Fl_Window::show();
diff --git a/vncviewer/DesktopWindow.h b/vncviewer/DesktopWindow.h
index ef3dbb08..67be6c6a 100644
--- a/vncviewer/DesktopWindow.h
+++ b/vncviewer/DesktopWindow.h
@@ -66,6 +66,9 @@ public:
void setCursor(int width, int height, const rfb::Point& hotspot,
const rdr::U8* data);
+ // Server-provided cursor position
+ void setCursorPos(const rfb::Point& pos);
+
// Change client LED state
void setLEDState(unsigned int state);
diff --git a/win/rfb_win32/SDisplay.cxx b/win/rfb_win32/SDisplay.cxx
index 06eccd9a..a9ee3615 100644
--- a/win/rfb_win32/SDisplay.cxx
+++ b/win/rfb_win32/SDisplay.cxx
@@ -417,7 +417,7 @@ SDisplay::processEvent(HANDLE event) {
// Update the cursor position
// NB: First translate from Screen coordinates to Desktop
Point desktopPos = info.position.translate(screenRect.tl.negate());
- server->setCursorPos(desktopPos);
+ server->setCursorPos(desktopPos, false);
old_cursor = info;
}