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:
crs 2003-05-17 13:44:24 +00:00
parent 92ff58a5af
commit 51919a50e6
4 changed files with 68 additions and 5 deletions

View File

@ -34,6 +34,12 @@
# else # else
# error The XTest extension is required to build synergy # error The XTest extension is required to build synergy
# endif # 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) # if defined(HAVE_X11_XF86KEYSYM_H)
# include <X11/XF86keysym.h> # include <X11/XF86keysym.h>
# endif # endif
@ -92,7 +98,8 @@ unsigned int assignBits(unsigned int src,
CXWindowsSecondaryScreen::CXWindowsSecondaryScreen(IScreenReceiver* receiver) : CXWindowsSecondaryScreen::CXWindowsSecondaryScreen(IScreenReceiver* receiver) :
CSecondaryScreen(), CSecondaryScreen(),
m_window(None) m_window(None),
m_xtestIsXineramaUnaware(true)
{ {
m_screen = new CXWindowsScreen(receiver, this); m_screen = new CXWindowsScreen(receiver, this);
} }
@ -295,8 +302,9 @@ CXWindowsSecondaryScreen::mouseWheel(SInt32 delta)
void void
CXWindowsSecondaryScreen::resetOptions() CXWindowsSecondaryScreen::resetOptions()
{ {
m_numLockHalfDuplex = false; m_numLockHalfDuplex = false;
m_capsLockHalfDuplex = false; m_capsLockHalfDuplex = false;
m_xtestIsXineramaUnaware = true;
CSecondaryScreen::resetOptions(); CSecondaryScreen::resetOptions();
} }
@ -312,6 +320,10 @@ CXWindowsSecondaryScreen::setOptions(const COptionsList& options)
m_numLockHalfDuplex = (options[i + 1] != 0); m_numLockHalfDuplex = (options[i + 1] != 0);
LOG((CLOG_DEBUG1 "half-duplex num-lock %s", m_numLockHalfDuplex ? "on" : "off")); 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); CSecondaryScreen::setOptions(options);
} }
@ -388,6 +400,30 @@ CXWindowsSecondaryScreen::onPostOpen()
// get the keyboard control state // get the keyboard control state
CDisplayLock display(m_screen); CDisplayLock display(m_screen);
XGetKeyboardControl(display, &m_keyControl); 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 void
@ -542,7 +578,16 @@ CXWindowsSecondaryScreen::warpCursor(SInt32 x, SInt32 y)
{ {
CDisplayLock display(m_screen); CDisplayLock display(m_screen);
Display* pDisplay = display; 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); XSync(display, False);
} }

View File

@ -175,6 +175,15 @@ private:
// the keyboard control state the last time this screen was entered // the keyboard control state the last time this screen was entered
XKeyboardState m_keyControl; 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 #endif

View File

@ -643,6 +643,9 @@ CConfig::getOptionName(OptionID id)
if (id == kOptionScreenSaverSync) { if (id == kOptionScreenSaverSync) {
return "screenSaverSync"; return "screenSaverSync";
} }
if (id == kOptionXTestXineramaUnaware) {
return "xtestIsXineramaUnaware";
}
return NULL; return NULL;
} }
@ -651,7 +654,8 @@ CConfig::getOptionValue(OptionID id, OptionValue value)
{ {
if (id == kOptionHalfDuplexCapsLock || if (id == kOptionHalfDuplexCapsLock ||
id == kOptionHalfDuplexNumLock || id == kOptionHalfDuplexNumLock ||
id == kOptionScreenSaverSync) { id == kOptionScreenSaverSync ||
id == kOptionXTestXineramaUnaware) {
return (value != 0) ? "true" : "false"; return (value != 0) ? "true" : "false";
} }
if (id == kOptionModifierMapForShift || if (id == kOptionModifierMapForShift ||
@ -883,6 +887,10 @@ CConfig::readSectionScreens(std::istream& s)
addOption(screen, kOptionModifierMapForSuper, addOption(screen, kOptionModifierMapForSuper,
parseModifierKey(value)); parseModifierKey(value));
} }
else if (name == "xtestIsXineramaUnaware") {
addOption(screen, kOptionXTestXineramaUnaware,
parseBoolean(value));
}
else { else {
// unknown argument // unknown argument
throw XConfigRead("unknown argument"); throw XConfigRead("unknown argument");

View File

@ -54,6 +54,7 @@ static const OptionID kOptionHeartbeat = OPTION_CODE("HART");
static const OptionID kOptionScreenSwitchDelay = OPTION_CODE("SSWT"); static const OptionID kOptionScreenSwitchDelay = OPTION_CODE("SSWT");
static const OptionID kOptionScreenSwitchTwoTap = OPTION_CODE("SSTT"); static const OptionID kOptionScreenSwitchTwoTap = OPTION_CODE("SSTT");
static const OptionID kOptionScreenSaverSync = OPTION_CODE("SSVR"); static const OptionID kOptionScreenSaverSync = OPTION_CODE("SSVR");
static const OptionID kOptionXTestXineramaUnaware = OPTION_CODE("XTXU");
//@} //@}
#undef OPTION_CODE #undef OPTION_CODE