]> git.saurik.com Git - wxWidgets.git/blobdiff - src/osx/carbon/graphics.cpp
Fix assertion when passing nil to setKeyEquivalent.
[wxWidgets.git] / src / osx / carbon / graphics.cpp
index 6afb4468a4f2eb71ca2886cf9ff12ae06d7765f6..74720dc37aed07f46cd7f24c9e95b96d0c0f6c9b 100644 (file)
     #include "wx/osx/dcprint.h"
     #include "wx/osx/dcclient.h"
     #include "wx/osx/dcmemory.h"
-#if wxOSX_USE_CARBON
-#include "wx/osx/uma.h"
-#else
-#include "wx/osx/private.h"
-#endif
-
+    #include "wx/osx/private.h"
 #else
     #include "CoreServices/CoreServices.h"
     #include "ApplicationServices/ApplicationServices.h"
@@ -76,6 +71,13 @@ int UMAGetSystemVersion()
 
 #endif
 
+#if wxOSX_USE_COCOA_OR_IPHONE
+extern CGContextRef wxOSXGetContextFromCurrentNSContext() ;
+extern bool wxOSXLockFocus( WXWidget view) ;
+extern void wxOSXUnlockFocus( WXWidget view) ;
+#endif
+
+
 //-----------------------------------------------------------------------------
 // constants
 //-----------------------------------------------------------------------------
@@ -1384,7 +1386,7 @@ public:
     DECLARE_DYNAMIC_CLASS_NO_COPY(wxMacCoreGraphicsContext)
 
 private:
-    void EnsureIsValid();
+    bool EnsureIsValid();
 
     virtual void DoDrawText( const wxString &str, wxDouble x, wxDouble y );
     virtual void DoDrawRotatedText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle );
@@ -1392,13 +1394,16 @@ private:
     CGContextRef m_cgContext;
 #if wxOSX_USE_CARBON
     WindowRef m_windowRef;
+#else
+    WXWidget m_view;
 #endif
-    bool m_releaseContext;
+    bool m_contextSynthesized;
     CGAffineTransform m_windowTransform;
     wxDouble m_width;
     wxDouble m_height;
+    bool m_invisible;
 
-#if wxOSX_USE_CARBON
+#if wxOSX_USE_COCOA_OR_CARBON
     wxCFRef<HIShapeRef> m_clipRgn;
 #endif
 };
@@ -1444,12 +1449,16 @@ public :
 void wxMacCoreGraphicsContext::Init()
 {
     m_cgContext = NULL;
-    m_releaseContext = false;
+    m_contextSynthesized = false;
+    m_width = 0;
+    m_height = 0;
 #if wxOSX_USE_CARBON
     m_windowRef = NULL;
 #endif
-    m_width = 0;
-    m_height = 0;
+#if wxOSX_USE_COCOA_OR_IPHONE
+    m_view = NULL;
+#endif
+    m_invisible = false;
 }
 
 wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, CGContextRef cgcontext, wxDouble width, wxDouble height ) : wxGraphicsContext(renderer)
@@ -1472,19 +1481,33 @@ wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer
 {
     Init();
 
+    wxSize sz = window->GetSize();
+    m_width = sz.x;
+    m_height = sz.y;
+
+#if wxOSX_USE_COCOA_OR_IPHONE
+    m_view = window->GetHandle();
+
+    if ( !((wxWidgetCocoaImpl*) window->GetPeer())->IsFlipped() )
+    {
+        m_windowTransform = CGAffineTransformMakeTranslation( 0 , m_height );
+        m_windowTransform = CGAffineTransformScale( m_windowTransform , 1 , -1 );
+    }
+    else
+    {
+        m_windowTransform = CGAffineTransformIdentity;
+    }
+#else
     int originX , originY;
     originX = originY = 0;
-
     Rect bounds = { 0,0,0,0 };
-#if defined(__WXCOCOA__) || !wxOSX_USE_CARBON
-#else
     m_windowRef = (WindowRef) window->MacGetTopLevelWindowRef();
     window->MacWindowToRootWindow( &originX , &originY );
     GetWindowBounds( m_windowRef, kWindowContentRgn, &bounds );
-#endif
     m_windowTransform = CGAffineTransformMakeTranslation( 0 , bounds.bottom - bounds.top );
     m_windowTransform = CGAffineTransformScale( m_windowTransform , 1 , -1 );
     m_windowTransform = CGAffineTransformTranslate( m_windowTransform, originX, originY ) ;
+#endif
 }
 
 wxMacCoreGraphicsContext::wxMacCoreGraphicsContext(wxGraphicsRenderer* renderer) : wxGraphicsContext(renderer)
