]> git.saurik.com Git - wxWidgets.git/blobdiff - src/cocoa/window.mm
Fix crash in wxDC::GetMultiLineTextExtent() after last commit.
[wxWidgets.git] / src / cocoa / window.mm
index fecbd8ac706551d634d0124b58f9adb7d7bdca52..8fb822a76f5d159bfb7155e9c2c333083e56b2a9 100644 (file)
@@ -6,7 +6,7 @@
 // Created:     2002/12/26
 // RCS-ID:      $Id$
 // Copyright:   (c) 2002 David Elliott
-// Licence:     wxWidgets licence
+// Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
 #include "wx/wxprec.h"
@@ -26,7 +26,7 @@
 #include "wx/cocoa/string.h"
 #include "wx/cocoa/trackingrectmanager.h"
 #include "wx/cocoa/private/scrollview.h"
-#include "wx/mac/corefoundation/cfref.h"
+#include "wx/osx/core/cfref.h"
 #include "wx/cocoa/ObjcRef.h"
 
 #import <Foundation/NSArray.h>
@@ -152,7 +152,7 @@ namespace { // file namespace
 
 class wxCocoaPrivateScreenCoordinateTransformer
 {
-    DECLARE_NO_COPY_CLASS(wxCocoaPrivateScreenCoordinateTransformer)
+    wxDECLARE_NO_COPY_CLASS(wxCocoaPrivateScreenCoordinateTransformer);
 public:
     wxCocoaPrivateScreenCoordinateTransformer();
     ~wxCocoaPrivateScreenCoordinateTransformer();
@@ -273,7 +273,7 @@ NSPoint wxWindowCocoa::OriginInCocoaScreenCoordinatesForRectInWxDisplayCoordinat
 // ========================================================================
 class wxWindowCocoaHider: protected wxCocoaNSView
 {
-    DECLARE_NO_COPY_CLASS(wxWindowCocoaHider)
+    wxDECLARE_NO_COPY_CLASS(wxWindowCocoaHider);
 public:
     wxWindowCocoaHider(wxWindow *owner);
     virtual ~wxWindowCocoaHider();
@@ -309,6 +309,12 @@ WX_IMPLEMENT_GET_OBJC_CLASS(wxDummyNSView,NSView)
 
 // ========================================================================
 // wxWindowCocoaHider
+//  NOTE: This class and method of hiding predates setHidden: support in
+//  the toolkit.  The hack used here is to replace the view with a stand-in
+//  that will be subject to the usual Cocoa resizing rules.
+//  When possible (i.e. when running on 10.3 or higher) we make it hidden
+//  mostly as an optimization so Cocoa doesn't have to consider it when
+//  drawing or finding key views.
 // ========================================================================
 wxWindowCocoaHider::wxWindowCocoaHider(wxWindow *owner)
 :   m_owner(owner)
@@ -319,6 +325,9 @@ wxWindowCocoaHider::wxWindowCocoaHider(wxWindow *owner)
         initWithFrame:[owner->GetNSViewForHiding() frame]];
     [m_dummyNSView setAutoresizingMask: [owner->GetNSViewForHiding() autoresizingMask]];
     AssociateNSView(m_dummyNSView);
+
+    if([m_dummyNSView respondsToSelector:@selector(setHidden:)])
+        [m_dummyNSView setHidden:YES];
 }
 
 wxWindowCocoaHider::~wxWindowCocoaHider()
@@ -348,9 +357,9 @@ bool wxWindowCocoaHider::Cocoa_drawRect(const NSRect& rect)
 
 
 /*! @class WXManualScrollView
-    @abstract   An NSScrollView subclass which implements wx scroll behavior
+    @abstract   An NSScrollView subclass which implements wx scroll behaviour
     @discussion
-    Overrides default behavior of NSScrollView such that this class receives
+    Overrides default behaviour of NSScrollView such that this class receives
     the scroller action messages and allows the wxCocoaScrollView to act
     on them accordingly.  In particular, because the NSScrollView will not
     receive action messages from the scroller, it will not adjust the
@@ -726,7 +735,7 @@ int wxWindowCocoaScrollView::GetScrollPos(wxOrientation orient)
         position is at range-thumbsize.
 
         The range of an NSScroller is 0.0 to 1.0.  Much easier! NOTE: Apple doesn't really specify
-        but GNUStep docs do say that 0.0 is top/left and 1.0 is bottom/right.  This is actualy
+        but GNUStep docs do say that 0.0 is top/left and 1.0 is bottom/right.  This is actually
         in contrast to NSSlider which generally has 1.0 at the TOP when it's done vertically.
      */
     CGFloat cocoaScrollPos = [cocoaScroller floatValue];
@@ -919,8 +928,6 @@ void wxWindowCocoaScrollView::Cocoa_FrameChanged(void)
 // normally the base classes aren't included, but wxWindow is special
 #ifdef __WXUNIVERSAL__
 IMPLEMENT_ABSTRACT_CLASS(wxWindowCocoa, wxWindowBase)
-#else
-IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
 #endif
 
 BEGIN_EVENT_TABLE(wxWindowCocoa, wxWindowBase)
@@ -934,7 +941,6 @@ void wxWindowCocoa::Init()
     m_cocoaNSView = NULL;
     m_cocoaHider = NULL;
     m_wxCocoaScrollView = NULL;
-    m_isBeingDeleted = false;
     m_isInPaint = false;
     m_visibleTrackingRectManager = NULL;
 }
