From 68cf256f506d4601a2d2cf3ec2d56713afd491e6 Mon Sep 17 00:00:00 2001 From: Caolán McNamara Date: Tue, 21 Jun 2016 21:29:25 +0100 Subject: Resolves: tdf#88985 block app from exiting during macro execution but stop basic execution on the exit attempt, and then resend exit at a safe place when basic execution has stopped Change-Id: I77c43acffa0b82e8125dcb3b10ad9bf0d6dd26c3 --- svx/source/form/fmscriptingenv.cxx | 118 ++++++++++++++++++++++++++++++++++++- 1 file changed, 115 insertions(+), 3 deletions(-) (limited to 'svx') diff --git a/svx/source/form/fmscriptingenv.cxx b/svx/source/form/fmscriptingenv.cxx index 3cc284e481b7..b79d42151394 100644 --- a/svx/source/form/fmscriptingenv.cxx +++ b/svx/source/form/fmscriptingenv.cxx @@ -22,14 +22,18 @@ #include "fmscriptingenv.hxx" #include "svx/fmmodel.hxx" -#include -#include +#include +#include +#include #include #include -#include +#include +#include +#include #include #include +#include #include #include #include @@ -764,6 +768,111 @@ namespace svxform m_pScriptExecutor = nullptr; } + // tdf#88985 If LibreOffice tries to exit during the execution of a macro + // then: detect the effort, stop basic execution, block until the macro + // returns due to that stop, then restart the quit. This avoids the app + // exiting and destroying itself until the macro is parked at a safe place + // to do that. + class QuitGuard + { + private: + + class TerminateListener : public cppu::WeakComponentImplHelper + { + private: + css::uno::Reference m_xDesktop; + osl::Mutex maMutex; + bool mbQuitBlocked; + public: + // XTerminateListener + virtual void SAL_CALL queryTermination(const css::lang::EventObject& /*rEvent*/) + throw(css::frame::TerminationVetoException, css::uno::RuntimeException, std::exception) override + { + mbQuitBlocked = true; + StarBASIC::Stop(); + throw css::frame::TerminationVetoException(); + } + + virtual void SAL_CALL notifyTermination(const css::lang::EventObject& /*rEvent*/) + throw(css::uno::RuntimeException, std::exception) override + { + mbQuitBlocked = false; + } + + using cppu::WeakComponentImplHelperBase::disposing; + + virtual void SAL_CALL disposing(const css::lang::EventObject& rEvent) + throw(css::uno::RuntimeException, std::exception) override + { + const bool bShutDown = (rEvent.Source == m_xDesktop); + if (bShutDown && m_xDesktop.is()) + { + m_xDesktop->removeTerminateListener(this); + m_xDesktop.clear(); + } + } + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() + throw (css::uno::RuntimeException, std::exception) override + { + return OUString("com.sun.star.comp.svx.StarBasicQuitGuard"); + } + + virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) + throw (css::uno::RuntimeException, std::exception) override + { + return cppu::supportsService(this, ServiceName); + } + + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() + throw (css::uno::RuntimeException, std::exception) override + { + css::uno::Sequence aSeq { "com.sun.star.svx.StarBasicQuitGuard" }; + return aSeq; + } + + public: + TerminateListener() + : cppu::WeakComponentImplHelper(maMutex) + , mbQuitBlocked(false) + { + } + + void start() + { + css::uno::Reference xContext(comphelper::getProcessComponentContext()); + m_xDesktop = css::frame::Desktop::create(xContext); + m_xDesktop->addTerminateListener(this); + } + + void stop() + { + if (!m_xDesktop.is()) + return; + m_xDesktop->removeTerminateListener(this); + if (mbQuitBlocked) + m_xDesktop->terminate(); + } + }; + + TerminateListener* mpListener; + css::uno::Reference mxLifeCycle; + public: + QuitGuard() + : mpListener(new TerminateListener) + , mxLifeCycle(mpListener) + { + mpListener->start(); + } + + ~QuitGuard() + { + mpListener->stop(); + } + }; IMPL_LINK_TYPED( FormScriptListener, OnAsyncScriptEvent, void*, p, void ) { @@ -776,7 +885,10 @@ namespace svxform ::osl::ClearableMutexGuard aGuard( m_aMutex ); if ( !impl_isDisposed_nothrow() ) + { + QuitGuard aQuitGuard; impl_doFireScriptEvent_nothrow( aGuard, *_pEvent, nullptr ); + } } delete _pEvent; -- cgit