@@ -1501,6 +1524,12 @@ wxMacCoreGraphicsContext::wxMacCoreGraphicsContext() : wxGraphicsContext(NULL)
 wxMacCoreGraphicsContext::~wxMacCoreGraphicsContext()
 {
     SetNativeContext(NULL);
+#if wxOSX_USE_COCOA_OR_IPHONE
+    if ( m_view )
+    {
+        CGContextFlush(m_cgContext);
+    }
+#endif
 }
 
 void wxMacCoreGraphicsContext::GetSize( wxDouble* width, wxDouble* height)
@@ -1533,43 +1562,75 @@ void wxMacCoreGraphicsContext::Flush()
     CGContextFlush(m_cgContext);
 }
 
-void wxMacCoreGraphicsContext::EnsureIsValid()
+bool wxMacCoreGraphicsContext::EnsureIsValid()
 {
     if ( !m_cgContext )
     {
-#if defined(__WXCOCOA__) || ! wxOSX_USE_CARBON
-        wxFAIL_MSG("Cannot create wxDCs lazily");
-#else
+        if (m_invisible)
+            return false;
+            
+#if wxOSX_USE_COCOA_OR_IPHONE
+        if ( wxOSXLockFocus(m_view) )
+        {
+            m_cgContext = wxOSXGetContextFromCurrentNSContext();
+            wxASSERT_MSG( m_cgContext != NULL, _T("Unable to retrieve drawing context from View"));
+        }
+        else
+        {
+            m_invisible = true;
+        }
+#endif
+#if wxOSX_USE_CARBON
         OSStatus status = QDBeginCGContext( GetWindowPort( m_windowRef ) , &m_cgContext );
         if ( status != noErr )
         {
             wxFAIL_MSG("Cannot nest wxDCs on the same window");
         }
-
-        CGContextConcatCTM( m_cgContext, m_windowTransform );
-        CGContextSaveGState( m_cgContext );
-        m_releaseContext = true;
-        if ( m_clipRgn.get() )
+#endif
+        if ( m_cgContext )
         {
-            // the clip region is in device coordinates, so we convert this again to user coordinates
-            wxCFRef<HIMutableShapeRef> hishape( HIShapeCreateMutableCopy( m_clipRgn ) );
-            CGPoint transformedOrigin = CGPointApplyAffineTransform( CGPointZero,m_windowTransform);
-            HIShapeOffset( hishape, -transformedOrigin.x, -transformedOrigin.y );
-            // if the shape is empty, HIShapeReplacePathInCGContext doesn't work
-            if ( HIShapeIsEmpty(hishape))
+            CGContextConcatCTM( m_cgContext, m_windowTransform );
+            CGContextSaveGState( m_cgContext );
+            m_contextSynthesized = true;
+            if ( m_clipRgn.get() )
             {
-                CGRect empty = CGRectMake( 0,0,0,0 );
-                CGContextClipToRect( m_cgContext, empty );
+                // the clip region is in device coordinates, so we convert this again to user coordinates
+                wxCFRef<HIMutableShapeRef> hishape( HIShapeCreateMutableCopy( m_clipRgn ) );
+                CGPoint transformedOrigin = CGPointApplyAffineTransform( CGPointZero,m_windowTransform);
+                HIShapeOffset( hishape, -transformedOrigin.x, -transformedOrigin.y );
+                // if the shape is empty, HIShapeReplacePathInCGContext doesn't work
+                if ( HIShapeIsEmpty(hishape))
+                {
+                    CGRect empty = CGRectMake( 0,0,0,0 );
+                    CGContextClipToRect( m_cgContext, empty );
+                }
+                else
+                {
+                    HIShapeReplacePathInCGContext( hishape, m_cgContext );
+                    CGContextClip( m_cgContext );
+                }
             }
-            else
+            CGContextSaveGState( m_cgContext );
+            
+#if 0 // turn on for debugging of clientdc
+            static float color = 0.5 ;
+            static int channel = 0 ;
+            CGRect bounds = CGRectMake(-1000,-1000,2000,2000);
+            CGContextSetRGBFillColor( m_cgContext, channel == 0 ? color : 0.5 ,
+                channel == 1 ? color : 0.5 , channel == 2 ? color : 0.5 , 1 );
+            CGContextFillRect( m_cgContext, bounds );
+            color += 0.1 ;
+            if ( color > 0.9 )
             {
-                HIShapeReplacePathInCGContext( hishape, m_cgContext );
-                CGContextClip( m_cgContext );
+                color = 0.5 ;
+                channel++ ;
+                if ( channel == 3 )
+                    channel = 0 ;
             }
-        }
-        CGContextSaveGState( m_cgContext );
 #endif
+        }
     }
