From 75c25a8219701b4e8e9c521c3c18e22fd2bd8b09 Mon Sep 17 00:00:00 2001 From: Stefan Csomor Date: Tue, 10 Apr 2007 11:23:51 +0000 Subject: [PATCH] fixing refcounting for embedded native controls git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@45376 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- src/mac/carbon/toolbar.cpp | 52 ++++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/src/mac/carbon/toolbar.cpp b/src/mac/carbon/toolbar.cpp index 9d0bf0cb1d..88c664f9bc 100644 --- a/src/mac/carbon/toolbar.cpp +++ b/src/mac/carbon/toolbar.cpp @@ -58,6 +58,16 @@ END_EVENT_TABLE() // We have a dual implementation for each tool, ControlRef and HIToolbarItemRef +// when embedding native controls in the native toolbar we must make sure the +// control does not get deleted behind our backs, so the retain count gets increased +// (after creation it is 1), first be the creation of the custom HIToolbarItem wrapper +// object, and second by the code 'creating' the custom HIView (which is the same as the +// already existing native control, therefore we just increase the ref count) +// when this view is removed from the native toolbar its count gets decremented again +// and when the HITooolbarItem wrapper object gets destroyed it is decremented as well +// so in the end the control lives with a refcount of one and can be disposed of by the +// wxControl code + class wxToolBarTool : public wxToolBarToolBase { public: @@ -99,17 +109,19 @@ public: void ClearControl() { - m_control = NULL; if ( m_controlHandle ) { if ( !IsControl() ) DisposeControl( m_controlHandle ); else { - // the embedded control is not under the responsibility of the tool + // the embedded control is not under the responsibility of the tool, it will be disposed of in the + // proper wxControl destructor + wxASSERT( IsValidControlHandle(GetControl()->GetPeer()->GetControlRef() )) ; } m_controlHandle = NULL ; } + m_control = NULL; #if wxMAC_USE_NATIVE_TOOLBAR if ( m_toolbarItemRef ) @@ -617,19 +629,25 @@ static pascal OSStatus ControlToolbarItemHandler( EventHandlerCallRef inCallRef, memcpy( &viewRef , CFDataGetBytePtr( data ) , sizeof( viewRef ) ) ; object->viewRef = (HIViewRef) viewRef ; + // make sure we keep that control during our lifetime + CFRetain( object->viewRef ) ; + verify_noerr(InstallEventHandler( GetControlEventTarget( viewRef ), ControlToolbarItemHandler, + GetEventTypeCount( kViewEvents ), kViewEvents, object, NULL )); result = noErr ; } break; case kEventHIObjectDestruct: { - // we've increased the ref count when creating this, so we decrease manually again in case - // it was never really installed and deinstalled HIViewRef viewRef = object->viewRef ; + wxASSERT( IsValidControlHandle(viewRef) ) ; if( viewRef && IsValidControlHandle( viewRef) ) { + // depending whether the wxControl corresponding to this HIView has already been destroyed or + // not, ref counts differ, so we cannot assert a special value CFIndex count = CFGetRetainCount( viewRef ) ; + wxASSERT_MSG( count >=1 , wxT("Reference Count of native tool was illegal before removal") ); if ( count >= 1 ) CFRelease( viewRef ) ; } @@ -646,12 +664,9 @@ static pascal OSStatus ControlToolbarItemHandler( EventHandlerCallRef inCallRef, case kEventToolbarItemCreateCustomView: { HIViewRef viewRef = object->viewRef ; - HIViewRemoveFromSuperview( viewRef ) ; HIViewSetVisible(viewRef, true) ; - InstallEventHandler( GetControlEventTarget( viewRef ), ControlToolbarItemHandler, - GetEventTypeCount( kViewEvents ), kViewEvents, object, NULL ); - + CFRetain( viewRef ) ; result = SetEventParameter( inEvent, kEventParamControlRef, typeControlRef, sizeof( HIViewRef ), &viewRef ); } break; @@ -1168,12 +1183,24 @@ bool wxToolBar::Realize() const long idx = tool2->GetIndex(); if ( idx != -1 ) { + if ( tool2->IsControl() ) + { + CFIndex count = CFGetRetainCount( tool2->GetControl()->GetPeer()->GetControlRef() ) ; + wxASSERT_MSG( count == 3 , wxT("Reference Count of native tool was not 3 before removal") ); + wxASSERT( IsValidControlHandle(tool2->GetControl()->GetPeer()->GetControlRef() )) ; + } err = HIToolbarRemoveItemAtIndex(refTB, idx); if ( err != noErr ) { wxLogDebug(wxT("HIToolbarRemoveItemAtIndex(%ld) failed [%ld]"), idx, (long)err); } + if ( tool2->IsControl() ) + { + CFIndex count = CFGetRetainCount( tool2->GetControl()->GetPeer()->GetControlRef() ) ; + wxASSERT_MSG( count == 2 , wxT("Reference Count of native tool was not 2 after removal") ); + wxASSERT( IsValidControlHandle(tool2->GetControl()->GetPeer()->GetControlRef() )) ; + } tool2->SetIndex(-1); } @@ -1187,6 +1214,12 @@ bool wxToolBar::Realize() } tool->SetIndex( currentPosition ); + if ( tool->IsControl() ) + { + CFIndex count = CFGetRetainCount( tool->GetControl()->GetPeer()->GetControlRef() ) ; + wxASSERT_MSG( count == 3 , wxT("Reference Count of native tool was not 3 after insertion") ); + wxASSERT( IsValidControlHandle(tool->GetControl()->GetPeer()->GetControlRef() )) ; + } } currentPosition++; @@ -1503,9 +1536,6 @@ bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos), wxToolBarToolBase *toolBase) wxCHECK_MSG( tool->GetControl(), false, _T("control must be non-NULL") ); HIViewRef viewRef = (HIViewRef) tool->GetControl()->GetHandle() ; - // as this control now is part of both the wxToolBar children and the native toolbar, we have to increase the - // reference count to make sure we are not dealing with zombie controls after the native toolbar has released its views - CFRetain( viewRef ) ; CFDataRef data = CFDataCreate( kCFAllocatorDefault , (UInt8*) &viewRef , sizeof(viewRef) ) ; err = HIToolbarCreateItemWithIdentifier((HIToolbarRef) m_macHIToolbarRef,kControlToolbarItemClassID, data , &item ) ; -- 2.45.2