From 51919a50e6be74113174cc789ca95d93c33989de Mon Sep 17 00:00:00 2001 From: crs Date: Sat, 17 May 2003 13:44:24 +0000 Subject: [PATCH] Added workaround for when XTest is unaware of Xinerama. When that's true, faking a mouse motion outside screen 0 is clamped onto screen 0. When the workaround is enabled, we use XWarpPointer() instead of an XTest fake motion. This isn't perfect but the only real fix requires patching XTest. --- lib/platform/CXWindowsSecondaryScreen.cpp | 53 +++++++++++++++++++++-- lib/platform/CXWindowsSecondaryScreen.h | 9 ++++ lib/server/CConfig.cpp | 10 ++++- lib/synergy/OptionTypes.h | 1 + 4 files changed, 68 insertions(+), 5 deletions(-) diff --git a/lib/platform/CXWindowsSecondaryScreen.cpp b/lib/platform/CXWindowsSecondaryScreen.cpp index fba55e7f..8d599970 100644 --- a/lib/platform/CXWindowsSecondaryScreen.cpp +++ b/lib/platform/CXWindowsSecondaryScreen.cpp @@ -34,6 +34,12 @@ # else # error The XTest extension is required to build synergy # endif +# if HAVE_X11_EXTENSIONS_XINERAMA_H + // Xinerama.h may lack extern "C" for inclusion by C++ + extern "C" { +# include + } +# endif # if defined(HAVE_X11_XF86KEYSYM_H) # include # endif @@ -92,7 +98,8 @@ unsigned int assignBits(unsigned int src, CXWindowsSecondaryScreen::CXWindowsSecondaryScreen(IScreenReceiver* receiver) : CSecondaryScreen(), - m_window(None) + m_window(None), + m_xtestIsXineramaUnaware(true) { m_screen = new CXWindowsScreen(receiver, this); } @@ -295,8 +302,9 @@ CXWindowsSecondaryScreen::mouseWheel(SInt32 delta) void CXWindowsSecondaryScreen::resetOptions() { - m_numLockHalfDuplex = false; - m_capsLockHalfDuplex = false; + m_numLockHalfDuplex = false; + m_capsLockHalfDuplex = false; + m_xtestIsXineramaUnaware = true; CSecondaryScreen::resetOptions(); } @@ -312,6 +320,10 @@ CXWindowsSecondaryScreen::setOptions(const COptionsList& options) m_numLockHalfDuplex = (options[i + 1] != 0); LOG((CLOG_DEBUG1 "half-duplex num-lock %s", m_numLockHalfDuplex ? "on" : "off")); } + else if (options[i] == kOptionXTestXineramaUnaware) { + m_xtestIsXineramaUnaware = (options[i + 1] != 0); + LOG((CLOG_DEBUG1 "XTest is Xinerama unaware %s", m_xtestIsXineramaUnaware ? "true" : "false")); + } } CSecondaryScreen::setOptions(options); } @@ -388,6 +400,30 @@ CXWindowsSecondaryScreen::onPostOpen() // get the keyboard control state CDisplayLock display(m_screen); XGetKeyboardControl(display, &m_keyControl); + + // check if xinerama is enabled and, if so, get the first + // screen's dimensions. + m_xinerama = false; +#if HAVE_X11_EXTENSIONS_XINERAMA_H + int eventBase, errorBase; + if (XineramaQueryExtension(display, &eventBase, &errorBase)) { + if (XineramaIsActive(display)) { + int numScreens; + XineramaScreenInfo* screens; + screens = XineramaQueryScreens(display, &numScreens); + if (screens != NULL) { + if (numScreens > 1) { + m_xinerama = true; + m_xXinerama = screens[0].x_org; + m_yXinerama = screens[0].y_org; + m_wXinerama = screens[0].width; + m_hXinerama = screens[0].height; + } + XFree(screens); + } + } + } +#endif } void @@ -542,7 +578,16 @@ CXWindowsSecondaryScreen::warpCursor(SInt32 x, SInt32 y) { CDisplayLock display(m_screen); Display* pDisplay = display; - XTestFakeMotionEvent(display, DefaultScreen(pDisplay), x, y, CurrentTime); + + if (m_xinerama && m_xtestIsXineramaUnaware && + (x < m_xXinerama || x >= m_xXinerama + m_wXinerama || + y < m_yXinerama || y >= m_yXinerama + m_hXinerama)) { + XWarpPointer(display, None, None, 0, 0, 0, 0, x, y); + } + else { + XTestFakeMotionEvent(display, DefaultScreen(pDisplay), + x - m_xXinerama, y - m_yXinerama, CurrentTime); + } XSync(display, False); } diff --git a/lib/platform/CXWindowsSecondaryScreen.h b/lib/platform/CXWindowsSecondaryScreen.h index f44a12ed..b37f4327 100644 --- a/lib/platform/CXWindowsSecondaryScreen.h +++ b/lib/platform/CXWindowsSecondaryScreen.h @@ -175,6 +175,15 @@ private: // the keyboard control state the last time this screen was entered XKeyboardState m_keyControl; + + // stuff to workaround xtest being xinerama unaware. attempting + // to fake a mouse motion outside the first xinerama screen will + // be silently clamped to that screen. if xtest is buggy then + // use XWarpPointer instead. + bool m_xtestIsXineramaUnaware; + bool m_xinerama; + SInt32 m_xXinerama, m_yXinerama; + SInt32 m_wXinerama, m_hXinerama; }; #endif diff --git a/lib/server/CConfig.cpp b/lib/server/CConfig.cpp index 3a66103b..89417b28 100644 --- a/lib/server/CConfig.cpp +++ b/lib/server/CConfig.cpp @@ -643,6 +643,9 @@ CConfig::getOptionName(OptionID id) if (id == kOptionScreenSaverSync) { return "screenSaverSync"; } + if (id == kOptionXTestXineramaUnaware) { + return "xtestIsXineramaUnaware"; + } return NULL; } @@ -651,7 +654,8 @@ CConfig::getOptionValue(OptionID id, OptionValue value) { if (id == kOptionHalfDuplexCapsLock || id == kOptionHalfDuplexNumLock || - id == kOptionScreenSaverSync) { + id == kOptionScreenSaverSync || + id == kOptionXTestXineramaUnaware) { return (value != 0) ? "true" : "false"; } if (id == kOptionModifierMapForShift || @@ -883,6 +887,10 @@ CConfig::readSectionScreens(std::istream& s) addOption(screen, kOptionModifierMapForSuper, parseModifierKey(value)); } + else if (name == "xtestIsXineramaUnaware") { + addOption(screen, kOptionXTestXineramaUnaware, + parseBoolean(value)); + } else { // unknown argument throw XConfigRead("unknown argument"); diff --git a/lib/synergy/OptionTypes.h b/lib/synergy/OptionTypes.h index d94cac37..aaefe7fa 100644 --- a/lib/synergy/OptionTypes.h +++ b/lib/synergy/OptionTypes.h @@ -54,6 +54,7 @@ static const OptionID kOptionHeartbeat = OPTION_CODE("HART"); static const OptionID kOptionScreenSwitchDelay = OPTION_CODE("SSWT"); static const OptionID kOptionScreenSwitchTwoTap = OPTION_CODE("SSTT"); static const OptionID kOptionScreenSaverSync = OPTION_CODE("SSVR"); +static const OptionID kOptionXTestXineramaUnaware = OPTION_CODE("XTXU"); //@} #undef OPTION_CODE