include/comphelper/interfacecontainer2.hxx | 68 +++++++++++++++++++++++++++++ sfx2/source/notify/globalevents.cxx | 6 +- 2 files changed, 72 insertions(+), 2 deletions(-)
New commits: commit c8b88a40a04e95b3f71e9b231ed68947007df671 Author: Stephan Bergmann <stephan.bergm...@allotropia.de> AuthorDate: Wed Nov 20 15:04:06 2024 +0100 Commit: Stephan Bergmann <stephan.bergm...@allotropia.de> CommitDate: Thu Nov 21 09:08:25 2024 +0100 Catch exceptions thrown when notifying individual listeners Any such exceptions were already caught further up the stack (by SfxBaseModel::postEvent_Impl), but prevented later listeners from being notified as soon as one listener threw an exception (which I saw happen with some 3rd-party extension). Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176854 Tested-by: Jenkins Reviewed-by: Stephan Bergmann <stephan.bergm...@allotropia.de> Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk> (cherry picked from commit 755b28d019db62d29ef36535a501809912182960) Conflicts: include/comphelper/interfacecontainer2.hxx include/comphelper/interfacecontainer4.hxx sfx2/source/notify/globalevents.cxx Change-Id: Ia6bd1c73d29ab6d6e131652df51939ba0c0e988e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176866 Tested-by: allotropia jenkins <jenk...@allotropia.de> Reviewed-by: Stephan Bergmann <stephan.bergm...@allotropia.de> diff --git a/include/comphelper/interfacecontainer2.hxx b/include/comphelper/interfacecontainer2.hxx index 63888008d3ea..9c4d9c3f08eb 100644 --- a/include/comphelper/interfacecontainer2.hxx +++ b/include/comphelper/interfacecontainer2.hxx @@ -191,6 +191,24 @@ public: template <typename ListenerT, typename FuncT> inline void forEach( FuncT const& func ); + /** Executes a functor for each contained listener of specified type, e.g. + <code>forEach<awt::XPaintListener>(...</code>. + + If a css::lang::DisposedException occurs which relates to + the called listener, then that listener is removed from the container. + + If any other UNO exception occurs, the exceptionFunc is called. + + @tparam ListenerT listener type + @tparam FuncT unary functor type, let your compiler deduce this for you + @tparam ExceptionFuncT nullary functor type, let your compiler deduce this for you + @param func unary functor object expecting an argument of type + css::uno::Reference<ListenerT> + @param exceptionFunc nullary functor object + */ + template <typename ListenerT, typename FuncT, typename ExceptionFuncT> + inline void forEach( FuncT const& func, ExceptionFuncT const& exceptionFunc ); + /** Calls a UNO listener method for each contained listener. The listener method must take a single argument of type EventT, @@ -215,6 +233,28 @@ public: template< typename ListenerT, typename EventT > inline void notifyEach( void ( SAL_CALL ListenerT::*NotificationMethod )( const EventT& ), const EventT& Event ); + /** Calls a UNO listener method for each contained listener. + + The listener method must take a single argument of type EventT, + and return <code>void</code>. + + If a css::lang::DisposedException occurs which relates to + the called listener, then that listener is removed from the container. + + If any other UNO exception occurs, the exceptionFunc is called. + + @tparam ListenerT UNO event listener type, let your compiler deduce this for you + @tparam EventT event type, let your compiler deduce this for you + @tparam ExceptionFuncT nullary functor type, let your compiler deduce this for you + @param NotificationMethod + Pointer to a method of a ListenerT interface. + @param Event + Event to notify to all contained listeners + @param exceptionFunc nullary functor object + */ + template< typename ListenerT, typename EventT, typename ExceptionFuncT > + inline void notifyEach( void ( SAL_CALL ListenerT::*NotificationMethod )( const EventT& ), const EventT& Event, const ExceptionFuncT& exceptionFunc ); + private: friend class OInterfaceIteratorHelper2; /** @@ -273,12 +313,40 @@ inline void OInterfaceContainerHelper2::forEach( FuncT const& func ) } } +template <typename ListenerT, typename FuncT, typename ExceptionFuncT> +inline void OInterfaceContainerHelper2::forEach( + FuncT const& func, ExceptionFuncT const& exceptionFunc ) +{ + OInterfaceIteratorHelper2 iter( *this ); + while (iter.hasMoreElements()) { + css::uno::Reference<ListenerT> const xListener( iter.next(), css::uno::UNO_QUERY ); + if (xListener.is()) { + try { + func( xListener ); + } + catch (css::lang::DisposedException const& exc) { + if (exc.Context == xListener) + iter.remove(); + } + catch (css::uno::Exception) { + exceptionFunc(); + } + } + } +} + template< typename ListenerT, typename EventT > inline void OInterfaceContainerHelper2::notifyEach( void ( SAL_CALL ListenerT::*NotificationMethod )( const EventT& ), const EventT& Event ) { forEach< ListenerT, NotifySingleListener< ListenerT, EventT > >( NotifySingleListener< ListenerT, EventT >( NotificationMethod, Event ) ); } +template< typename ListenerT, typename EventT, typename ExceptionFuncT > +inline void OInterfaceContainerHelper2::notifyEach( void ( SAL_CALL ListenerT::*NotificationMethod )( const EventT& ), const EventT& Event, const ExceptionFuncT& exceptionFunc ) +{ + forEach< ListenerT, NotifySingleListener< ListenerT, EventT > >( NotifySingleListener< ListenerT, EventT >( NotificationMethod, Event ), exceptionFunc ); +} + } #endif diff --git a/sfx2/source/notify/globalevents.cxx b/sfx2/source/notify/globalevents.cxx index cfb994ac30f1..c1aa49a01bd7 100644 --- a/sfx2/source/notify/globalevents.cxx +++ b/sfx2/source/notify/globalevents.cxx @@ -384,9 +384,11 @@ void SfxGlobalEvents_Impl::implts_notifyListener(const document::DocumentEvent& { // containers are threadsafe document::EventObject aLegacyEvent(aEvent.Source, aEvent.EventName); - m_aLegacyListeners.notifyEach( &document::XEventListener::notifyEvent, aLegacyEvent ); + m_aLegacyListeners.notifyEach( + &document::XEventListener::notifyEvent, aLegacyEvent, + [] { TOOLS_WARN_EXCEPTION("sfx.notify", "ignoring"); } ); - m_aDocumentListeners.notifyEach( &document::XDocumentEventListener::documentEventOccured, aEvent ); + m_aDocumentListeners.notifyEach( &document::XDocumentEventListener::documentEventOccured, aEvent, [] { TOOLS_WARN_EXCEPTION("sfx.notify", "ignoring"); } ); }