]> git.saurik.com Git - wxWidgets.git/blobdiff - src/cocoa/window.mm
test for __DARWIN__ with ifdef, not if
[wxWidgets.git] / src / cocoa / window.mm
index 194d5685bc4e2e2f46fa7f94e98b3ba4e1780a08..01c776073b85c3ecac6adf824b85bb1660dfdcb6 100644 (file)
@@ -540,7 +540,6 @@ void wxWindowCocoa::CocoaAddChild(wxWindowCocoa *child)
 
     wxASSERT(childView);
     [m_cocoaNSView addSubview: childView];
-    child->m_isShown = !m_cocoaHider;
 }
 
 void wxWindowCocoa::CocoaRemoveFromParent(void)
@@ -811,8 +810,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 +838,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;
 }
@@ -1153,10 +1173,15 @@ int wxWindow::GetCharWidth() const
     return 5;
 }
 
-void wxWindow::GetTextExtent(const wxString& string, int *x, int *y,
-        int *descent, int *externalLeading, const wxFont *theFont) const
+void wxWindow::GetTextExtent(const wxString& string, int *outX, int *outY,
+        int *outDescent, int *outExternalLeading, const wxFont *inFont) const
 {
-    // TODO
+    // FIXME: This obviously ignores the window's font (if any) along with any size
+    // transformations.  However, it's better than nothing.
+    // We don't create a wxClientDC because we don't want to accidently be able to use
+    // it for drawing.
+    wxDC tmpdc;
+    return tmpdc.GetTextExtent(string, outX, outY, outDescent, outExternalLeading, inFont);
 }
 
 // Coordinates relative to the window
@@ -1212,11 +1237,44 @@ void wxWindow::ScrollWindow(int dx, int dy, const wxRect *rect)
     // TODO
 }
 
+static inline int _DoFixupDistance(int vDistance, int cDistance)
+{
+    // If the virtual distance is wxDefaultCoord, set it to the client distance
+    // This definitely has to be done or else we literally get views with a -1 size component!
+    if(vDistance == wxDefaultCoord)
+        vDistance = cDistance;
+    // NOTE: Since cDistance should always be >= 0 and since wxDefaultCoord is -1, the above
+    // test is more or less useless because it gets covered by the next one.  However, just in
+    // case anyone decides that the next test is not correct, I want them to be aware that
+    // the above test would still be needed.
+
+    // I am not entirely sure about this next one but I believe it makes sense because
+    // otherwise the virtual view (which is the m_cocoaNSView that got wrapped by the scrolling
+    // machinery) can be smaller than the NSClipView (the client area) which
+    // means that, for instance, mouse clicks inside the client area as wx sees it but outside
+    // the virtual area as wx sees it won't be seen by the m_cocoaNSView.
+    // We make the assumption that if a virtual distance is less than the client distance that
+    // the real view must already be or will soon be positioned at coordinate 0  within the
+    // NSClipView that represents the client area.  This way, when we increase the distance to
+    // be the client distance, the real view will exactly fit in the clip view.
+    else if(vDistance < cDistance)
+        vDistance = cDistance;
+    return vDistance;
+}
+
 void wxWindow::DoSetVirtualSize( int x, int y )
 {
+    // Call wxWindowBase method which will set m_virtualSize to the appropriate value,
+    // possibly not what the caller passed in.  For example, the current implementation
+    // clamps the width and height to within the min/max virtual ranges.
+    // wxDefaultCoord is passed through unchanged which means we need to handle it ourselves
+    // which we do by using the _DoFixupDistance helper method.
     wxWindowBase::DoSetVirtualSize(x,y);
+    // Create the scroll view if it hasn't been already.
     CocoaCreateNSScrollView();
-    [m_cocoaNSView setFrameSize:NSMakeSize(m_virtualSize.x,m_virtualSize.y)];
+    // Now use fixed-up distances when setting the frame size
+    wxSize clientSize = GetClientSize();
+    [m_cocoaNSView setFrameSize:NSMakeSize(_DoFixupDistance(m_virtualSize.x, clientSize.x), _DoFixupDistance(m_virtualSize.y, clientSize.y))];
 }
 
 bool wxWindow::SetFont(const wxFont& font)
@@ -1591,8 +1649,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 +1664,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();