+    return m_cgContext != NULL;
 }
 
 // TODO test whether the private CGContextSetCompositeOperation works under 10.3 (using NSCompositingModes)
@@ -1579,8 +1640,9 @@ bool wxMacCoreGraphicsContext::SetLogicalFunction( wxRasterOperationMode functio
     if (m_logicalFunction == function)
         return true;
 
-    EnsureIsValid();
-
+    if (EnsureIsValid()==false)
+        return true;
+        
     bool retval = false;
     bool shouldAntiAlias = true;
     CGBlendMode mode = kCGBlendModeNormal;
@@ -1638,7 +1700,7 @@ bool wxMacCoreGraphicsContext::SetLogicalFunction( wxRasterOperationMode functio
 
 void wxMacCoreGraphicsContext::Clip( const wxRegion &region )
 {
-#if wxOSX_USE_CARBON
+#if wxOSX_USE_COCOA_OR_CARBON
     if( m_cgContext )
     {
         wxCFRef<HIShapeRef> shape = wxCFRefFromGet(region.GetWXHRGN());
@@ -1680,7 +1742,7 @@ void wxMacCoreGraphicsContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDoubl
     }
     else
     {
-#if wxOSX_USE_CARBON
+#if wxOSX_USE_COCOA_OR_CARBON
         // the clipping itself must be stored as device coordinates, otherwise
         // we cannot apply it back correctly
         r.origin= CGPointApplyAffineTransform( r.origin, m_windowTransform );
@@ -1709,7 +1771,7 @@ void wxMacCoreGraphicsContext::ResetClip()
     }
     else
     {
-#if wxOSX_USE_CARBON
+#if wxOSX_USE_COCOA_OR_CARBON
         m_clipRgn.reset();
 #else
     // allow usage as measuring context
@@ -1723,8 +1785,9 @@ void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath &path )
     if ( m_pen.IsNull() )
         return ;
 
-    EnsureIsValid();
-
+    if (EnsureIsValid()==false)
+        return;
+        
     wxQuartzOffsetHelper helper( m_cgContext , ShouldOffset() );
 
     ((wxMacCoreGraphicsPenData*)m_pen.GetRefData())->Apply(this);
@@ -1734,6 +1797,9 @@ void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath &path )
 
 void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath &path , wxPolygonFillMode fillStyle )
 {
+    if (EnsureIsValid()==false)
+        return;
+        
     if ( !m_brush.IsNull() && ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->IsShading() )
     {
         // when using shading, we cannot draw pen and brush at the same time
@@ -1768,8 +1834,6 @@ void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath &path , wxPolygonF
         }
     }
 
-    EnsureIsValid();
-
     if ( !m_brush.IsNull() )
         ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->Apply(this);
     if ( !m_pen.IsNull() )
@@ -1786,8 +1850,9 @@ void wxMacCoreGraphicsContext::FillPath( const wxGraphicsPath &path , wxPolygonF
     if ( m_brush.IsNull() )
         return;
 
-    EnsureIsValid();
-
+    if (EnsureIsValid()==false)
+        return;
+        
     if ( ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->IsShading() )
     {
         CGContextSaveGState( m_cgContext );
@@ -1814,20 +1879,24 @@ void wxMacCoreGraphicsContext::SetNativeContext( CGContextRef cg )
 
     if ( m_cgContext )
     {
-        // TODO : when is this necessary - should we add a Flush() method ? CGContextSynchronize( m_cgContext );
         CGContextRestoreGState( m_cgContext );
         CGContextRestoreGState( m_cgContext );
-        if ( m_releaseContext )
+        if ( m_contextSynthesized )
         {
+            // TODO: in case of performance problems, try issuing this not too 
+            // frequently (half of refresh rate)
+            CGContextFlush(m_cgContext);
 #if wxOSX_USE_CARBON
             QDEndCGContext( GetWindowPort( m_windowRef ) , &m_cgContext);
+#endif
+#if wxOSX_USE_COCOA_OR_IPHONE
+            wxOSXUnlockFocus(m_view);
 #endif
         }
         else
             CGContextRelease(m_cgContext);
     }
 
-
     m_cgContext = cg;
 
     // FIXME: This check is needed because currently we need to use a DC/GraphicsContext
@@ -1843,7 +1912,7 @@ void wxMacCoreGraphicsContext::SetNativeContext( CGContextRef cg )
         CGContextSaveGState( m_cgContext );
         CGContextSetTextMatrix( m_cgContext, CGAffineTransformIdentity );
         CGContextSaveGState( m_cgContext );
-        m_releaseContext = false;
+        m_contextSynthesized = false;
     }
 }
 
@@ -1879,7 +1948,9 @@ void wxMacCoreGraphicsContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDo
 
 void wxMacCoreGraphicsContext::DrawBitmap( const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
 {
-    EnsureIsValid();
+    if (EnsureIsValid()==false)
+        return;
+        
 #ifdef __WXMAC__
     wxMacCoreGraphicsBitmapData* refdata  =static_cast<wxMacCoreGraphicsBitmapData*>(bmp.GetRefData());
     CGImageRef image = refdata->GetBitmap();
@@ -1916,30 +1987,33 @@ void wxMacCoreGraphicsContext::DrawBitmap( const wxGraphicsBitmap &bmp, wxDouble
 
 void wxMacCoreGraphicsContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
 {
-    EnsureIsValid();
-
+    if (EnsureIsValid()==false)
+        return;
+        
     CGRect r = CGRectMake( (CGFloat) 0.0 , (CGFloat) 0.0 , (CGFloat) w , (CGFloat) h );
     CGContextSaveGState( m_cgContext );
     CGContextTranslateCTM( m_cgContext,(CGFloat) x ,(CGFloat) (y + h) );
     CGContextScaleCTM( m_cgContext, 1, -1 );
-#if wxOSX_USE_CARBON
+#if wxOSX_USE_COCOA_OR_CARBON
     PlotIconRefInContext( m_cgContext , &r , kAlignNone , kTransformNone ,
-        NULL , kPlotIconRefNormalFlags , MAC_WXHICON( icon.GetHICON() ) );
+        NULL , kPlotIconRefNormalFlags , icon.GetHICON() );
 #endif
     CGContextRestoreGState( m_cgContext );
 }
 
 void wxMacCoreGraphicsContext::PushState()
 {
-    EnsureIsValid();
-
+    if (EnsureIsValid()==false)
+        return;
+        
     CGContextSaveGState( m_cgContext );
 }
 
 void wxMacCoreGraphicsContext::PopState()
 {
-    EnsureIsValid();
-
+    if (EnsureIsValid()==false)
+        return;
+        
     CGContextRestoreGState( m_cgContext );
 }
 
@@ -1947,7 +2021,9 @@ void wxMacCoreGraphicsContext::DoDrawText( const wxString &str, wxDouble x, wxDo
 {
     wxCHECK_RET( !m_font.IsNull(), wxT("wxMacCoreGraphicsContext::DrawText - no valid font set") );
 
-    EnsureIsValid();
+    if (EnsureIsValid()==false)
+        return;
+        
 #if wxOSX_USE_CORE_TEXT
     if ( UMAGetSystemVersion() >= 0x1050 )
     {
@@ -2005,7 +2081,9 @@ void wxMacCoreGraphicsContext::DoDrawRotatedText(const wxString &str,
 {
     wxCHECK_RET( !m_font.IsNull(), wxT("wxMacCoreGraphicsContext::DrawText - no valid font set") );
 
-    EnsureIsValid();
+    if (EnsureIsValid()==false)
+        return;
+        
 #if wxOSX_USE_CORE_TEXT
     if ( UMAGetSystemVersion() >= 0x1050 )
     {
@@ -2422,10 +2500,6 @@ wxGraphicsRenderer* wxGraphicsRenderer::GetDefaultRenderer()
     return &gs_MacCoreGraphicsRenderer;
 }
 
-#if defined( __WXCOCOA__ ) || wxOSX_USE_COCOA
-extern CGContextRef wxMacGetContextFromCurrentNSContext() ;
-#endif
-
 wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContext( const wxWindowDC& dc )
 {
     const wxDCImpl* impl = dc.GetImpl();
@@ -2435,12 +2509,13 @@ wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContext( const wxWindowDC&
         int w, h;
         win_impl->GetSize( &w, &h );
         CGContextRef cgctx = 0;
-#ifdef __WXMAC__
-        cgctx =  (CGContextRef)(win_impl->GetWindow()->MacGetCGContextRef());
-#else
-        cgctx = wxMacGetContextFromCurrentNSContext() ;
-#endif
-        return new wxMacCoreGraphicsContext( this, cgctx, (wxDouble) w, (wxDouble) h );
+
+        wxASSERT_MSG(win_impl->GetWindow(), "Invalid wxWindow in wxMacCoreGraphicsRenderer::CreateContext");
+        if (win_impl->GetWindow())
+            cgctx =  (CGContextRef)(win_impl->GetWindow()->MacGetCGContextRef());
+
+        if (cgctx != 0)
+            return new wxMacCoreGraphicsContext( this, cgctx, (wxDouble) w, (wxDouble) h );
     }
     return NULL;
 }