diff --git a/common/rfb/CConnection.cxx b/common/rfb/CConnection.cxx index 9a9593e289..1c9490095c 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 deab50ae52..d5d07ca0b0 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 5b14806ad1..43d8df246a 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 40fb5912a1..3620d76c80 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/tests/perf/decperf.cxx b/tests/perf/decperf.cxx index a6c65a221d..23f3fe24a3 100644 --- a/tests/perf/decperf.cxx +++ b/tests/perf/decperf.cxx @@ -66,6 +66,7 @@ class CConn : public rfb::CConnection { 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 9f30cab7ab..69121ffa4d 100644 --- a/tests/perf/encperf.cxx +++ b/tests/perf/encperf.cxx @@ -95,6 +95,7 @@ class CConn : public rfb::CConnection { 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/vncviewer/CConn.cxx b/vncviewer/CConn.cxx index 4894ddf78e..e1f5f70a27 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 ad3fb797bb..e662ec8726 100644 --- a/vncviewer/CConn.h +++ b/vncviewer/CConn.h @@ -63,6 +63,7 @@ class CConn : public rfb::CConnection 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 6dc85f4a9e..34c1f7d51b 100644 --- a/vncviewer/DesktopWindow.cxx +++ b/vncviewer/DesktopWindow.cxx @@ -322,6 +322,27 @@ 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, pos.y); +#elif defined(__APPLE__) + CGPoint new_pos; + new_pos.x = pos.x; + new_pos.y = pos.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, pos.y); +#endif +} + + void DesktopWindow::show() { Fl_Window::show(); diff --git a/vncviewer/DesktopWindow.h b/vncviewer/DesktopWindow.h index ef3dbb08ec..67be6c6a88 100644 --- a/vncviewer/DesktopWindow.h +++ b/vncviewer/DesktopWindow.h @@ -66,6 +66,9 @@ class DesktopWindow : public Fl_Window { 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);