From ed1a77252b2731c61941df2cacc77774a1ee7173 Mon Sep 17 00:00:00 2001 From: "azanar@carrel.org" Date: Mon, 10 Jan 2011 07:55:41 +0000 Subject: [PATCH] Fix for #2875: MacOS cursor should now hide when not on the active screen. This time committed to the correct branch. Thanks (again!) to Doug Marcey (dougmarcey@gmail.com) for the patch. --- lib/platform/COSXScreen.cpp | 135 +++++++++++++++++++++++++----------- lib/platform/COSXScreen.h | 15 ++++ 2 files changed, 109 insertions(+), 41 deletions(-) diff --git a/lib/platform/COSXScreen.cpp b/lib/platform/COSXScreen.cpp index e3732810..34cb883e 100644 --- a/lib/platform/COSXScreen.cpp +++ b/lib/platform/COSXScreen.cpp @@ -541,6 +541,28 @@ COSXScreen::fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const } } +void +COSXScreen::showCursor() +{ + CGDisplayShowCursor(m_displayID); + CFStringRef propertyString = CFStringCreateWithCString(NULL, "SetsCursorInBackground", kCFStringEncodingMacRoman); + CGSSetConnectionProperty(_CGSDefaultConnection(), _CGSDefaultConnection(), propertyString, kCFBooleanFalse); + CFRelease(propertyString); + + LOG((CLOG_DEBUG "Trying to show cursor.")); +} + +void +COSXScreen::hideCursor() +{ + CFStringRef propertyString = CFStringCreateWithCString(NULL, "SetsCursorInBackground", kCFStringEncodingMacRoman); + CGSSetConnectionProperty(_CGSDefaultConnection(), _CGSDefaultConnection(), propertyString, kCFBooleanTrue); + CFRelease(propertyString); + + CGDisplayHideCursor(m_displayID); + LOG((CLOG_DEBUG "Trying to hide cursor.")); +} + void COSXScreen::enable() { @@ -558,55 +580,57 @@ COSXScreen::enable() kCGEventMaskForAllEvents, handleCGInputEvent, this); - if(!m_eventTapPort) { - LOG((CLOG_ERR "Failed to create quartz event tap.")); - } - m_eventTapRLSR=CFMachPortCreateRunLoopSource(kCFAllocatorDefault, m_eventTapPort, 0); - if(!m_eventTapRLSR) { - LOG((CLOG_ERR "Failed to create a CFRunLoopSourceRef for the quartz event tap.")); - } - CFRunLoopAddSource(CFRunLoopGetCurrent(), m_eventTapRLSR, kCFRunLoopDefaultMode); } else { // FIXME -- prevent system from entering power save mode // hide cursor if (!m_cursorHidden) { -// CGDisplayHideCursor(m_displayID); + hideCursor(); m_cursorHidden = true; } // warp the mouse to the cursor center fakeMouseMove(m_xCenter, m_yCenter); - // FIXME -- prepare to show cursor if it moves + // there may be a better way to do this, but we register an event handler even if we're + // not on the primary display (acting as a client). This way, if a local event comes in + // (either keyboard or mouse), we can make sure to show the cursor if we've hidden it. + m_eventTapPort=CGEventTapCreate(kCGHIDEventTap, kCGHIDEventTap, 0, + kCGEventMaskForAllEvents, + handleCGInputEventSecondary, + this); } + if(!m_eventTapPort) { + LOG((CLOG_ERR "Failed to create quartz event tap.")); + } + m_eventTapRLSR=CFMachPortCreateRunLoopSource(kCFAllocatorDefault, m_eventTapPort, 0); + if(!m_eventTapRLSR) { + LOG((CLOG_ERR "Failed to create a CFRunLoopSourceRef for the quartz event tap.")); + } + CFRunLoopAddSource(CFRunLoopGetCurrent(), m_eventTapRLSR, kCFRunLoopDefaultMode); } void COSXScreen::disable() { - if (m_isPrimary) { - // FIXME -- stop watching jump zones, stop capturing input - - if(m_eventTapRLSR) { - CFRelease(m_eventTapRLSR); - m_eventTapRLSR=NULL; - } - if(m_eventTapPort) { - CFRelease(m_eventTapPort); - m_eventTapPort=NULL; - } + // show cursor if hidden + if (m_cursorHidden) { + showCursor(); + m_cursorHidden = false; } - else { - // show cursor - if (m_cursorHidden) { -// CGDisplayShowCursor(m_displayID); - m_cursorHidden = false; - } - - // FIXME -- allow system to enter power saving mode + + // FIXME -- stop watching jump zones, stop capturing input + + if(m_eventTapRLSR) { + CFRelease(m_eventTapRLSR); + m_eventTapRLSR=NULL; + } + if(m_eventTapPort) { + CFRelease(m_eventTapPort); + m_eventTapPort=NULL; } + // FIXME -- allow system to enter power saving mode // disable drag handling m_dragNumButtonsDown = 0; @@ -625,6 +649,11 @@ COSXScreen::disable() void COSXScreen::enter() { + // show cursor + if (m_cursorHidden) { + showCursor(); + m_cursorHidden = false; + } if (m_isPrimary) { CGSetLocalEventsSuppressionInterval(0.0); @@ -632,12 +661,6 @@ COSXScreen::enter() //setGlobalHotKeysEnabled(true); } else { - // show cursor - if (m_cursorHidden) { -// CGDisplayShowCursor(m_displayID); - m_cursorHidden = false; - } - // reset buttons m_buttonState.reset(); @@ -659,6 +682,12 @@ COSXScreen::enter() bool COSXScreen::leave() { + // hide cursor + if (!m_cursorHidden) { + hideCursor(); + m_cursorHidden = true; + } + if (m_isPrimary) { // warp to center warpCursor(m_xCenter, m_yCenter); @@ -672,12 +701,6 @@ COSXScreen::leave() //setGlobalHotKeysEnabled(false); } else { - // hide cursor - if (!m_cursorHidden) { -// CGDisplayHideCursor(m_displayID); - m_cursorHidden = true; - } - // warp the mouse to the cursor center fakeMouseMove(m_xCenter, m_yCenter); @@ -1594,6 +1617,34 @@ COSXScreen::CHotKeyItem::operator<(const CHotKeyItem& x) const (m_keycode == x.m_keycode && m_mask < x.m_mask)); } +// Quartz event tap support for the secondary display. This make sure that we +// will show the cursor if a local event comes in while synergy has the cursor off the screen. +CGEventRef +COSXScreen::handleCGInputEventSecondary(CGEventTapProxy proxy, + CGEventType type, + CGEventRef event, + void* refcon) +{ + COSXScreen* screen = (COSXScreen*)refcon; + if (screen->m_cursorHidden) { + CGPoint pos; + bool showCursor = true; + if (type == kCGEventMouseMoved) { + pos = CGEventGetLocation(event); + if (pos.x == screen->m_xCenter && pos.y == screen->m_yCenter) { + showCursor = false; + } + } + if (showCursor) { + LOG((CLOG_DEBUG "Trying to show cursor from local event. (type = %d)", type)); + screen->showCursor(); + screen->m_cursorHidden = false; + } + } + LOG((CLOG_DEBUG2 "Local event? (type = %d)", type)); + return event; +} + // Quartz event tap support CGEventRef COSXScreen::handleCGInputEvent(CGEventTapProxy proxy, @@ -1653,6 +1704,8 @@ COSXScreen::handleCGInputEvent(CGEventTapProxy proxy, // Unknown, forward it return event; break; + case NX_NUMPROCS: + break; default: LOG((CLOG_NOTE "Unknown Quartz Event type: 0x%02x", type)); } diff --git a/lib/platform/COSXScreen.h b/lib/platform/COSXScreen.h index fe6ddea4..ab6870f0 100644 --- a/lib/platform/COSXScreen.h +++ b/lib/platform/COSXScreen.h @@ -34,6 +34,13 @@ #include #include +extern "C" { + typedef int CGSConnectionID; + CGError CGSSetConnectionProperty(CGSConnectionID cid, CGSConnectionID targetCID, CFStringRef key, CFTypeRef value); + int _CGSDefaultConnection(); +} + + template class CCondVar; class CEventQueueTimer; @@ -113,6 +120,10 @@ private: bool onKey(CGEventRef event); bool onHotKey(EventRef event) const; + + // Added here to allow the carbon cursor hack to be called. + void showCursor(); + void hideCursor(); // map mac mouse button to synergy buttons ButtonID mapMacButtonToSynergy(UInt16) const; @@ -168,6 +179,10 @@ private: CGEventType type, CGEventRef event, void* refcon); + static CGEventRef handleCGInputEventSecondary(CGEventTapProxy proxy, + CGEventType type, + CGEventRef event, + void* refcon); private: struct CHotKeyItem { public: