fixed spurious mouse motions when entering/leaving primary

screen on X11.
This commit is contained in:
crs 2002-07-03 16:25:36 +00:00
parent d813329c0c
commit 217313e013
2 changed files with 90 additions and 85 deletions

View File

@ -160,44 +160,37 @@ CXWindowsPrimaryScreen::run()
case MotionNotify: case MotionNotify:
{ {
log((CLOG_DEBUG2 "event: MotionNotify %d,%d", xevent.xmotion.x_root, xevent.xmotion.y_root)); log((CLOG_DEBUG2 "event: MotionNotify %d,%d", xevent.xmotion.x_root, xevent.xmotion.y_root));
SInt32 x = xevent.xmotion.x_root;
SInt32 y = xevent.xmotion.y_root; // compute motion delta (relative to the last known
if (!m_active) { // mouse position)
m_server->onMouseMovePrimary(x, y); SInt32 x = xevent.xmotion.x_root - m_x;
SInt32 y = xevent.xmotion.y_root - m_y;
// save position to compute delta of next motion
m_x = xevent.xmotion.x_root;
m_y = xevent.xmotion.y_root;
if (xevent.xmotion.send_event) {
// we warped the mouse. discard events until we
// find the matching sent event. see
// warpCursorNoLockNoFlush() for where the events
// are sent. we discard the matching sent event
// and can be sure we've skipped the warp event.
CDisplayLock display(this);
do {
XMaskEvent(display, PointerMotionMask, &xevent);
} while (!xevent.xmotion.send_event);
}
else if (!m_active) {
// motion on primary screen
m_server->onMouseMovePrimary(m_x, m_y);
} }
else { else {
// compute motion delta. this is relative to the // motion on secondary screen. warp mouse back to
// last known mouse position. // center.
x -= m_x; //
y -= m_y; // my lombard (powerbook g3) running linux and
// using the adbmouse driver has two problems:
// save position to compute delta of next motion
m_x = xevent.xmotion.x_root;
m_y = xevent.xmotion.y_root;
// if event was sent then ignore it and discard
// the event from the mouse warp. this is how we
// warp the mouse back to the center of the screen
// without that causing a corresponding motion on
// the secondary screen.
if (xevent.xmotion.send_event) {
// ignore event
x = 0;
y = 0;
// discard events until we find the matching
// sent event. see below for where the events
// are sent. we discard the matching sent
// event and can be sure we've skipped the
// warp event.
CDisplayLock display(this);
do {
XMaskEvent(display, PointerMotionMask, &xevent);
} while (!xevent.xmotion.send_event);
}
// warp mouse back to center. my lombard (powerbook
// g3) using the adbmouse driver has two problems:
// first, the driver only sends motions of +/-2 // first, the driver only sends motions of +/-2
// pixels and, second, it seems to discard some // pixels and, second, it seems to discard some
// physical input after a warp. the former isn't a // physical input after a warp. the former isn't a
@ -211,28 +204,15 @@ CXWindowsPrimaryScreen::run()
xevent.xmotion.y_root - m_yCenter < -s_size || xevent.xmotion.y_root - m_yCenter < -s_size ||
xevent.xmotion.y_root - m_yCenter > s_size) { xevent.xmotion.y_root - m_yCenter > s_size) {
CDisplayLock display(this); CDisplayLock display(this);
// send an event that we can recognize before warpCursorNoLockNoFlush(display, m_xCenter, m_yCenter);
// the mouse warp.
XEvent eventBefore = xevent;
xevent.xmotion.window = m_window;
xevent.xmotion.time = CurrentTime;
xevent.xmotion.x = m_xCenter;
xevent.xmotion.y = m_yCenter;
xevent.xmotion.x_root = m_xCenter;
xevent.xmotion.y_root = m_yCenter;
XEvent eventAfter = eventBefore;
XSendEvent(display, m_window, False, 0, &xevent);
// warp mouse back to center
XWarpPointer(display, None, getRoot(),
0, 0, 0, 0, m_xCenter, m_yCenter);
// send an event that we can recognize after
// the mouse warp.
XSendEvent(display, m_window, False, 0, &xevent);
} }
// send event if mouse moved // send event if mouse moved. do this after warping
// back to center in case the motion takes us onto
// the primary screen. if we sent the event first
// in that case then the warp would happen after
// warping to the primary screen's enter position,
// effectively overriding it.
if (x != 0 || y != 0) { if (x != 0 || y != 0) {
m_server->onMouseMoveSecondary(x, y); m_server->onMouseMoveSecondary(x, y);
} }
@ -331,28 +311,18 @@ CXWindowsPrimaryScreen::enter(SInt32 x, SInt32 y, bool forScreenSaver)
CDisplayLock display(this); CDisplayLock display(this);
// warp to requested location
if (!forScreenSaver) {
XWarpPointer(display, None, m_window, 0, 0, 0, 0, x, y);
}
// unmap the grab window. this also ungrabs the mouse and keyboard. // unmap the grab window. this also ungrabs the mouse and keyboard.
XUnmapWindow(display, m_window); XUnmapWindow(display, m_window);
// redirect input to root window // warp to requested location
if (forScreenSaver) { if (!forScreenSaver) {
XSetInputFocus(display, PointerRoot, PointerRoot, CurrentTime); warpCursorNoLock(display, x, y);
} }
// remove all input events for grab window // redirect input to root window. do not warp the mouse because
XEvent event; // that will deactivate the screen saver.
while (XCheckWindowEvent(display, m_window, else {
PointerMotionMask | XSetInputFocus(display, PointerRoot, PointerRoot, CurrentTime);
ButtonPressMask | ButtonReleaseMask |
KeyPressMask | KeyReleaseMask |
KeymapStateMask,
&event)) {
// do nothing
} }
// not active anymore // not active anymore
@ -414,7 +384,7 @@ CXWindowsPrimaryScreen::leave()
} while (result != GrabSuccess); } while (result != GrabSuccess);
log((CLOG_DEBUG1 "grabbed pointer and keyboard")); log((CLOG_DEBUG1 "grabbed pointer and keyboard"));
// move the mouse to the center of grab window // warp mouse to center
warpCursorNoLock(display, m_xCenter, m_yCenter); warpCursorNoLock(display, m_xCenter, m_yCenter);
// local client now active // local client now active
@ -439,18 +409,16 @@ CXWindowsPrimaryScreen::warpCursor(SInt32 x, SInt32 y)
void void
CXWindowsPrimaryScreen::warpCursorNoLock(Display* display, SInt32 x, SInt32 y) CXWindowsPrimaryScreen::warpCursorNoLock(Display* display, SInt32 x, SInt32 y)
{ {
assert(display != NULL); // warp mouse
assert(m_window != None); warpCursorNoLockNoFlush(display, x, y);
// warp the mouse // remove all input events before and including warp
XWarpPointer(display, None, getRoot(), 0, 0, 0, 0, x, y); XEvent event;
XSync(display, False); while (XCheckMaskEvent(display, PointerMotionMask |
log((CLOG_DEBUG2 "warped to %d,%d", x, y)); ButtonPressMask | ButtonReleaseMask |
KeyPressMask | KeyReleaseMask |
// discard mouse events since we just added one we don't want KeymapStateMask,
XEvent xevent; &event)) {
while (XCheckWindowEvent(display, m_window,
PointerMotionMask, &xevent)) {
// do nothing // do nothing
} }
@ -459,6 +427,41 @@ CXWindowsPrimaryScreen::warpCursorNoLock(Display* display, SInt32 x, SInt32 y)
m_y = y; m_y = y;
} }
void
CXWindowsPrimaryScreen::warpCursorNoLockNoFlush(
Display* display, SInt32 x, SInt32 y)
{
assert(display != NULL);
assert(m_window != None);
// send an event that we can recognize before the mouse warp
XEvent eventBefore;
eventBefore.type = MotionNotify;
eventBefore.xmotion.display = display;
eventBefore.xmotion.window = m_window;
eventBefore.xmotion.root = getRoot();
eventBefore.xmotion.subwindow = m_window;
eventBefore.xmotion.time = CurrentTime;
eventBefore.xmotion.x = x;
eventBefore.xmotion.y = y;
eventBefore.xmotion.x_root = x;
eventBefore.xmotion.y_root = y;
eventBefore.xmotion.state = 0;
eventBefore.xmotion.is_hint = False;
eventBefore.xmotion.same_screen = True;
XEvent eventAfter = eventBefore;
XSendEvent(display, m_window, False, 0, &eventBefore);
// warp mouse
XWarpPointer(display, None, getRoot(), 0, 0, 0, 0, x, y);
// send an event that we can recognize after the mouse warp
XSendEvent(display, m_window, False, 0, &eventAfter);
XSync(display, False);
log((CLOG_DEBUG2 "warped to %d,%d", x, y));
}
void void
CXWindowsPrimaryScreen::setClipboard(ClipboardID id, CXWindowsPrimaryScreen::setClipboard(ClipboardID id,
const IClipboard* clipboard) const IClipboard* clipboard)

View File

@ -42,6 +42,8 @@ private:
void doSelectEvents(Display*, Window) const; void doSelectEvents(Display*, Window) const;
void warpCursorNoLock(Display*, void warpCursorNoLock(Display*,
SInt32 xAbsolute, SInt32 yAbsolute); SInt32 xAbsolute, SInt32 yAbsolute);
void warpCursorNoLockNoFlush(Display*,
SInt32 xAbsolute, SInt32 yAbsolute);
KeyModifierMask mapModifier(unsigned int state) const; KeyModifierMask mapModifier(unsigned int state) const;
KeyID mapKey(XKeyEvent*) const; KeyID mapKey(XKeyEvent*) const;