Related: tdf#113160 set a temporary dialog parent during type detection

to get warning dialogs that don't block the existing windows but whose
lifecycle can be controlled to avoid crashes during exit

Change-Id: I57965301c3d8a031acb33e83bf7715fe132385d0
Reviewed-on: https://gerrit.libreoffice.org/45044
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Tested-by: Caolán McNamara <caolanm@redhat.com>
This commit is contained in:
Caolán McNamara
2017-11-21 16:25:55 +00:00
parent e0bd8f3696
commit c46f0c9f6e
3 changed files with 129 additions and 24 deletions

View File

@@ -1042,32 +1042,17 @@ bool LoadEnv::impl_loadContent()
bool bHidden = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN(), false); bool bHidden = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_HIDDEN(), false);
bool bMinimized = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_MINIMIZED(), false); bool bMinimized = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_MINIMIZED(), false);
bool bPreview = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_PREVIEW(), false); bool bPreview = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_PREVIEW(), false);
css::uno::Reference< css::task::XStatusIndicator > xProgress = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_STATUSINDICATOR(), css::uno::Reference< css::task::XStatusIndicator >());
if (!bHidden && !bMinimized && !bPreview) if (!bHidden && !bMinimized && !bPreview && !xProgress.is())
{ {
css::uno::Reference< css::task::XStatusIndicator > xProgress = m_lMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_STATUSINDICATOR(), css::uno::Reference< css::task::XStatusIndicator >()); // Note: it's an optional interface!
if (!xProgress.is()) css::uno::Reference< css::task::XStatusIndicatorFactory > xProgressFactory(xTargetFrame, css::uno::UNO_QUERY);
if (xProgressFactory.is())
{ {
// Note: it's an optional interface! xProgress = xProgressFactory->createStatusIndicator();
css::uno::Reference< css::task::XStatusIndicatorFactory > xProgressFactory(xTargetFrame, css::uno::UNO_QUERY); if (xProgress.is())
if (xProgressFactory.is()) m_lMediaDescriptor[utl::MediaDescriptor::PROP_STATUSINDICATOR()] <<= xProgress;
{
xProgress = xProgressFactory->createStatusIndicator();
if (xProgress.is())
m_lMediaDescriptor[utl::MediaDescriptor::PROP_STATUSINDICATOR()] <<= xProgress;
}
}
if (!comphelper::LibreOfficeKit::isActive())
{
//now that we have a window, set things up so that warnings dialogs are relative to that window
css::uno::Reference<css::task::XInteractionHandler> xInteractionHandler(
task::InteractionHandler::createWithParent(m_xContext, xTargetFrame->getContainerWindow()),
css::uno::UNO_QUERY);
if (xInteractionHandler.is())
{
m_lMediaDescriptor[utl::MediaDescriptor::PROP_INTERACTIONHANDLER()] <<= xInteractionHandler;
m_lMediaDescriptor[utl::MediaDescriptor::PROP_AUTHENTICATIONHANDLER()] <<= xInteractionHandler;
}
} }
} }

View File

