diff --git a/client/CClient.cpp b/client/CClient.cpp index 5e452909..1206176d 100644 --- a/client/CClient.cpp +++ b/client/CClient.cpp @@ -557,13 +557,13 @@ CClient::onQueryInfo() void CClient::onQueryInfoNoLock() { - SInt32 x, y, w, h; - m_screen->getMousePos(&x, &y); - m_screen->getSize(&w, &h); + SInt32 mx, my, x, y, w, h; + m_screen->getMousePos(mx, my); + m_screen->getShape(x, y, w, h); SInt32 zoneSize = m_screen->getJumpZoneSize(); - log((CLOG_DEBUG1 "sending info size=%d,%d zone=%d pos=%d,%d", w, h, zoneSize, x, y)); - CProtocolUtil::writef(m_output, kMsgDInfo, w, h, zoneSize, x, y); + log((CLOG_DEBUG1 "sending info shape=%d,%d %dx%d zone=%d pos=%d,%d", x, y, w, h, zoneSize, mx, my)); + CProtocolUtil::writef(m_output, kMsgDInfo, x, y, w, h, zoneSize, mx, my); } void diff --git a/client/CMSWindowsSecondaryScreen.cpp b/client/CMSWindowsSecondaryScreen.cpp index 9e7c14ef..dec2e2f9 100644 --- a/client/CMSWindowsSecondaryScreen.cpp +++ b/client/CMSWindowsSecondaryScreen.cpp @@ -339,11 +339,11 @@ CMSWindowsSecondaryScreen::mouseMove(SInt32 x, SInt32 y) assert(m_window != NULL); syncDesktop(); - SInt32 w, h; - getScreenSize(&w, &h); + SInt32 x0, y0, w, h; + getScreenShape(x0, y0, w, h); mouse_event(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE, - (SInt32)(65535.99 * x / (w - 1)), - (SInt32)(65535.99 * y / (h - 1)), + (SInt32)(65535.99 * x / (w - 1)) + x0, + (SInt32)(65535.99 * y / (h - 1)) + y0, 0, 0); } @@ -381,30 +381,28 @@ CMSWindowsSecondaryScreen::grabClipboard(ClipboardID /*id*/) } void -CMSWindowsSecondaryScreen::getMousePos(SInt32* x, SInt32* y) const +CMSWindowsSecondaryScreen::getMousePos(SInt32& x, SInt32& y) const { - assert(x != NULL); - assert(y != NULL); - CLock lock(&m_mutex); assert(m_window != NULL); syncDesktop(); POINT pos; if (GetCursorPos(&pos)) { - *x = pos.x; - *y = pos.y; + x = pos.x; + y = pos.y; } else { - *x = 0; - *y = 0; + x = 0; + y = 0; } } void -CMSWindowsSecondaryScreen::getSize(SInt32* width, SInt32* height) const +CMSWindowsSecondaryScreen::getShape( + SInt32& x, SInt32& y, SInt32& w, SInt32& h) const { - getScreenSize(width, height); + getScreenShape(x, y, w, h); } SInt32 @@ -547,7 +545,7 @@ CMSWindowsSecondaryScreen::onEvent(HWND hwnd, UINT msg, case WM_DISPLAYCHANGE: // screen resolution has changed - updateScreenSize(); + updateScreenShape(); m_client->onResolutionChanged(); return 0; } @@ -559,11 +557,11 @@ void CMSWindowsSecondaryScreen::onEnter(SInt32 x, SInt32 y) { // warp to requested location - SInt32 w, h; - getScreenSize(&w, &h); + SInt32 x0, y0, w, h; + getScreenShape(x0, y0, w, h); mouse_event(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE, - (DWORD)((65535.99 * x) / (w - 1)), - (DWORD)((65535.99 * y) / (h - 1)), + (DWORD)((65535.99 * x) / (w - 1)) + x0, + (DWORD)((65535.99 * y) / (h - 1)) + y0, 0, 0); // show cursor diff --git a/client/CMSWindowsSecondaryScreen.h b/client/CMSWindowsSecondaryScreen.h index 084ed47c..e845d49a 100644 --- a/client/CMSWindowsSecondaryScreen.h +++ b/client/CMSWindowsSecondaryScreen.h @@ -30,8 +30,8 @@ public: virtual void mouseWheel(SInt32 delta); virtual void setClipboard(ClipboardID, const IClipboard*); virtual void grabClipboard(ClipboardID); - virtual void getMousePos(SInt32* x, SInt32* y) const; - virtual void getSize(SInt32* width, SInt32* height) const; + virtual void getMousePos(SInt32& x, SInt32& y) const; + virtual void getShape(SInt32&, SInt32&, SInt32&, SInt32&) const; virtual SInt32 getJumpZoneSize() const; virtual void getClipboard(ClipboardID, IClipboard*) const; diff --git a/client/CXWindowsSecondaryScreen.cpp b/client/CXWindowsSecondaryScreen.cpp index 90b14a0a..60b0c0dc 100644 --- a/client/CXWindowsSecondaryScreen.cpp +++ b/client/CXWindowsSecondaryScreen.cpp @@ -287,7 +287,7 @@ CXWindowsSecondaryScreen::grabClipboard(ClipboardID id) } void -CXWindowsSecondaryScreen::getMousePos(SInt32* x, SInt32* y) const +CXWindowsSecondaryScreen::getMousePos(SInt32& x, SInt32& y) const { CDisplayLock display(this); int xTmp, yTmp, dummy; @@ -295,14 +295,15 @@ CXWindowsSecondaryScreen::getMousePos(SInt32* x, SInt32* y) const Window dummyWindow; XQueryPointer(display, getRoot(), &dummyWindow, &dummyWindow, &xTmp, &yTmp, &dummy, &dummy, &dummyMask); - *x = xTmp; - *y = yTmp; + x = xTmp; + y = yTmp; } void -CXWindowsSecondaryScreen::getSize(SInt32* width, SInt32* height) const +CXWindowsSecondaryScreen::getShape( + SInt32& x, SInt32& y, SInt32& w, SInt32& h) const { - getScreenSize(width, height); + getScreenShape(x, y, w, h); } SInt32 diff --git a/client/CXWindowsSecondaryScreen.h b/client/CXWindowsSecondaryScreen.h index 77ebf158..296cc13e 100644 --- a/client/CXWindowsSecondaryScreen.h +++ b/client/CXWindowsSecondaryScreen.h @@ -29,8 +29,8 @@ public: virtual void mouseWheel(SInt32 delta); virtual void setClipboard(ClipboardID, const IClipboard*); virtual void grabClipboard(ClipboardID); - virtual void getMousePos(SInt32* x, SInt32* y) const; - virtual void getSize(SInt32* width, SInt32* height) const; + virtual void getMousePos(SInt32& x, SInt32& y) const; + virtual void getShape(SInt32&, SInt32&, SInt32&, SInt32&) const; virtual SInt32 getJumpZoneSize() const; virtual void getClipboard(ClipboardID, IClipboard*) const; diff --git a/platform/CMSWindowsScreen.cpp b/platform/CMSWindowsScreen.cpp index f5309074..c3c08105 100644 --- a/platform/CMSWindowsScreen.cpp +++ b/platform/CMSWindowsScreen.cpp @@ -6,6 +6,15 @@ #include "CString.h" #include +// +// add backwards compatible multihead support (suppress bogus warning) +// +#pragma warning(push) +#pragma warning(disable: 4706) // assignment within conditional +#define COMPILE_MULTIMON_STUBS +#include +#pragma warning(pop) + // // CMSWindowsScreen // @@ -16,6 +25,7 @@ CMSWindowsScreen* CMSWindowsScreen::s_screen = NULL; CMSWindowsScreen::CMSWindowsScreen() : m_class(0), m_cursor(NULL), + m_x(0), m_y(0), m_w(0), m_h(0), m_thread(0) { @@ -99,11 +109,8 @@ CMSWindowsScreen::openDisplay() classInfo.hIconSm = NULL; m_class = RegisterClassEx(&classInfo); - // get screen size - // FIXME -- should handle multiple screens - m_w = GetSystemMetrics(SM_CXSCREEN); - m_h = GetSystemMetrics(SM_CYSCREEN); - log((CLOG_INFO "display size: %dx%d", m_w, m_h)); + // get screen shape + updateScreenShape(); // let subclass prep display onOpenDisplay(); @@ -142,21 +149,25 @@ CMSWindowsScreen::getClass() const } void -CMSWindowsScreen::updateScreenSize() +CMSWindowsScreen::updateScreenShape() { - m_w = GetSystemMetrics(SM_CXSCREEN); - m_h = GetSystemMetrics(SM_CYSCREEN); - log((CLOG_INFO "display resize: %dx%d", m_w, m_h)); + m_x = GetSystemMetrics(SM_XVIRTUALSCREEN); + m_y = GetSystemMetrics(SM_YVIRTUALSCREEN); + m_w = GetSystemMetrics(SM_CXVIRTUALSCREEN); + m_h = GetSystemMetrics(SM_CYVIRTUALSCREEN); + log((CLOG_INFO "screen shape: %d,%d %dx%d", m_x, m_y, m_w, m_h)); } void -CMSWindowsScreen::getScreenSize(SInt32* w, SInt32* h) const +CMSWindowsScreen::getScreenShape( + SInt32& x, SInt32& y, SInt32& w, SInt32& h) const { assert(m_class != 0); - assert(w != NULL && h != NULL); - *w = m_w; - *h = m_h; + x = m_x; + y = m_y; + w = m_w; + h = m_h; } HDESK diff --git a/platform/CMSWindowsScreen.h b/platform/CMSWindowsScreen.h index 00c05dda..85dc91bb 100644 --- a/platform/CMSWindowsScreen.h +++ b/platform/CMSWindowsScreen.h @@ -44,10 +44,11 @@ protected: ATOM getClass() const; // update screen size cache - void updateScreenSize(); + void updateScreenShape(); // get the size of the screen - void getScreenSize(SInt32* w, SInt32* h) const; + void getScreenShape(SInt32& x, SInt32& y, + SInt32& width, SInt32& height) const; // get the input desktop. caller must CloseDesktop() the result. // do not call under windows 95/98/me. @@ -87,6 +88,7 @@ private: ATOM m_class; HICON m_icon; HCURSOR m_cursor; + SInt32 m_x, m_y; SInt32 m_w, m_h; DWORD m_thread; static CMSWindowsScreen* s_screen; diff --git a/platform/CXWindowsScreen.cpp b/platform/CXWindowsScreen.cpp index fc8d0156..c314c6ea 100644 --- a/platform/CXWindowsScreen.cpp +++ b/platform/CXWindowsScreen.cpp @@ -19,6 +19,7 @@ CXWindowsScreen* CXWindowsScreen::s_screen = NULL; CXWindowsScreen::CXWindowsScreen() : m_display(NULL), m_root(None), + m_x(0), m_y(0), m_w(0), m_h(0), m_stop(false) { @@ -59,10 +60,12 @@ CXWindowsScreen::openDisplay() m_screen = DefaultScreen(m_display); Screen* screen = ScreenOfDisplay(m_display, m_screen); - // get screen size + // get screen shape + m_x = 0; + m_y = 0; m_w = WidthOfScreen(screen); m_h = HeightOfScreen(screen); - log((CLOG_INFO "display size: %dx%d", m_w, m_h)); + log((CLOG_INFO "screen shape: %d,%d %dx%d", m_x, m_y, m_w, m_h)); // get the root window m_root = RootWindow(m_display, m_screen); @@ -113,13 +116,15 @@ CXWindowsScreen::getRoot() const } void -CXWindowsScreen::getScreenSize(SInt32* w, SInt32* h) const +CXWindowsScreen::getScreenShape( + SInt32& x, SInt32& y, SInt32& w, SInt32& h) const { assert(m_display != NULL); - assert(w != NULL && h != NULL); - *w = m_w; - *h = m_h; + x = m_x; + y = m_y; + w = m_w; + h = m_h; } Cursor diff --git a/platform/CXWindowsScreen.h b/platform/CXWindowsScreen.h index b589aba6..074411bb 100644 --- a/platform/CXWindowsScreen.h +++ b/platform/CXWindowsScreen.h @@ -41,12 +41,13 @@ protected: // is closed. void closeDisplay(); - // get the opened screen, its size, its root window. to get the + // get the opened screen, its shape, its root window. to get the // display create a CDisplayLock object passing this. while the // object exists no other threads may access the display. do not // save the Display* beyond the lifetime of the CDisplayLock. int getScreen() const; - void getScreenSize(SInt32* w, SInt32* h) const; + void getScreenShape( + SInt32& x, SInt32& y, SInt32& w, SInt32& h) const; Window getRoot() const; // create a cursor that is transparent everywhere @@ -108,6 +109,7 @@ private: Display* m_display; int m_screen; Window m_root; + SInt32 m_x, m_y; SInt32 m_w, m_h; bool m_stop; diff --git a/server/CMSWindowsPrimaryScreen.cpp b/server/CMSWindowsPrimaryScreen.cpp index 394c1a42..26915d71 100644 --- a/server/CMSWindowsPrimaryScreen.cpp +++ b/server/CMSWindowsPrimaryScreen.cpp @@ -111,15 +111,15 @@ CMSWindowsPrimaryScreen::open(CServer* server) nextMark(); // send screen info - SInt32 w, h; - getScreenSize(&w, &h); + SInt32 x, y, w, h; + getScreenShape(x, y, w, h); POINT pos; GetCursorPos(&pos); - m_server->setInfo(w, h, getJumpZoneSize(), pos.x, pos.y); + m_server->setInfo(x, y, w, h, getJumpZoneSize(), pos.x, pos.y); - // compute center pixel of screen - m_xCenter = w >> 1; - m_yCenter = h >> 1; + // compute center pixel of primary screen + m_xCenter = GetSystemMetrics(SM_CXSCREEN) >> 1; + m_yCenter = GetSystemMetrics(SM_CYSCREEN) >> 1; // get keyboard state updateKeys(); @@ -228,10 +228,10 @@ void CMSWindowsPrimaryScreen::onConfigure() { if ((m_is95Family || m_desk != NULL) && !m_active) { - SInt32 w, h; - getScreenSize(&w, &h); + SInt32 x, y, w, h; + getScreenShape(x, y, w, h); m_setZone(m_server->getActivePrimarySides(), - w, h, getJumpZoneSize()); + x, y, w, h, getJumpZoneSize()); } } @@ -264,9 +264,10 @@ CMSWindowsPrimaryScreen::grabClipboard(ClipboardID /*id*/) } void -CMSWindowsPrimaryScreen::getSize(SInt32* width, SInt32* height) const +CMSWindowsPrimaryScreen::getShape( + SInt32& x, SInt32& y, SInt32& w, SInt32& h) const { - getScreenSize(width, height); + getScreenShape(x, y, w, h); } SInt32 @@ -551,17 +552,17 @@ CMSWindowsPrimaryScreen::onEvent(HWND hwnd, UINT msg, case WM_DISPLAYCHANGE: { // screen resolution may have changed - SInt32 wOld, hOld; - getScreenSize(&wOld, &hOld); - SInt32 w, h; - updateScreenSize(); - getScreenSize(&w, &h); + SInt32 xOld, yOld, wOld, hOld; + getScreenShape(xOld, yOld, wOld, hOld); + updateScreenShape(); + SInt32 x, y, w, h; + getScreenShape(x, y, w, h); // do nothing if resolution hasn't changed - if (w != wOld || h != hOld) { - // recompute center pixel of screen - m_xCenter = w >> 1; - m_yCenter = h >> 1; + if (x != xOld || y != yOld || w != wOld || h != hOld) { + // recompute center pixel of primary screen + m_xCenter = GetSystemMetrics(SM_CXSCREEN) >> 1; + m_yCenter = GetSystemMetrics(SM_CYSCREEN) >> 1; // warp mouse to center if active if (m_active) { @@ -576,7 +577,7 @@ CMSWindowsPrimaryScreen::onEvent(HWND hwnd, UINT msg, // send new screen info POINT pos; GetCursorPos(&pos); - m_server->setInfo(w, h, getJumpZoneSize(), pos.x, pos.y); + m_server->setInfo(x, y, w, h, getJumpZoneSize(), pos.x, pos.y); } return 0; @@ -682,8 +683,8 @@ CMSWindowsPrimaryScreen::openDesktop() // with losing keyboard input (focus?) in that case. // unfortunately, hiding the full screen window (when entering // the scren causes all other windows to redraw). - SInt32 w, h; - getScreenSize(&w, &h); + SInt32 x, y, w, h; + getScreenShape(x, y, w, h); // create the window m_window = CreateWindowEx(WS_EX_TOPMOST | @@ -692,7 +693,7 @@ CMSWindowsPrimaryScreen::openDesktop() (LPCTSTR)getClass(), "Synergy", WS_POPUP, - 0, 0, w, h, NULL, NULL, + x, y, w, h, NULL, NULL, getInstance(), NULL); if (m_window == NULL) { @@ -792,8 +793,8 @@ CMSWindowsPrimaryScreen::switchDesktop(HDESK desk) // with losing keyboard input (focus?) in that case. // unfortunately, hiding the full screen window (when entering // the scren causes all other windows to redraw). - SInt32 w, h; - getScreenSize(&w, &h); + SInt32 x, y, w, h; + getScreenShape(x, y, w, h); // create the window m_window = CreateWindowEx(WS_EX_TOPMOST | @@ -802,7 +803,7 @@ CMSWindowsPrimaryScreen::switchDesktop(HDESK desk) (LPCTSTR)getClass(), "Synergy", WS_POPUP, - 0, 0, w, h, NULL, NULL, + x, y, w, h, NULL, NULL, getInstance(), NULL); if (m_window == NULL) { diff --git a/server/CMSWindowsPrimaryScreen.h b/server/CMSWindowsPrimaryScreen.h index c026e466..22d15ac9 100644 --- a/server/CMSWindowsPrimaryScreen.h +++ b/server/CMSWindowsPrimaryScreen.h @@ -25,7 +25,7 @@ public: virtual void warpCursor(SInt32 xAbsolute, SInt32 yAbsolute); virtual void setClipboard(ClipboardID, const IClipboard*); virtual void grabClipboard(ClipboardID); - virtual void getSize(SInt32* width, SInt32* height) const; + virtual void getShape(SInt32&, SInt32&, SInt32&, SInt32&) const; virtual SInt32 getJumpZoneSize() const; virtual void getClipboard(ClipboardID, IClipboard*) const; virtual KeyModifierMask getToggleMask() const; diff --git a/server/CServer.cpp b/server/CServer.cpp index 91504f52..aca6a6c4 100644 --- a/server/CServer.cpp +++ b/server/CServer.cpp @@ -260,24 +260,27 @@ CServer::getActivePrimarySides() const } void -CServer::setInfo(SInt32 w, SInt32 h, SInt32 zoneSize, SInt32 x, SInt32 y) +CServer::setInfo(SInt32 x, SInt32 y, SInt32 w, SInt32 h, + SInt32 zoneSize, SInt32 mx, SInt32 my) { CLock lock(&m_mutex); assert(m_primaryInfo != NULL); - setInfoNoLock(m_primaryInfo->m_name, w, h, zoneSize, x, y); + setInfoNoLock(m_primaryInfo->m_name, x, y, w, h, zoneSize, mx, my); } void CServer::setInfo(const CString& client, - SInt32 w, SInt32 h, SInt32 zoneSize, SInt32 x, SInt32 y) + SInt32 x, SInt32 y, SInt32 w, SInt32 h, + SInt32 zoneSize, SInt32 mx, SInt32 my) { CLock lock(&m_mutex); - setInfoNoLock(client, w, h, zoneSize, x, y); + setInfoNoLock(client, x, y, w, h, zoneSize, mx, my); } void CServer::setInfoNoLock(const CString& screen, - SInt32 w, SInt32 h, SInt32 zoneSize, SInt32 x, SInt32 y) + SInt32 x, SInt32 y, SInt32 w, SInt32 h, + SInt32 zoneSize, SInt32 mx, SInt32 my) { assert(!screen.empty()); assert(w > 0); @@ -297,13 +300,15 @@ CServer::setInfoNoLock(const CString& screen, // update screen info if (info == m_active) { // update the remote mouse coordinates - m_x = x; - m_y = y; + m_x = mx; + m_y = my; } - info->m_width = w; - info->m_height = h; + info->m_x = x; + info->m_y = y; + info->m_w = w; + info->m_h = h; info->m_zoneSize = zoneSize; - log((CLOG_INFO "screen \"%s\" size=%dx%d zone=%d pos=%d,%d", screen.c_str(), w, h, zoneSize, x, y)); + log((CLOG_INFO "screen \"%s\" shape=%d,%d %dx%d zone=%d pos=%d,%d", screen.c_str(), x, y, w, h, zoneSize, mx, my)); // send acknowledgement (if screen isn't the primary) if (info->m_protocol != NULL) { @@ -313,7 +318,7 @@ CServer::setInfoNoLock(const CString& screen, // handle resolution change to primary screen else { if (info == m_active) { - onMouseMovePrimaryNoLock(x, y); + onMouseMovePrimaryNoLock(mx, my); } else { onMouseMoveSecondaryNoLock(0, 0); @@ -536,22 +541,22 @@ CServer::onMouseMovePrimaryNoLock(SInt32 x, SInt32 y) // see if we should change screens CConfig::EDirection dir; - if (x < m_active->m_zoneSize) { + if (x < m_active->m_x + m_active->m_zoneSize) { x -= m_active->m_zoneSize; dir = CConfig::kLeft; log((CLOG_DEBUG1 "switch to left")); } - else if (x >= m_active->m_width - m_active->m_zoneSize) { + else if (x >= m_active->m_x + m_active->m_w - m_active->m_zoneSize) { x += m_active->m_zoneSize; dir = CConfig::kRight; log((CLOG_DEBUG1 "switch to right")); } - else if (y < m_active->m_zoneSize) { + else if (y < m_active->m_y + m_active->m_zoneSize) { y -= m_active->m_zoneSize; dir = CConfig::kTop; log((CLOG_DEBUG1 "switch to top")); } - else if (y >= m_active->m_height - m_active->m_zoneSize) { + else if (y >= m_active->m_y + m_active->m_h - m_active->m_zoneSize) { y += m_active->m_zoneSize; dir = CConfig::kBottom; log((CLOG_DEBUG1 "switch to bottom")); @@ -561,17 +566,13 @@ CServer::onMouseMovePrimaryNoLock(SInt32 x, SInt32 y) return false; } - // get jump destination + // get jump destination and, if no screen in jump direction, + // then ignore the move. CScreenInfo* newScreen = getNeighbor(m_active, dir, x, y); - - // if no screen in jump direction then ignore the move if (newScreen == NULL) { return false; } - // remap position to account for resolution differences - mapPosition(m_active, dir, newScreen, x, y); - // switch screen switchScreen(newScreen, x, y); return true; @@ -615,16 +616,16 @@ CServer::onMouseMoveSecondaryNoLock(SInt32 dx, SInt32 dy) if (!isLockedToScreenNoLock()) { // find direction of neighbor CConfig::EDirection dir; - if (m_x < 0) { + if (m_x < m_active->m_x) { dir = CConfig::kLeft; } - else if (m_x > m_active->m_width - 1) { + else if (m_x > m_active->m_x + m_active->m_w - 1) { dir = CConfig::kRight; } - else if (m_y < 0) { + else if (m_y < m_active->m_y) { dir = CConfig::kTop; } - else if (m_y > m_active->m_height - 1) { + else if (m_y > m_active->m_y + m_active->m_h - 1) { dir = CConfig::kBottom; } else { @@ -638,39 +639,32 @@ CServer::onMouseMoveSecondaryNoLock(SInt32 dx, SInt32 dy) if (newScreen == NULL) { log((CLOG_DEBUG1 "leave \"%s\" on %s", m_active->m_name.c_str(), CConfig::dirName(dir))); - SInt32 x = m_x, y = m_y; - newScreen = getNeighbor(m_active, dir, x, y); - - // remap position to account for resolution differences - if (newScreen != NULL) { - mapPosition(m_active, dir, newScreen, x, y); - m_x = x; - m_y = y; - } - else { + // get new position or clamp to current screen + newScreen = getNeighbor(m_active, dir, m_x, m_y); + if (newScreen == NULL) { log((CLOG_DEBUG1 "no neighbor; clamping")); - if (m_x < 0) - m_x = 0; - else if (m_x > m_active->m_width - 1) - m_x = m_active->m_width - 1; - if (m_y < 0) - m_y = 0; - else if (m_y > m_active->m_height - 1) - m_y = m_active->m_height - 1; + if (m_x < m_active->m_x) + m_x = m_active->m_x; + else if (m_x > m_active->m_x + m_active->m_w - 1) + m_x = m_active->m_x + m_active->m_w - 1; + if (m_y < m_active->m_y) + m_y = m_active->m_y; + else if (m_y > m_active->m_y + m_active->m_h - 1) + m_y = m_active->m_y + m_active->m_h - 1; } } } else { // clamp to edge when locked log((CLOG_DEBUG1 "clamp to \"%s\"", m_active->m_name.c_str())); - if (m_x < 0) - m_x = 0; - else if (m_x > m_active->m_width - 1) - m_x = m_active->m_width - 1; - if (m_y < 0) - m_y = 0; - else if (m_y > m_active->m_height - 1) - m_y = m_active->m_height - 1; + if (m_x < m_active->m_x) + m_x = m_active->m_x; + else if (m_x > m_active->m_x + m_active->m_w - 1) + m_x = m_active->m_x + m_active->m_w - 1; + if (m_y < m_active->m_y) + m_y = m_active->m_y; + else if (m_y > m_active->m_y + m_active->m_h - 1) + m_y = m_active->m_y + m_active->m_h - 1; } // warp cursor if on same screen @@ -729,7 +723,8 @@ void CServer::switchScreen(CScreenInfo* dst, SInt32 x, SInt32 y) { assert(dst != NULL); - assert(x >= 0 && y >= 0 && x < dst->m_width && y < dst->m_height); + assert(x >= dst->m_x && y >= dst->m_y); + assert(x < dst->m_x + dst->m_w && y < dst->m_y + dst->m_h); assert(m_active != NULL); log((CLOG_INFO "switch from \"%s\" to \"%s\" at %d,%d", m_active->m_name.c_str(), dst->m_name.c_str(), x, y)); @@ -832,22 +827,27 @@ CServer::getNeighbor(CScreenInfo* src, assert(src != NULL); // get the first neighbor - CScreenInfo* lastGoodScreen = src; CScreenInfo* dst = getNeighbor(src, srcSide); if (dst == NULL) { return NULL; } // get the source screen's size (needed for kRight and kBottom) - SInt32 w = src->m_width, h = src->m_height; + SInt32 w = src->m_w, h = src->m_h; - // find destination screen, adjusting x or y (but not both) + // find destination screen, adjusting x or y (but not both). the + // searches are done in a sort of canonical screen space where + // the upper-left corner is 0,0 for each screen. we adjust from + // actual to canonical position on entry to and from canonical to + // actual on exit from the search. + CScreenInfo* lastGoodScreen = src; switch (srcSide) { case CConfig::kLeft: + x -= src->m_x; while (dst != NULL && dst != lastGoodScreen) { lastGoodScreen = dst; - w = lastGoodScreen->m_width; - h = lastGoodScreen->m_height; + w = lastGoodScreen->m_w; + h = lastGoodScreen->m_h; x += w; if (x >= 0) { break; @@ -855,27 +855,33 @@ CServer::getNeighbor(CScreenInfo* src, log((CLOG_DEBUG2 "skipping over screen %s", dst->m_name.c_str())); dst = getNeighbor(lastGoodScreen, srcSide); } + assert(lastGoodScreen != NULL); + x += lastGoodScreen->m_x; break; case CConfig::kRight: + x -= src->m_x; while (dst != NULL) { lastGoodScreen = dst; x -= w; - w = lastGoodScreen->m_width; - h = lastGoodScreen->m_height; + w = lastGoodScreen->m_w; + h = lastGoodScreen->m_h; if (x < w) { break; } log((CLOG_DEBUG2 "skipping over screen %s", dst->m_name.c_str())); dst = getNeighbor(lastGoodScreen, srcSide); } + assert(lastGoodScreen != NULL); + x += lastGoodScreen->m_x; break; case CConfig::kTop: + y -= src->m_y; while (dst != NULL) { lastGoodScreen = dst; - w = lastGoodScreen->m_width; - h = lastGoodScreen->m_height; + w = lastGoodScreen->m_w; + h = lastGoodScreen->m_h; y += h; if (y >= 0) { break; @@ -883,106 +889,108 @@ CServer::getNeighbor(CScreenInfo* src, log((CLOG_DEBUG2 "skipping over screen %s", dst->m_name.c_str())); dst = getNeighbor(lastGoodScreen, srcSide); } + assert(lastGoodScreen != NULL); + y += lastGoodScreen->m_y; break; case CConfig::kBottom: + y -= src->m_y; while (dst != NULL) { lastGoodScreen = dst; y -= h; - w = lastGoodScreen->m_width; - h = lastGoodScreen->m_height; + w = lastGoodScreen->m_w; + h = lastGoodScreen->m_h; if (y < h) { break; } log((CLOG_DEBUG2 "skipping over screen %s", dst->m_name.c_str())); dst = getNeighbor(lastGoodScreen, srcSide); } + assert(lastGoodScreen != NULL); + y += lastGoodScreen->m_y; break; } - assert(lastGoodScreen != NULL); -/* allow screen to be it's own neighbor to allow wrapping - // no neighbor if best neighbor is the source itself - if (lastGoodScreen == src) - return NULL; -*/ + // save destination screen + assert(lastGoodScreen != NULL); + dst = lastGoodScreen; // if entering primary screen then be sure to move in far enough // to avoid the jump zone. if entering a side that doesn't have // a neighbor (i.e. an asymmetrical side) then we don't need to // move inwards because that side can't provoke a jump. - if (lastGoodScreen->m_protocol == NULL) { - const CString dstName(lastGoodScreen->m_name); + if (dst->m_protocol == NULL) { + const CString dstName(dst->m_name); switch (srcSide) { case CConfig::kLeft: if (!m_config.getNeighbor(dstName, CConfig::kRight).empty() && - x > w - 1 - lastGoodScreen->m_zoneSize) - x = w - 1 - lastGoodScreen->m_zoneSize; + x > dst->m_x + w - 1 - dst->m_zoneSize) + x = dst->m_x + w - 1 - dst->m_zoneSize; break; case CConfig::kRight: if (!m_config.getNeighbor(dstName, CConfig::kLeft).empty() && - x < lastGoodScreen->m_zoneSize) - x = lastGoodScreen->m_zoneSize; + x < dst->m_x + dst->m_zoneSize) + x = dst->m_x + dst->m_zoneSize; break; case CConfig::kTop: if (!m_config.getNeighbor(dstName, CConfig::kBottom).empty() && - y > h - 1 - lastGoodScreen->m_zoneSize) - y = h - 1 - lastGoodScreen->m_zoneSize; + y > dst->m_y + h - 1 - dst->m_zoneSize) + y = dst->m_y + h - 1 - dst->m_zoneSize; break; case CConfig::kBottom: if (!m_config.getNeighbor(dstName, CConfig::kTop).empty() && - y < lastGoodScreen->m_zoneSize) - y = lastGoodScreen->m_zoneSize; + y < dst->m_y + dst->m_zoneSize) + y = dst->m_y + dst->m_zoneSize; break; } } - return lastGoodScreen; -} - -void -CServer::mapPosition(CScreenInfo* src, CConfig::EDirection srcSide, - CScreenInfo* dst, SInt32& x, SInt32& y) const -{ - assert(src != NULL); - assert(dst != NULL); - assert(srcSide >= CConfig::kFirstDirection && - srcSide <= CConfig::kLastDirection); - + // adjust the coordinate orthogonal to srcSide to account for + // resolution differences. for example, if y is 200 pixels from + // the top on a screen 1000 pixels high (20% from the top) when + // we cross the left edge onto a screen 600 pixels high then y + // should be set 120 pixels from the top (again 20% from the + // top). switch (srcSide) { case CConfig::kLeft: case CConfig::kRight: + y -= src->m_y; if (y < 0) { y = 0; } - else if (y >= src->m_height) { - y = dst->m_height - 1; + else if (y >= src->m_h) { + y = dst->m_h - 1; } else { y = static_cast(0.5 + y * - static_cast(dst->m_height - 1) / - (src->m_height - 1)); + static_cast(dst->m_h - 1) / + (src->m_h - 1)); } + y += dst->m_y; break; case CConfig::kTop: case CConfig::kBottom: + x -= src->m_x; if (x < 0) { x = 0; } - else if (x >= src->m_width) { - x = dst->m_width - 1; + else if (x >= src->m_w) { + x = dst->m_w - 1; } else { x = static_cast(0.5 + x * - static_cast(dst->m_width - 1) / - (src->m_width - 1)); + static_cast(dst->m_w - 1) / + (src->m_w - 1)); } + x += dst->m_x; break; } + + return dst; } #include "CTCPListenSocket.h" @@ -1536,8 +1544,8 @@ CServer::removeConnection(const CString& name) // if this is active screen then we have to jump off of it if (m_active == index->second && m_active != m_primaryInfo) { // record new position (center of primary screen) - m_x = m_primaryInfo->m_width >> 1; - m_y = m_primaryInfo->m_height >> 1; + m_x = m_primaryInfo->m_x + (m_primaryInfo->m_w >> 1); + m_y = m_primaryInfo->m_y + (m_primaryInfo->m_h >> 1); // don't notify active screen since it probably already disconnected log((CLOG_INFO "jump from \"%s\" to \"%s\" at %d,%d", m_active->m_name.c_str(), m_primaryInfo->m_name.c_str(), m_x, m_y)); @@ -1601,8 +1609,10 @@ CServer::CScreenInfo::CScreenInfo(const CString& name, m_name(name), m_protocol(protocol), m_ready(false), - m_width(0), - m_height(0), + m_x(0), + m_y(0), + m_w(0), + m_h(0), m_zoneSize(0) { for (ClipboardID id = 0; id < kClipboardEnd; ++id) diff --git a/server/CServer.h b/server/CServer.h index c68a71a5..318ec4a7 100644 --- a/server/CServer.h +++ b/server/CServer.h @@ -55,12 +55,14 @@ public: void grabClipboard(ClipboardID); // handle updates from primary - void setInfo(SInt32 wScreen, SInt32 hScreen, + void setInfo(SInt32 xScreen, SInt32 yScreen, + SInt32 wScreen, SInt32 hScreen, SInt32 zoneSize, SInt32 xMouse, SInt32 yMouse); // handle messages from clients void setInfo(const CString& clientName, + SInt32 xScreen, SInt32 yScreen, SInt32 wScreen, SInt32 hScreen, SInt32 zoneSize, SInt32 xMouse, SInt32 yMouse); @@ -119,8 +121,12 @@ private: CString m_name; IServerProtocol* m_protocol; bool m_ready; - SInt32 m_width, m_height; + + // screen shape and jump zone size + SInt32 m_x, m_y; + SInt32 m_w, m_h; SInt32 m_zoneSize; + bool m_gotClipboard[kClipboardEnd]; }; @@ -130,6 +136,7 @@ private: // update screen info void setInfoNoLock(const CString& screenName, + SInt32 xScreen, SInt32 yScreen, SInt32 wScreen, SInt32 hScreen, SInt32 zoneSize, SInt32 xMouse, SInt32 yMouse); @@ -150,19 +157,12 @@ private: // lookup neighboring screen. given a position relative to the // source screen, find the screen we should move onto and where. // if the position is sufficiently far from the source then we - // cross multiple screens. + // cross multiple screens. if there is no suitable screen then + // return NULL and x,y are not modified. CScreenInfo* getNeighbor(CScreenInfo*, CConfig::EDirection, SInt32& x, SInt32& y) const; - // adjust coordinates to account for resolution differences. the - // position is converted to a resolution independent form then - // converted back to screen coordinates on the destination screen. - void mapPosition(CScreenInfo* src, - CConfig::EDirection srcSide, - CScreenInfo* dst, - SInt32& x, SInt32& y) const; - // open/close the primary screen void openPrimaryScreen(); void closePrimaryScreen(); diff --git a/server/CServerProtocol1_0.cpp b/server/CServerProtocol1_0.cpp index bfd5fef9..54eaf81e 100644 --- a/server/CServerProtocol1_0.cpp +++ b/server/CServerProtocol1_0.cpp @@ -199,21 +199,21 @@ void CServerProtocol1_0::recvInfo() { // parse the message - SInt16 x, y, w, h, zoneInfo; + SInt16 x, y, w, h, zoneInfo, mx, my; CProtocolUtil::readf(getInputStream(), kMsgDInfo + 4, - &w, &h, &zoneInfo, &x, &y); - log((CLOG_DEBUG "received client \"%s\" info size=%dx%d, zone=%d, pos=%d,%d", getClient().c_str(), w, h, zoneInfo, x, y)); + &x, &y, &w, &h, &zoneInfo, &mx, &my); + log((CLOG_DEBUG "received client \"%s\" info shape=%d,%d %dx%d, zone=%d, pos=%d,%d", getClient().c_str(), x, y, w, h, zoneInfo, mx, my)); // validate if (w <= 0 || h <= 0 || zoneInfo < 0) { throw XBadClient(); } - if (x < 0 || y < 0 || x >= w || y >= h) { + if (mx < x || my < y || mx >= x + w || my >= y + h) { throw XBadClient(); } // tell server of change - getServer()->setInfo(getClient(), w, h, zoneInfo, x, y); + getServer()->setInfo(getClient(), x, y, w, h, zoneInfo, mx, my); } void diff --git a/server/CSynergyHook.cpp b/server/CSynergyHook.cpp index f834f413..23d0cf62 100644 --- a/server/CSynergyHook.cpp +++ b/server/CSynergyHook.cpp @@ -48,6 +48,8 @@ static HHOOK g_keyboardLL = NULL; static bool g_relay = false; static SInt32 g_zoneSize = 0; static UInt32 g_zoneSides = 0; +static SInt32 g_xScreen = 0; +static SInt32 g_yScreen = 0; static SInt32 g_wScreen = 0; static SInt32 g_hScreen = 0; static HCURSOR g_cursor = NULL; @@ -196,16 +198,16 @@ mouseHook(int code, WPARAM wParam, LPARAM lParam) SInt32 x = (SInt32)info->pt.x; SInt32 y = (SInt32)info->pt.y; if (!inside && (g_zoneSides & CConfig::kLeftMask) != 0) { - inside = (x < g_zoneSize); + inside = (x < g_xScreen + g_zoneSize); } if (!inside && (g_zoneSides & CConfig::kRightMask) != 0) { - inside = (x >= g_wScreen - g_zoneSize); + inside = (x >= g_xScreen + g_wScreen - g_zoneSize); } if (!inside && (g_zoneSides & CConfig::kTopMask) != 0) { - inside = (y < g_zoneSize); + inside = (y < g_yScreen + g_zoneSize); } if (!inside && (g_zoneSides & CConfig::kBottomMask) != 0) { - inside = (y >= g_hScreen - g_zoneSize); + inside = (y >= g_yScreen + g_hScreen - g_zoneSize); } // if inside then eat event and notify our window @@ -463,6 +465,8 @@ install(DWORD threadID) g_relay = false; g_zoneSize = 0; g_zoneSides = 0; + g_xScreen = 0; + g_yScreen = 0; g_wScreen = 0; g_hScreen = 0; g_cursor = NULL; @@ -585,10 +589,14 @@ uninstall(void) } void -setZone(UInt32 sides, SInt32 w, SInt32 h, SInt32 jumpZoneSize) +setZone(UInt32 sides, + SInt32 x, SInt32 y, SInt32 w, SInt32 h, + SInt32 jumpZoneSize) { g_zoneSize = jumpZoneSize; g_zoneSides = sides; + g_xScreen = x; + g_yScreen = y; g_wScreen = w; g_hScreen = h; g_relay = false; @@ -601,6 +609,8 @@ setRelay(void) g_relay = true; g_zoneSize = 0; g_zoneSides = 0; + g_xScreen = 0; + g_yScreen = 0; g_wScreen = 0; g_hScreen = 0; } diff --git a/server/CSynergyHook.h b/server/CSynergyHook.h index 159144c9..34078de8 100644 --- a/server/CSynergyHook.h +++ b/server/CSynergyHook.h @@ -26,13 +26,15 @@ extern "C" { typedef int (*InstallFunc)(DWORD targetQueueThreadID); typedef int (*UninstallFunc)(void); -typedef void (*SetZoneFunc)(UInt32, SInt32, SInt32, SInt32); +typedef void (*SetZoneFunc)(UInt32, + SInt32, SInt32, SInt32, SInt32, SInt32); typedef void (*SetRelayFunc)(void); CSYNERGYHOOK_API int install(DWORD); CSYNERGYHOOK_API int uninstall(void); CSYNERGYHOOK_API void setZone(UInt32 sides, - SInt32 w, SInt32 h, SInt32 jumpZoneSize); + SInt32 x, SInt32 y, SInt32 w, SInt32 h, + SInt32 jumpZoneSize); CSYNERGYHOOK_API void setRelay(void); } diff --git a/server/CXWindowsPrimaryScreen.cpp b/server/CXWindowsPrimaryScreen.cpp index c8ba3a68..d7f723c4 100644 --- a/server/CXWindowsPrimaryScreen.cpp +++ b/server/CXWindowsPrimaryScreen.cpp @@ -161,6 +161,7 @@ CXWindowsPrimaryScreen::run() // FIXME -- slurp up all remaining motion events? // probably not since keystrokes may go to wrong place. +// XXX -- why call XQueryPointer? // get mouse deltas { CDisplayLock display(this); @@ -173,8 +174,8 @@ CXWindowsPrimaryScreen::run() } // compute position of center of window - SInt32 w, h; - getScreenSize(&w, &h); + SInt32 x0, y0, w, h; + getScreenShape(x0, y0, w, h); x = xRoot - (w >> 1); y = yRoot - (h >> 1); @@ -216,11 +217,11 @@ CXWindowsPrimaryScreen::open(CServer* server) // m_numLockHalfDuplex = true; // m_capsLockHalfDuplex = true; - // get screen size - SInt32 w, h; - getScreenSize(&w, &h); + // get screen shape + SInt32 x, y, w, h; + getScreenShape(x, y, w, h); - int x, y; + int mx, my; { CDisplayLock display(this); @@ -232,14 +233,14 @@ CXWindowsPrimaryScreen::open(CServer* server) int xWindow, yWindow; unsigned int mask; if (!XQueryPointer(display, m_window, &root, &window, - &x, &y, &xWindow, &yWindow, &mask)) { - x = w >> 1; - y = h >> 1; + &mx, &my, &xWindow, &yWindow, &mask)) { + mx = w >> 1; + my = h >> 1; } } // send screen info - m_server->setInfo(w, h, getJumpZoneSize(), x, y); + m_server->setInfo(x, y, w, h, getJumpZoneSize(), mx, my); } void @@ -340,8 +341,8 @@ CXWindowsPrimaryScreen::leave() log((CLOG_DEBUG1 "grabbed pointer and keyboard")); // move the mouse to the center of grab window - SInt32 w, h; - getScreenSize(&w, &h); + SInt32 x, y, w, h; + getScreenShape(x, y, w, h); warpCursorNoLock(display, w >> 1, h >> 1); // local client now active @@ -396,9 +397,10 @@ CXWindowsPrimaryScreen::grabClipboard(ClipboardID id) } void -CXWindowsPrimaryScreen::getSize(SInt32* width, SInt32* height) const +CXWindowsPrimaryScreen::getShape( + SInt32& x, SInt32& y, SInt32& w, SInt32& h) const { - getScreenSize(width, height); + getScreenShape(x, y, w, h); } SInt32 @@ -480,8 +482,8 @@ CXWindowsPrimaryScreen::onOpenDisplay(Display* display) assert(m_window == None); // get size of screen - SInt32 w, h; - getScreenSize(&w, &h); + SInt32 x, y, w, h; + getScreenShape(x, y, w, h); // create the grab window. this window is used to capture user // input when the user is focussed on another client. don't let @@ -494,7 +496,7 @@ CXWindowsPrimaryScreen::onOpenDisplay(Display* display) attr.do_not_propagate_mask = 0; attr.override_redirect = True; attr.cursor = createBlankCursor(); - m_window = XCreateWindow(display, getRoot(), 0, 0, w, h, 0, 0, + m_window = XCreateWindow(display, getRoot(), x, y, w, h, 0, 0, InputOnly, CopyFromParent, CWDontPropagate | CWEventMask | CWOverrideRedirect | CWCursor, diff --git a/server/CXWindowsPrimaryScreen.h b/server/CXWindowsPrimaryScreen.h index fe4bbc87..13b63c11 100644 --- a/server/CXWindowsPrimaryScreen.h +++ b/server/CXWindowsPrimaryScreen.h @@ -21,7 +21,7 @@ public: virtual void warpCursor(SInt32 xAbsolute, SInt32 yAbsolute); virtual void setClipboard(ClipboardID, const IClipboard*); virtual void grabClipboard(ClipboardID); - virtual void getSize(SInt32* width, SInt32* height) const; + virtual void getShape(SInt32&, SInt32&, SInt32&, SInt32&) const; virtual SInt32 getJumpZoneSize() const; virtual void getClipboard(ClipboardID, IClipboard*) const; virtual KeyModifierMask getToggleMask() const; diff --git a/synergy/IPrimaryScreen.h b/synergy/IPrimaryScreen.h index c88207d5..0a318c14 100644 --- a/synergy/IPrimaryScreen.h +++ b/synergy/IPrimaryScreen.h @@ -79,8 +79,9 @@ public: virtual CString getName() const = 0; */ - // get the size of the screen - virtual void getSize(SInt32* width, SInt32* height) const = 0; + // get the screen region + virtual void getShape(SInt32& x, SInt32& y, + SInt32& width, SInt32& height) const = 0; // get the size of jump zone virtual SInt32 getJumpZoneSize() const = 0; diff --git a/synergy/ISecondaryScreen.h b/synergy/ISecondaryScreen.h index be709890..57091147 100644 --- a/synergy/ISecondaryScreen.h +++ b/synergy/ISecondaryScreen.h @@ -66,10 +66,11 @@ public: // accessors // get the position of the mouse on the screen - virtual void getMousePos(SInt32* x, SInt32* y) const = 0; + virtual void getMousePos(SInt32& x, SInt32& y) const = 0; // get the size of the screen - virtual void getSize(SInt32* width, SInt32* height) const = 0; + virtual void getShape(SInt32& x, SInt32& y, + SInt32& width, SInt32& height) const = 0; // get the size of jump zone virtual SInt32 getJumpZoneSize() const = 0; diff --git a/synergy/ProtocolTypes.h b/synergy/ProtocolTypes.h index b60fc831..3d2223e2 100644 --- a/synergy/ProtocolTypes.h +++ b/synergy/ProtocolTypes.h @@ -16,6 +16,10 @@ static const UInt16 kDefaultPort = 24800; // always 4 bytes optionally followed by message specific parameters. // +// +// positions and sizes are signed 16 bit integers. +// + // // command codes // @@ -101,9 +105,12 @@ static const char kMsgDMouseWheel[] = "DMWM%2i"; static const char kMsgDClipboard[] = "DCLP%1i%4i%s"; // client data: secondary -> primary -// $1 = seconary screen width in pixels, $2 = screen height, $3 = -// size of warp zone. $4 and $5 are the x,y position of the mouse -// on the secondary screen. +// $1 = coordinate of leftmost pixel on secondary screen, +// $2 = coordinate of topmost pixel on secondary screen, +// $3 = width of secondary screen in pixels, +// $4 = height of secondary screen in pixels, +// $5 = size of warp zone, +// $6, $7 = the x,y position of the mouse on the secondary screen. // // the secondary screen must send this message in response to the // kMsgQInfo message. it must also send this message when the @@ -111,7 +118,7 @@ static const char kMsgDClipboard[] = "DCLP%1i%4i%s"; // should ignore any kMsgDMouseMove messages until it receives a // kMsgCInfoAck in order to prevent attempts to move the mouse off // the new screen area. -static const char kMsgDInfo[] = "DINF%2i%2i%2i%2i%2i"; +static const char kMsgDInfo[] = "DINF%2i%2i%2i%2i%2i%2i%2i"; //