X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/bbd321ffc2d4e7f9e45c72af9e3f824fa9ccda51..653a54d04953da64d79bf088c5b067ccce955c7a:/src/mac/carbon/toolbar.cpp diff --git a/src/mac/carbon/toolbar.cpp b/src/mac/carbon/toolbar.cpp index f65ba6d135..f7bcdf598c 100644 --- a/src/mac/carbon/toolbar.cpp +++ b/src/mac/carbon/toolbar.cpp @@ -58,6 +58,17 @@ 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. For embedded controls on a non-native toolbar this ref count is less +// so we can only test against a range, not a specific value of the refcount. + class wxToolBarTool : public wxToolBarToolBase { public: @@ -72,8 +83,8 @@ public: const wxString& shortHelp, const wxString& longHelp ); - wxToolBarTool(wxToolBar *tbar, wxControl *control) - : wxToolBarToolBase(tbar, control) + wxToolBarTool(wxToolBar *tbar, wxControl *control, const wxString& label) + : wxToolBarToolBase(tbar, control, label) { Init(); if (control != NULL) @@ -99,17 +110,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 ) @@ -176,7 +189,7 @@ public: enc = f.GetEncoding(); else enc = wxFont::GetDefaultEncoding(); - + HIToolbarItemSetHelpText( m_toolbarItemRef, wxMacCFStringHolder( GetShortHelp(), enc ), @@ -533,9 +546,10 @@ wxToolBarToolBase *wxToolBar::CreateTool( clientData, shortHelp, longHelp ); } -wxToolBarToolBase * wxToolBar::CreateTool( wxControl *control ) +wxToolBarToolBase * +wxToolBar::CreateTool(wxControl *control, const wxString& label) { - return new wxToolBarTool( this, control ); + return new wxToolBarTool(this, control, label); } void wxToolBar::Init() @@ -553,26 +567,26 @@ void wxToolBar::Init() #define kControlToolbarItemClassID CFSTR( "org.wxwidgets.controltoolbaritem" ) -const EventTypeSpec kEvents[] = +const EventTypeSpec kEvents[] = { { kEventClassHIObject, kEventHIObjectConstruct }, { kEventClassHIObject, kEventHIObjectInitialize }, { kEventClassHIObject, kEventHIObjectDestruct }, - + { kEventClassToolbarItem, kEventToolbarItemCreateCustomView } }; -const EventTypeSpec kViewEvents[] = -{ - { kEventClassControl, kEventControlGetSizeConstraints } +const EventTypeSpec kViewEvents[] = +{ + { kEventClassControl, kEventControlGetSizeConstraints } }; -struct ControlToolbarItem -{ - HIToolbarItemRef toolbarItem; +struct ControlToolbarItem +{ + HIToolbarItemRef toolbarItem; HIViewRef viewRef; wxSize lastValidSize ; -}; +}; static pascal OSStatus ControlToolbarItemHandler( EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData ) { @@ -588,20 +602,21 @@ static pascal OSStatus ControlToolbarItemHandler( EventHandlerCallRef inCallRef, { HIObjectRef toolbarItem; ControlToolbarItem* item; - + GetEventParameter( inEvent, kEventParamHIObjectInstance, typeHIObjectRef, NULL, sizeof( HIObjectRef ), NULL, &toolbarItem ); - + item = (ControlToolbarItem*) malloc(sizeof(ControlToolbarItem)) ; item->toolbarItem = toolbarItem ; + item->lastValidSize = wxSize(-1,-1); item->viewRef = NULL ; - + SetEventParameter( inEvent, kEventParamHIObjectInstance, typeVoidPtr, sizeof( void * ), &item ); - + result = noErr ; } break; - + case kEventHIObjectInitialize: result = CallNextEventHandler( inCallRef, inEvent ); if ( result == noErr ) @@ -609,26 +624,31 @@ static pascal OSStatus ControlToolbarItemHandler( EventHandlerCallRef inCallRef, CFDataRef data; GetEventParameter( inEvent, kEventParamToolbarItemConfigData, typeCFTypeRef, NULL, sizeof( CFTypeRef ), NULL, &data ); - + HIViewRef viewRef ; - + wxASSERT_MSG( CFDataGetLength( data ) == sizeof( viewRef ) , wxT("Illegal Data passed") ) ; 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 ; if( viewRef && IsValidControlHandle( viewRef) ) { - CFIndex count = CFGetRetainCount( 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 ) ; } @@ -638,25 +658,22 @@ static pascal OSStatus ControlToolbarItemHandler( EventHandlerCallRef inCallRef, break; } break; - + case kEventClassToolbarItem: switch ( GetEventKind( inEvent ) ) - { + { 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; } break; - + case kEventClassControl: switch ( GetEventKind( inEvent ) ) { @@ -665,24 +682,29 @@ static pascal OSStatus ControlToolbarItemHandler( EventHandlerCallRef inCallRef, wxWindow* wxwindow = wxFindControlFromMacControl(object->viewRef ) ; if ( wxwindow ) { - wxSize sz = wxwindow->GetSize() ; - sz.x -= wxwindow->MacGetLeftBorderSize() + wxwindow->MacGetRightBorderSize(); - sz.y -= wxwindow->MacGetTopBorderSize() + wxwindow->MacGetBottomBorderSize(); - // during toolbar layout the native window sometimes gets negative sizes - // so we always keep the last valid size here, to make sure we survive the - // shuffle ... - if ( sz.x > 0 && sz.y > 0 ) - object->lastValidSize = sz ; - else - sz = object->lastValidSize ; - + // during toolbar layout the native window sometimes gets negative sizes, + // sometimes it just gets shrunk behind our back, so in order to avoid + // ever shrinking more, once a valid size is captured, we keep it + + wxSize sz = object->lastValidSize; + if ( sz.x <= 0 || sz.y <= 0 ) + { + sz = wxwindow->GetSize() ; + sz.x -= wxwindow->MacGetLeftBorderSize() + wxwindow->MacGetRightBorderSize(); + sz.y -= wxwindow->MacGetTopBorderSize() + wxwindow->MacGetBottomBorderSize(); + if ( sz.x > 0 && sz.y > 0 ) + object->lastValidSize = sz ; + else + sz = wxSize(0,0) ; + } + HISize min, max; min.width = max.width = sz.x ; min.height = max.height = sz.y ; - + result = SetEventParameter( inEvent, kEventParamMinimumSize, typeHISize, sizeof( HISize ), &min ); - + result = SetEventParameter( inEvent, kEventParamMaximumSize, typeHISize, sizeof( HISize ), &max ); result = noErr ; @@ -692,19 +714,19 @@ static pascal OSStatus ControlToolbarItemHandler( EventHandlerCallRef inCallRef, } break; } - + return result; } void RegisterControlToolbarItemClass() { static bool sRegistered; - + if ( !sRegistered ) { HIObjectRegisterSubclass( kControlToolbarItemClassID, kHIToolbarItemClassID, 0, ControlToolbarItemHandler, GetEventTypeCount( kEvents ), kEvents, 0, NULL ); - + sRegistered = true; } } @@ -712,26 +734,26 @@ void RegisterControlToolbarItemClass() HIToolbarItemRef CreateControlToolbarItem(CFStringRef inIdentifier, CFTypeRef inConfigData) { RegisterControlToolbarItemClass(); - + OSStatus err; EventRef event; UInt32 options = kHIToolbarItemAllowDuplicates; HIToolbarItemRef result = NULL; - + err = CreateEvent( NULL, kEventClassHIObject, kEventHIObjectInitialize, GetCurrentEventTime(), 0, &event ); require_noerr( err, CantCreateEvent ); - + SetEventParameter( event, kEventParamAttributes, typeUInt32, sizeof( UInt32 ), &options ); SetEventParameter( event, kEventParamToolbarItemIdentifier, typeCFStringRef, sizeof( CFStringRef ), &inIdentifier ); - + if ( inConfigData ) SetEventParameter( event, kEventParamToolbarItemConfigData, typeCFTypeRef, sizeof( CFTypeRef ), &inConfigData ); - + err = HIObjectCreate( kControlToolbarItemClassID, event, (HIObjectRef*)&result ); check_noerr( err ); - + ReleaseEvent( event ); -CantCreateEvent : +CantCreateEvent : return result ; } @@ -761,7 +783,7 @@ static OSStatus ToolbarDelegateHandler( EventHandlerCallRef inCallRef, EventRef result = noErr; } break; - + case kEventToolbarGetAllowedIdentifiers: { GetEventParameter( inEvent, kEventParamMutableArray, typeCFMutableArrayRef, NULL, @@ -776,13 +798,13 @@ static OSStatus ToolbarDelegateHandler( EventHandlerCallRef inCallRef, EventRef HIToolbarItemRef item = NULL; CFTypeRef data = NULL; CFStringRef identifier = NULL ; - + GetEventParameter( inEvent, kEventParamToolbarItemIdentifier, typeCFStringRef, NULL, sizeof( CFStringRef ), NULL, &identifier ); - + GetEventParameter( inEvent, kEventParamToolbarItemConfigData, typeCFTypeRef, NULL, sizeof( CFTypeRef ), NULL, &data ); - + if ( CFStringCompare( kControlToolbarItemClassID, identifier, kCFCompareBackwards ) == kCFCompareEqualTo ) { item = CreateControlToolbarItem( kControlToolbarItemClassID, data ); @@ -793,7 +815,7 @@ static OSStatus ToolbarDelegateHandler( EventHandlerCallRef inCallRef, EventRef result = noErr; } } - + } break; } @@ -843,7 +865,7 @@ bool wxToolBar::Create( HIToolbarSetDisplayMode( (HIToolbarRef) m_macHIToolbarRef, mode ); HIToolbarSetDisplaySize( (HIToolbarRef) m_macHIToolbarRef, displaySize ); } -#endif +#endif // wxMAC_USE_NATIVE_TOOLBAR return (err == noErr); } @@ -1102,6 +1124,8 @@ bool wxToolBar::Realize() #if wxMAC_USE_NATIVE_TOOLBAR CFIndex currentPosition = 0; bool insertAll = false; + + HIToolbarRef refTB = (HIToolbarRef)m_macHIToolbarRef; #endif node = m_tools.GetFirst(); @@ -1141,9 +1165,9 @@ bool wxToolBar::Realize() #if wxMAC_USE_NATIVE_TOOLBAR // install in native HIToolbar - if ( m_macHIToolbarRef != NULL ) + if ( refTB ) { - HIToolbarItemRef hiItemRef = tool->GetToolbarItemRef(); + HIToolbarItemRef hiItemRef = tool->GetToolbarItemRef(); if ( hiItemRef != NULL ) { if ( insertAll || (tool->GetIndex() != currentPosition) ) @@ -1155,28 +1179,53 @@ bool wxToolBar::Realize() // 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 - // all following tools will have to be reinserted (insertAll). i = 100 because there's - // no way to determine how many there are in a toolbar, so just a high number :-( - for ( CFIndex i = 100; i >= currentPosition; --i ) + // all following tools will have to be reinserted (insertAll). + for ( wxToolBarToolsList::compatibility_iterator node2 = m_tools.GetLast(); + node2 != node; + node2 = node2->GetPrevious() ) { - err = HIToolbarRemoveItemAtIndex( (HIToolbarRef) m_macHIToolbarRef, i ); - } - - if (err != noErr) - { - wxString errMsg = wxString::Format( wxT("HIToolbarRemoveItemAtIndex failed [%ld]"), (long)err ); - wxFAIL_MSG( errMsg.c_str() ); + 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 || count == 2 , wxT("Reference Count of native tool was illegal 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); + } } } - err = HIToolbarInsertItemAtIndex( (HIToolbarRef) m_macHIToolbarRef, hiItemRef, currentPosition ); + err = HIToolbarInsertItemAtIndex( refTB, hiItemRef, currentPosition ); if (err != noErr) { - wxString errMsg = wxString::Format( wxT("HIToolbarInsertItemAtIndex failed [%ld]"), (long)err ); - wxFAIL_MSG( errMsg.c_str() ); + wxLogDebug( wxT("HIToolbarInsertItemAtIndex failed [%ld]"), (long)err ); } tool->SetIndex( currentPosition ); + if ( tool->IsControl() ) + { + CFIndex count = CFGetRetainCount( tool->GetControl()->GetPeer()->GetControlRef() ) ; + wxASSERT_MSG( count == 3 || count == 2, wxT("Reference Count of native tool was illegal after insertion") ); + wxASSERT( IsValidControlHandle(tool->GetControl()->GetPeer()->GetControlRef() )) ; + } } currentPosition++; @@ -1332,7 +1381,7 @@ void wxToolBar::SetToolNormalBitmap( int id, const wxBitmap& bitmap ) // a side-effect of the UpdateToggleImage function is that it always changes the bitmap used on the button. tool->UpdateToggleImage( tool->CanBeToggled() && tool->IsToggled() ); - } + } } void wxToolBar::SetToolDisabledBitmap( int id, const wxBitmap& bitmap ) @@ -1343,9 +1392,9 @@ void wxToolBar::SetToolDisabledBitmap( int id, const wxBitmap& bitmap ) wxCHECK_RET( tool->IsButton(), wxT("Can only set bitmap on button tools.")); tool->SetDisabledBitmap(bitmap); - + // TODO: what to do for this one? - } + } } wxToolBarToolBase *wxToolBar::FindToolForPosition(wxCoord x, wxCoord y) const @@ -1403,6 +1452,10 @@ bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos), wxToolBarToolBase *toolBase) OSStatus err = 0; tool->Attach( this ); +#if wxMAC_USE_NATIVE_TOOLBAR + HIToolbarItemRef item; +#endif + switch (tool->GetStyle()) { case wxTOOL_STYLE_SEPARATOR: @@ -1415,21 +1468,18 @@ bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos), wxToolBarToolBase *toolBase) else toolrect.right = toolSize.x; -#ifdef __WXMAC_OSX__ // in flat style we need a visual separator #if wxMAC_USE_NATIVE_TOOLBAR - HIToolbarItemRef item; err = HIToolbarItemCreate( kHIToolbarSeparatorIdentifier, kHIToolbarItemCantBeRemoved | kHIToolbarItemIsSeparator | kHIToolbarItemAllowDuplicates, &item ); if (err == noErr) tool->SetToolbarItemRef( item ); -#endif +#endif // wxMAC_USE_NATIVE_TOOLBAR CreateSeparatorControl( window, &toolrect, &controlHandle ); tool->SetControlHandle( controlHandle ); -#endif } break; @@ -1454,7 +1504,6 @@ bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos), wxToolBarToolBase *toolBase) } #if wxMAC_USE_NATIVE_TOOLBAR - HIToolbarItemRef item; wxString labelStr = wxString::Format(wxT("%xd"), (int)tool); err = HIToolbarItemCreate( wxMacCFStringHolder(labelStr, wxFont::GetDefaultEncoding()), @@ -1464,12 +1513,12 @@ bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos), wxToolBarToolBase *toolBase) InstallEventHandler( HIObjectGetEventTarget(item), GetwxMacToolBarEventHandlerUPP(), GetEventTypeCount(toolBarEventList), toolBarEventList, tool, NULL ); - HIToolbarItemSetLabel( item, wxMacCFStringHolder(tool->GetLabel(), m_font.GetEncoding()) ); + HIToolbarItemSetIconRef( item, info.u.iconRef ); HIToolbarItemSetCommandID( item, kHIToolbarCommandPressAction ); tool->SetToolbarItemRef( item ); } -#endif +#endif // wxMAC_USE_NATIVE_TOOLBAR wxMacReleaseBitmapButton( &info ); @@ -1490,15 +1539,12 @@ bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos), wxToolBarToolBase *toolBase) #if wxMAC_USE_NATIVE_TOOLBAR { - wxASSERT( tool->GetControl() != NULL ); - HIToolbarItemRef item; + 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 ) ; + err = HIToolbarCreateItemWithIdentifier((HIToolbarRef) m_macHIToolbarRef,kControlToolbarItemClassID, + data , &item ) ; if (err == noErr) { @@ -1516,6 +1562,19 @@ bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos), wxToolBarToolBase *toolBase) break; } +#if wxMAC_USE_NATIVE_TOOLBAR + wxString label = tool->GetLabel(); + if ( !label.empty() ) + { + // strip mnemonics from the label for compatibility + // with the usual labels in wxStaticText sense + label = wxStripMenuCodes(label); + + HIToolbarItemSetLabel(item, + wxMacCFStringHolder(label, m_font.GetEncoding())); + } +#endif // wxMAC_USE_NATIVE_TOOLBAR + if ( err == noErr ) { if ( controlHandle )