diff --git a/src/lib/platform/COSXScreen.cpp b/src/lib/platform/COSXScreen.cpp index 28af27a0..ee3aa95e 100644 --- a/src/lib/platform/COSXScreen.cpp +++ b/src/lib/platform/COSXScreen.cpp @@ -650,18 +650,30 @@ COSXScreen::showCursor() { LOG((CLOG_DEBUG "showing cursor")); + CFStringRef propertyString = CFStringCreateWithCString( + NULL, "SetsCursorInBackground", kCFStringEncodingMacRoman); + + // it looks like from around 2010 (os x 10.6 or 10.7) the behavior of + // CGDisplayHideCursor changed so that the cursor could only be hidden by + // the program which owned it. ed's solution in r820 was to send the + // cursor to the background before trying to hide it. however, this + // intermittently caused the cursor to remain hidden when we try to + // show it again. to solve this bug, we return the cursor to the + // background. + CGSSetConnectionProperty( + _CGSDefaultConnection(), _CGSDefaultConnection(), + propertyString, kCFBooleanTrue); + CGError error = CGDisplayShowCursor(m_displayID); if (error != kCGErrorSuccess) { LOG((CLOG_ERR "failed to show cursor, error=%d", error)); } - CFStringRef propertyString = CFStringCreateWithCString(NULL, "SetsCursorInBackground", kCFStringEncodingMacRoman); - CGSSetConnectionProperty(_CGSDefaultConnection(), _CGSDefaultConnection(), propertyString, kCFBooleanFalse); - CFRelease(propertyString); + CGSSetConnectionProperty( + _CGSDefaultConnection(), _CGSDefaultConnection(), + propertyString, kCFBooleanFalse); - if (!CGCursorIsVisible()) { - LOG((CLOG_WARN "cursor is not visible")); - } + CFRelease(propertyString); m_cursorHidden = false; } @@ -671,18 +683,41 @@ COSXScreen::hideCursor() { LOG((CLOG_DEBUG "hiding cursor")); - CFStringRef propertyString = CFStringCreateWithCString(NULL, "SetsCursorInBackground", kCFStringEncodingMacRoman); - CGSSetConnectionProperty(_CGSDefaultConnection(), _CGSDefaultConnection(), propertyString, kCFBooleanTrue); - CFRelease(propertyString); + CFStringRef propertyString = CFStringCreateWithCString( + NULL, "SetsCursorInBackground", kCFStringEncodingMacRoman); + + CGSSetConnectionProperty( + _CGSDefaultConnection(), _CGSDefaultConnection(), + propertyString, kCFBooleanTrue); CGError error = CGDisplayHideCursor(m_displayID); if (error != kCGErrorSuccess) { LOG((CLOG_ERR "failed to hide cursor, error=%d", error)); } + // ed's solution to send the cursor to the background before hiding + // fixed the bug caused by the new behavior of CGDisplayHideCursor, + // which is to only allow cursor to be shown/hidden by the program + // that has focus. + // however, this does not always work, and the cursor remains hidden, + // often when leaving the screen immediately after using the dock. + // to work around this, we send the mouse to the corner of the screen + // when the cursor is still visible, where it is less noticeable than + // at the center. if (CGCursorIsVisible()) { - LOG((CLOG_WARN "cursor is still visible")); + LOG((CLOG_WARN "cursor is still visible (warping to corner)")); + warpCursor(0, m_h); } + else { + LOG((CLOG_DEBUG "cursor is hidden, warping to center")); + warpCursor(m_xCenter, m_yCenter); + } + + CGSSetConnectionProperty( + _CGSDefaultConnection(), _CGSDefaultConnection(), + propertyString, kCFBooleanFalse); + + CFRelease(propertyString); m_cursorHidden = true; } @@ -807,7 +842,7 @@ COSXScreen::leave() if (m_isPrimary) { // warp to center - warpCursor(m_xCenter, m_yCenter); + //warpCursor(m_xCenter, m_yCenter); // This used to be necessary to get smooth mouse motion on other screens, // but now is just to avoid a hesitating cursor when transitioning to @@ -819,7 +854,7 @@ COSXScreen::leave() } else { // warp the mouse to the cursor center - fakeMouseMove(m_xCenter, m_yCenter); + //fakeMouseMove(m_xCenter, m_yCenter); // FIXME -- prepare to show cursor if it moves