X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/18b32eb5b56cde55d91a4796ac167d9c61180770..a5de860f0b8994b2d87d0a0d3c3dedf750fa7ddb:/src/cocoa/window.mm?ds=sidebyside diff --git a/src/cocoa/window.mm b/src/cocoa/window.mm index 194d5685bc..390d250a93 100644 --- a/src/cocoa/window.mm +++ b/src/cocoa/window.mm @@ -811,8 +811,21 @@ void wxWindowCocoa::Cocoa_FrameChanged(void) bool wxWindowCocoa::Cocoa_resetCursorRects() { wxLogTrace(wxTRACE_COCOA,wxT("wxWindow=%p::Cocoa_resetCursorRects"),this); + + // When we are called there may be a queued tracking rect event (mouse entered or exited) and + // we won't know it. A specific example is wxGenericHyperlinkCtrl changing the cursor from its + // mouse exited event. If the control happens to share the edge with its parent window which is + // also tracking mouse events then Cocoa receives two mouse exited events from the window server. + // The first one will cause wxGenericHyperlinkCtrl to call wxWindow::SetCursor which will + // invaildate the cursor rect causing Cocoa to schedule cursor rect reset with the run loop + // which willl in turn call us before exiting for the next user event. + + // If we are the parent window then rebuilding our tracking rectangle will cause us to miss + // our mouse exited event because the already queued event will have the old tracking rect + // tag. The simple solution is to only rebuild our tracking rect if we need to. + if(m_visibleTrackingRectManager != NULL) - m_visibleTrackingRectManager->RebuildTrackingRect(); + m_visibleTrackingRectManager->RebuildTrackingRectIfNeeded(); if(!m_cursor.GetNSCursor()) return false; @@ -826,7 +839,15 @@ bool wxWindowCocoa::SetCursor(const wxCursor &cursor) { if(!wxWindowBase::SetCursor(cursor)) return false; + + // Set up the cursor rect so that invalidateCursorRectsForView: will destroy it. + // If we don't do this then Cocoa thinks (rightly) that we don't have any cursor + // rects and thus won't ever call resetCursorRects. + [GetNSView() addCursorRect: [GetNSView() visibleRect] cursor: m_cursor.GetNSCursor()]; + // Invalidate the cursor rects so the cursor will change + // Note that it is not enough to remove the old one (if any) and add the new one. + // For the rects to work properly, Cocoa itself must call resetCursorRects. [[GetNSView() window] invalidateCursorRectsForView:GetNSView()]; return true; } @@ -1591,8 +1612,12 @@ void wxCocoaTrackingRectManager::BuildTrackingRect() if([theView window] != nil) { - m_trackingRectTag = [theView addTrackingRect:[theView visibleRect] owner:theView userData:NULL assumeInside:NO]; + NSRect visibleRect = [theView visibleRect]; + + m_trackingRectTag = [theView addTrackingRect:visibleRect owner:theView userData:NULL assumeInside:NO]; + m_trackingRectInWindowCoordinates = [theView convertRect:visibleRect toView:nil]; m_isTrackingRectActive = true; + wxLogTrace(wxTRACE_COCOA_TrackingRect, wxT("%s@%p: Added tracking rect #%d"), m_window->GetClassInfo()->GetClassName(), m_window, m_trackingRectTag); } } @@ -1602,6 +1627,21 @@ void wxCocoaTrackingRectManager::BeginSynthesizingEvents() s_mouseMovedSynthesizer.RegisterWxCocoaView(m_window); } +void wxCocoaTrackingRectManager::RebuildTrackingRectIfNeeded() +{ + if(m_isTrackingRectActive) + { + NSView *theView = m_window->GetNSView(); + NSRect currentRect = [theView convertRect:[theView visibleRect] toView:nil]; + if(NSEqualRects(m_trackingRectInWindowCoordinates,currentRect)) + { + wxLogTrace(wxTRACE_COCOA_TrackingRect, wxT("Ignored request to rebuild TR#%d"), m_trackingRectTag); + return; + } + } + RebuildTrackingRect(); +} + void wxCocoaTrackingRectManager::RebuildTrackingRect() { ClearTrackingRect();