@@ -22,17 +22,127 @@
#include <vector> #include <vector>
#include <com/sun/star/frame/Desktop.hpp>
#include <com/sun/star/frame/TerminationVetoException.hpp>
#include <com/sun/star/frame/XTerminateListener2.hpp>
#include <com/sun/star/task/XInteractionHandler2.hpp> #include <com/sun/star/task/XInteractionHandler2.hpp>
#include <com/sun/star/task/XInteractionRequest.hpp> #include <com/sun/star/task/XInteractionRequest.hpp>
#include <cppuhelper/compbase.hxx>
#include <cppuhelper/implbase.hxx> #include <cppuhelper/implbase.hxx>
#include <sfx2/app.hxx>
#include <toolkit/helper/vclunohelper.hxx>
#include <vcl/dialog.hxx>
#include <vcl/svapp.hxx>
#include <vcl/wrkwin.hxx>
namespace com { namespace sun { namespace star { namespace uno { namespace com { namespace sun { namespace star { namespace uno {
class XComponentContext; class XComponentContext;
} } } } } } } }
namespace sfx2 { namespace sfx2 {
inline void closedialogs(SystemWindow& rTopLevel, bool bCloseRoot)
{
for (vcl::Window *pChild = rTopLevel.GetWindow(GetWindowType::FirstTopWindowChild); pChild; pChild = rTopLevel.GetWindow(GetWindowType::NextTopWindowSibling))
closedialogs(dynamic_cast<SystemWindow&>(*pChild), true);
if (bCloseRoot)
rTopLevel.Close();
}
// This is intended to be the parent for any warning dialogs launched
// during the load of a document so that those dialogs are modal to
// this window and don't block any existing windows.
//
// If there are dialog children open on exit then veto termination,
// close the topmost dialog and retry termination.
class WarningDialogsParent :
public cppu::WeakComponentImplHelper<css::frame::XTerminateListener>
{
private:
osl::Mutex m_aLock;
VclPtr<WorkWindow> m_xWin;
css::uno::Reference<css::awt::XWindow> m_xInterface;
private:
DECL_STATIC_LINK(WarningDialogsParent, TerminateDesktop, void*, void);
void closewarningdialogs()
{
if (!m_xWin)
return;
SolarMutexGuard aSolarGuard;
closedialogs(dynamic_cast<SystemWindow&>(*m_xWin), false);
}
public:
using cppu::WeakComponentImplHelperBase::disposing;
virtual void SAL_CALL disposing(const css::lang::EventObject&) override
{
}
// XTerminateListener
virtual void SAL_CALL queryTermination(const css::lang::EventObject&) override
{
closewarningdialogs();
Application::PostUserEvent(LINK(this, WarningDialogsParent, TerminateDesktop));
throw css::frame::TerminationVetoException();
}
virtual void SAL_CALL notifyTermination(const css::lang::EventObject&) override
{
}
public:
WarningDialogsParent()
: cppu::WeakComponentImplHelper<css::frame::XTerminateListener>(m_aLock)
{
SolarMutexGuard aSolarGuard;
m_xWin = VclPtr<WorkWindow>::Create(nullptr, WB_STDWORK);
m_xWin->SetText("dialog parent for warning dialogs during load");
m_xInterface = VCLUnoHelper::GetInterface(m_xWin);
}
virtual ~WarningDialogsParent() override
{
closewarningdialogs();
m_xWin.disposeAndClear();
}
const css::uno::Reference<css::awt::XWindow>& GetDialogParent() const
{
return m_xInterface;
}
};
class WarningDialogsParentScope
{
private:
css::uno::Reference<css::frame::XDesktop> m_xDesktop;
rtl::Reference<WarningDialogsParent> m_xListener;
public:
WarningDialogsParentScope(const css::uno::Reference<css::uno::XComponentContext>& rContext)
: m_xDesktop(css::frame::Desktop::create(rContext), css::uno::UNO_QUERY_THROW)
, m_xListener(new WarningDialogsParent)
{
m_xDesktop->addTerminateListener(m_xListener.get());
}
const css::uno::Reference<css::awt::XWindow>& GetDialogParent() const
{
return m_xListener->GetDialogParent();
}
~WarningDialogsParentScope()
{
m_xDesktop->removeTerminateListener(m_xListener.get());
}
};
/** /**
@short Prevent us from showing the same interaction more than once during @short Prevent us from showing the same interaction more than once during
the same transaction. the same transaction.
@@ -99,6 +209,8 @@ class PreventDuplicateInteraction : private ThreadHelpBase2
if it's not blocked. */ if it's not blocked. */
css::uno::Reference< css::task::XInteractionHandler > m_xHandler; css::uno::Reference< css::task::XInteractionHandler > m_xHandler;
std::unique_ptr<WarningDialogsParentScope> m_xWarningDialogsParent;
/** This list describe which and how incoming interactions must be handled. /** This list describe which and how incoming interactions must be handled.
Further it contains all collected information after this interaction Further it contains all collected information after this interaction
object was used.*/ object was used.*/

View File

@@ -19,6 +19,7 @@
#include <preventduplicateinteraction.hxx> #include <preventduplicateinteraction.hxx>
#include <comphelper/processfactory.hxx>
#include <osl/diagnose.h> #include <osl/diagnose.h>
#include <com/sun/star/task/InteractionHandler.hpp> #include <com/sun/star/task/InteractionHandler.hpp>
@@ -53,7 +54,9 @@ void PreventDuplicateInteraction::useDefaultUUIHandler()
aLock.clear(); aLock.clear();
// <- SAFE // <- SAFE
css::uno::Reference< css::task::XInteractionHandler > xHandler( css::task::InteractionHandler::createWithParent( m_xContext, nullptr ), css::uno::UNO_QUERY_THROW ); m_xWarningDialogsParent.reset(new WarningDialogsParentScope(m_xContext));
css::uno::Reference<css::task::XInteractionHandler> xHandler(css::task::InteractionHandler::createWithParent(
m_xContext, m_xWarningDialogsParent->GetDialogParent()), css::uno::UNO_QUERY_THROW);
// SAFE -> // SAFE ->
aLock.reset(); aLock.reset();
@@ -227,6 +230,11 @@ bool PreventDuplicateInteraction::getInteractionInfo(const css::uno::Type&
return false; return false;
} }
IMPL_STATIC_LINK_NOARG(WarningDialogsParent, TerminateDesktop, void*, void)
{
css::frame::Desktop::create(comphelper::getProcessComponentContext())->terminate();
}
} // namespace sfx2 } // namespace sfx2
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ /* vim:set shiftwidth=4 softtabstop=4 expandtab: */