@@ -1403,17 +1409,48 @@ bool wxWindow::Show(bool show)
         // If state isn't changing, return false
         if(!m_cocoaHider)
             return false;
+
+        // Replace the stand-in view with the real one and destroy the dummy view
         CocoaReplaceView(m_cocoaHider->GetNSView(), cocoaView);
         wxASSERT(![m_cocoaHider->GetNSView() superview]);
         delete m_cocoaHider;
         m_cocoaHider = NULL;
         wxASSERT([cocoaView superview]);
+
+        // Schedule an update of the key view loop (NOTE: 10.4+ only.. argh)
+        NSWindow *window = [cocoaView window];
+        if(window != nil)
+        {
+            // Delay this until returning to the event loop for a couple of reasons:
+            // 1. If a lot of stuff is shown/hidden we avoid recalculating needlessly
+            // 2. NSWindow does not seem to see the newly shown views if we do it right now.
+            if([window respondsToSelector:@selector(recalculateKeyViewLoop)])
+                [window performSelector:@selector(recalculateKeyViewLoop) withObject:nil afterDelay:0.0];
+        }
     }
     else
     {
         // If state isn't changing, return false
         if(m_cocoaHider)
             return false;
+
+        // Handle the first responder
+        NSWindow *window = [cocoaView window];
+        if(window != nil)
+        {
+            NSResponder *firstResponder = [window firstResponder];
+            if([firstResponder isKindOfClass:[NSView class]] && [(NSView*)firstResponder isDescendantOf:cocoaView])
+            {
+                BOOL didResign = [window makeFirstResponder:nil];
+                // If the current first responder (one of our subviews) refuses to give
+                // up its status, then fail now and don't hide this view
+                if(didResign == NO)
+                    return false;
+            }
+        }
+
+        // Create a new view to stand in for the real one (via wxWindowCocoaHider) and replace
+        // the real one with the stand in.
         m_cocoaHider = new wxWindowCocoaHider(this);
         // NOTE: replaceSubview:with will cause m_cocaNSView to be
         // (auto)released which balances out addSubview
@@ -1674,7 +1711,7 @@ int wxWindow::GetCharWidth() const
     return 5;
 }
 
-void wxWindow::GetTextExtent(const wxString& string, int *outX, int *outY,
+void wxWindow::DoGetTextExtent(const wxString& string, int *outX, int *outY,
         int *outDescent, int *outExternalLeading, const wxFont *inFont) const
 {
     // FIXME: This obviously ignores the window's font (if any) along with any size
@@ -1778,7 +1815,7 @@ static char const * const comparisonresultStrings[] =
 
 class CocoaWindowCompareContext
 {
-    DECLARE_NO_COPY_CLASS(CocoaWindowCompareContext)
+    wxDECLARE_NO_COPY_CLASS(CocoaWindowCompareContext);
 public:
     CocoaWindowCompareContext(); // Not implemented
     CocoaWindowCompareContext(NSView *target, NSArray *subviews)
@@ -1969,7 +2006,7 @@ wxWindow* wxFindWindowAtPointer(wxPoint& pt)
  */
 class wxCocoaMouseMovedEventSynthesizer
 {
-    DECLARE_NO_COPY_CLASS(wxCocoaMouseMovedEventSynthesizer)
+    wxDECLARE_NO_COPY_CLASS(wxCocoaMouseMovedEventSynthesizer);
 public:
     wxCocoaMouseMovedEventSynthesizer()
     {   m_lastScreenMouseLocation = NSZeroPoint;