From 217313e0136a6327b73389aae7c8cb6fa7659eaa Mon Sep 17 00:00:00 2001 From: crs Date: Wed, 3 Jul 2002 16:25:36 +0000 Subject: [PATCH] fixed spurious mouse motions when entering/leaving primary screen on X11. --- server/CXWindowsPrimaryScreen.cpp | 173 +++++++++++++++--------------- server/CXWindowsPrimaryScreen.h | 2 + 2 files changed, 90 insertions(+), 85 deletions(-) diff --git a/server/CXWindowsPrimaryScreen.cpp b/server/CXWindowsPrimaryScreen.cpp index fe16effa..0a9ecb36 100644 --- a/server/CXWindowsPrimaryScreen.cpp +++ b/server/CXWindowsPrimaryScreen.cpp @@ -160,44 +160,37 @@ CXWindowsPrimaryScreen::run() case MotionNotify: { 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; - if (!m_active) { - m_server->onMouseMovePrimary(x, y); + + // compute motion delta (relative to the last known + // mouse position) + 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 { - // compute motion delta. this is relative to the - // last known mouse position. - x -= m_x; - y -= m_y; - - // 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: + // motion on secondary screen. warp mouse back to + // center. + // + // my lombard (powerbook g3) running linux and + // using the adbmouse driver has two problems: // first, the driver only sends motions of +/-2 // pixels and, second, it seems to discard some // 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) { CDisplayLock display(this); - // send an event that we can recognize before - // 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); + warpCursorNoLockNoFlush(display, m_xCenter, m_yCenter); } - // 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) { m_server->onMouseMoveSecondary(x, y); } @@ -331,28 +311,18 @@ CXWindowsPrimaryScreen::enter(SInt32 x, SInt32 y, bool forScreenSaver) 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. XUnmapWindow(display, m_window); - // redirect input to root window - if (forScreenSaver) { - XSetInputFocus(display, PointerRoot, PointerRoot, CurrentTime); + // warp to requested location + if (!forScreenSaver) { + warpCursorNoLock(display, x, y); } - // remove all input events for grab window - XEvent event; - while (XCheckWindowEvent(display, m_window, - PointerMotionMask | - ButtonPressMask | ButtonReleaseMask | - KeyPressMask | KeyReleaseMask | - KeymapStateMask, - &event)) { - // do nothing + // redirect input to root window. do not warp the mouse because + // that will deactivate the screen saver. + else { + XSetInputFocus(display, PointerRoot, PointerRoot, CurrentTime); } // not active anymore @@ -414,7 +384,7 @@ CXWindowsPrimaryScreen::leave() } while (result != GrabSuccess); 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); // local client now active @@ -439,18 +409,16 @@ CXWindowsPrimaryScreen::warpCursor(SInt32 x, SInt32 y) void CXWindowsPrimaryScreen::warpCursorNoLock(Display* display, SInt32 x, SInt32 y) { - assert(display != NULL); - assert(m_window != None); + // warp mouse + warpCursorNoLockNoFlush(display, x, y); - // warp the mouse - XWarpPointer(display, None, getRoot(), 0, 0, 0, 0, x, y); - XSync(display, False); - log((CLOG_DEBUG2 "warped to %d,%d", x, y)); - - // discard mouse events since we just added one we don't want - XEvent xevent; - while (XCheckWindowEvent(display, m_window, - PointerMotionMask, &xevent)) { + // remove all input events before and including warp + XEvent event; + while (XCheckMaskEvent(display, PointerMotionMask | + ButtonPressMask | ButtonReleaseMask | + KeyPressMask | KeyReleaseMask | + KeymapStateMask, + &event)) { // do nothing } @@ -459,6 +427,41 @@ CXWindowsPrimaryScreen::warpCursorNoLock(Display* display, SInt32 x, SInt32 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 CXWindowsPrimaryScreen::setClipboard(ClipboardID id, const IClipboard* clipboard) diff --git a/server/CXWindowsPrimaryScreen.h b/server/CXWindowsPrimaryScreen.h index c8996650..8cabc11f 100644 --- a/server/CXWindowsPrimaryScreen.h +++ b/server/CXWindowsPrimaryScreen.h @@ -42,6 +42,8 @@ private: void doSelectEvents(Display*, Window) const; void warpCursorNoLock(Display*, SInt32 xAbsolute, SInt32 yAbsolute); + void warpCursorNoLockNoFlush(Display*, + SInt32 xAbsolute, SInt32 yAbsolute); KeyModifierMask mapModifier(unsigned int state) const; KeyID mapKey(XKeyEvent*) const;