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.
This commit is contained in:
parent
92ff58a5af
commit
51919a50e6
|
@ -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 <X11/extensions/Xinerama.h>
|
||||
}
|
||||
# endif
|
||||
# if defined(HAVE_X11_XF86KEYSYM_H)
|
||||
# include <X11/XF86keysym.h>
|
||||
# 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue