fixing refcounting for embedded native controls, backporting code for Realize
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/WX_2_8_BRANCH@45375 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -58,6 +58,16 @@ END_EVENT_TABLE()
|
|||||||
|
|
||||||
// We have a dual implementation for each tool, ControlRef and HIToolbarItemRef
|
// 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
|
class wxToolBarTool : public wxToolBarToolBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -99,18 +109,20 @@ public:
|
|||||||
|
|
||||||
void ClearControl()
|
void ClearControl()
|
||||||
{
|
{
|
||||||
m_control = NULL;
|
|
||||||
if ( m_controlHandle )
|
if ( m_controlHandle )
|
||||||
{
|
{
|
||||||
if ( !IsControl() )
|
if ( !IsControl() )
|
||||||
DisposeControl( m_controlHandle );
|
DisposeControl( m_controlHandle );
|
||||||
else
|
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_controlHandle = NULL ;
|
||||||
}
|
}
|
||||||
|
m_control = NULL;
|
||||||
|
|
||||||
#if wxMAC_USE_NATIVE_TOOLBAR
|
#if wxMAC_USE_NATIVE_TOOLBAR
|
||||||
if ( m_toolbarItemRef )
|
if ( m_toolbarItemRef )
|
||||||
{
|
{
|
||||||
@@ -616,19 +628,25 @@ static pascal OSStatus ControlToolbarItemHandler( EventHandlerCallRef inCallRef,
|
|||||||
memcpy( &viewRef , CFDataGetBytePtr( data ) , sizeof( viewRef ) ) ;
|
memcpy( &viewRef , CFDataGetBytePtr( data ) , sizeof( viewRef ) ) ;
|
||||||
|
|
||||||
object->viewRef = (HIViewRef) 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 ;
|
result = noErr ;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kEventHIObjectDestruct:
|
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 ;
|
HIViewRef viewRef = object->viewRef ;
|
||||||
|
wxASSERT( IsValidControlHandle(viewRef) ) ;
|
||||||
if( viewRef && 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 ) ;
|
CFIndex count = CFGetRetainCount( viewRef ) ;
|
||||||
|
wxASSERT_MSG( count >=1 , wxT("Reference Count of native tool was illegal before removal") );
|
||||||
if ( count >= 1 )
|
if ( count >= 1 )
|
||||||
CFRelease( viewRef ) ;
|
CFRelease( viewRef ) ;
|
||||||
}
|
}
|
||||||
@@ -645,12 +663,9 @@ static pascal OSStatus ControlToolbarItemHandler( EventHandlerCallRef inCallRef,
|
|||||||
case kEventToolbarItemCreateCustomView:
|
case kEventToolbarItemCreateCustomView:
|
||||||
{
|
{
|
||||||
HIViewRef viewRef = object->viewRef ;
|
HIViewRef viewRef = object->viewRef ;
|
||||||
|
HIViewRemoveFromSuperview( viewRef ) ;
|
||||||
HIViewRemoveFromSuperview( viewRef ) ;
|
|
||||||
HIViewSetVisible(viewRef, true) ;
|
HIViewSetVisible(viewRef, true) ;
|
||||||
InstallEventHandler( GetControlEventTarget( viewRef ), ControlToolbarItemHandler,
|
CFRetain( viewRef ) ;
|
||||||
GetEventTypeCount( kViewEvents ), kViewEvents, object, NULL );
|
|
||||||
|
|
||||||
result = SetEventParameter( inEvent, kEventParamControlRef, typeControlRef, sizeof( HIViewRef ), &viewRef );
|
result = SetEventParameter( inEvent, kEventParamControlRef, typeControlRef, sizeof( HIViewRef ), &viewRef );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1155,11 +1170,37 @@ bool wxToolBar::Realize()
|
|||||||
|
|
||||||
// if this is the first tool that gets newly inserted or repositioned
|
// if this is the first tool that gets newly inserted or repositioned
|
||||||
// first remove all 'old' tools from here to the right, because of this
|
// first remove all 'old' tools from here to the right, because of this
|
||||||
// all following tools will have to be reinserted (insertAll). i = 100 because there's
|
// all following tools will have to be reinserted (insertAll).
|
||||||
// no way to determine how many there are in a toolbar, so just a high number :-(
|
for ( wxToolBarToolsList::compatibility_iterator node2 = m_tools.GetLast();
|
||||||
for ( CFIndex i = 100; i >= currentPosition; --i )
|
node2 != node;
|
||||||
|
node2 = node2->GetPrevious() )
|
||||||
{
|
{
|
||||||
err = HIToolbarRemoveItemAtIndex( (HIToolbarRef) m_macHIToolbarRef, i );
|
wxToolBarTool *tool2 = (wxToolBarTool*) node2->GetData();
|
||||||
|
|
||||||
|
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((HIToolbarRef) m_macHIToolbarRef, 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err != noErr)
|
if (err != noErr)
|
||||||
@@ -1177,6 +1218,12 @@ bool wxToolBar::Realize()
|
|||||||
}
|
}
|
||||||
|
|
||||||
tool->SetIndex( currentPosition );
|
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++;
|
currentPosition++;
|
||||||
@@ -1493,9 +1540,6 @@ bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos), wxToolBarToolBase *toolBase)
|
|||||||
wxASSERT( tool->GetControl() != NULL );
|
wxASSERT( tool->GetControl() != NULL );
|
||||||
HIToolbarItemRef item;
|
HIToolbarItemRef item;
|
||||||
HIViewRef viewRef = (HIViewRef) tool->GetControl()->GetHandle() ;
|
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) ) ;
|
CFDataRef data = CFDataCreate( kCFAllocatorDefault , (UInt8*) &viewRef , sizeof(viewRef) ) ;
|
||||||
err = HIToolbarCreateItemWithIdentifier((HIToolbarRef) m_macHIToolbarRef,kControlToolbarItemClassID,
|
err = HIToolbarCreateItemWithIdentifier((HIToolbarRef) m_macHIToolbarRef,kControlToolbarItemClassID,
|
||||||
data , &item ) ;
|
data , &item ) ;
|
||||||
|
Reference in New Issue
Block a user