extensions/Library_scn.mk | 1 extensions/source/scanner/scanwin.cxx | 159 +++++++++++++++++++++------------- 2 files changed, 101 insertions(+), 59 deletions(-)
New commits: commit 70e1be1b2f40e881b9aeee8f0d39f894dbf67205 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Sat Dec 29 23:56:44 2018 +0300 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Sun Dec 30 01:43:26 2018 +0100 tdf#114635: Scan operations are modal To ensure that a document frame isn't modified/closed while an asynchronous scan operation is performed, the frame is blocked for the lifetime of the shim process. Change-Id: I7e21c816ca6de8eb0a53498e77eae359985dbf71 Reviewed-on: https://gerrit.libreoffice.org/65727 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/extensions/Library_scn.mk b/extensions/Library_scn.mk index 71051e112624..a95675823495 100644 --- a/extensions/Library_scn.mk +++ b/extensions/Library_scn.mk @@ -33,6 +33,7 @@ $(eval $(call gb_Library_use_libraries,scn,\ sal \ $(if $(filter WNT,$(OS)),salhelper) \ svt \ + $(if $(filter WNT,$(OS)),tk) \ tl \ utl \ vcl \ diff --git a/extensions/source/scanner/scanwin.cxx b/extensions/source/scanner/scanwin.cxx index e6d238fbcaf8..24068e12b1ee 100644 --- a/extensions/source/scanner/scanwin.cxx +++ b/extensions/source/scanner/scanwin.cxx @@ -18,9 +18,12 @@ */ #include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/frame/XFrame.hpp> +#include <com/sun/star/frame/Desktop.hpp> #include "twain32shim.hxx" +#include <comphelper/processfactory.hxx> #include <config_folders.h> #include <o3tl/char16_t2wchar_t.hxx> #include <osl/conditn.hxx> @@ -28,12 +31,15 @@ #include <osl/mutex.hxx> #include <rtl/bootstrap.hxx> #include <salhelper/thread.hxx> +#include <toolkit/helper/vclunohelper.hxx> #include <tools/stream.hxx> #include <tools/helpers.hxx> #include <vcl/svapp.hxx> +#include <vcl/window.hxx> #include "scanner.hxx" -using namespace ::com::sun::star; +namespace +{ enum TwainState { @@ -53,15 +59,23 @@ using ScopedHANDLE = std::unique_ptr<HANDLE, HANDLEDeleter>; class Twain { +public: + Twain(); + ~Twain(); + + bool SelectSource(ScannerManager& rMgr); + bool PerformTransfer(ScannerManager& rMgr, + const css::uno::Reference<css::lang::XEventListener>& rxListener); + + TwainState GetState() const { return meState; } + +private: friend class ShimListenerThread; class ShimListenerThread : public salhelper::Thread { public: - ShimListenerThread(Twain& rOwner) - : salhelper::Thread("TWAINShimListenerThread") - , mrOwner(rOwner) - { - } + ShimListenerThread(); + ~ShimListenerThread() override; void execute() override; const OUString& getError() { return msErrorReported; } @@ -74,7 +88,7 @@ class Twain bool RequestInitXfer(); private: - Twain& mrOwner; + VclPtr<vcl::Window> mxTopWindow; // the window that we made modal bool mbDontNotify = false; HWND mhWndShim = nullptr; // shim main window handle OUString msErrorReported; @@ -89,8 +103,8 @@ class Twain void NotifyOwner(WPARAM nEvent); void NotifyXFerOwner(LPARAM nHandle); }; - uno::Reference<lang::XEventListener> mxListener; - uno::Reference<scanner::XScannerManager> mxMgr; + css::uno::Reference<css::lang::XEventListener> mxListener; + css::uno::Reference<css::scanner::XScannerManager> mxMgr; ScannerManager* mpCurMgr = nullptr; TwainState meState = TWAIN_STATE_NONE; rtl::Reference<ShimListenerThread> mpThread; @@ -104,17 +118,47 @@ class Twain bool InitializeNewShim(ScannerManager& rMgr); void Reset(); // cleanup thread and manager +}; -public: - Twain(); - ~Twain(); +static Twain aTwain; - bool SelectSource(ScannerManager& rMgr); - bool PerformTransfer(ScannerManager& rMgr, - const uno::Reference<lang::XEventListener>& rxListener); +css::uno::Reference<css::frame::XFrame> ImplGetActiveFrame() +{ + try + { + // query desktop instance + css::uno::Reference<css::frame::XDesktop2> xDesktop + = css::frame::Desktop::create(comphelper::getProcessComponentContext()); + if (css::uno::Reference<css::frame::XFrame> xActiveFrame = xDesktop->getActiveFrame()) + return xActiveFrame; + } + catch (const css::uno::Exception&) + { + } + SAL_WARN("extensions.scanner", "ImplGetActiveFrame: Could not determine active frame!"); + return css::uno::Reference<css::frame::XFrame>(); +} - TwainState GetState() const { return meState; } -}; +Twain::ShimListenerThread::ShimListenerThread() + : salhelper::Thread("TWAINShimListenerThread") +{ + if (css::uno::Reference<css::frame::XFrame> xTopFrame = ImplGetActiveFrame()) + { + mxTopWindow = VCLUnoHelper::GetWindow(xTopFrame->getComponentWindow()); + if (mxTopWindow) + { + mxTopWindow->IncModalCount(); // the operation is modal to the frame + } + } +} + +Twain::ShimListenerThread::~ShimListenerThread() +{ + if (mxTopWindow) + { + mxTopWindow->DecModalCount(); // unblock the frame + } +} bool Twain::ShimListenerThread::WaitInitialization() { @@ -128,20 +172,6 @@ bool Twain::ShimListenerThread::WaitRequestResult() return mbRequestResult; } -void Twain::ShimListenerThread::RequestDestroy() { SendShimRequest(TWAIN_REQUEST_QUIT); } - -bool Twain::ShimListenerThread::RequestSelectSource() -{ - assert(mbInitSucceeded); - return SendShimRequestWithResult(TWAIN_REQUEST_SELECTSOURCE); -} - -bool Twain::ShimListenerThread::RequestInitXfer() -{ - assert(mbInitSucceeded); - return SendShimRequestWithResult(TWAIN_REQUEST_INITXFER); -} - void Twain::ShimListenerThread::SendShimRequest(WPARAM nRequest) { if (mhWndShim) @@ -156,16 +186,30 @@ bool Twain::ShimListenerThread::SendShimRequestWithResult(WPARAM nRequest) return WaitRequestResult(); } +void Twain::ShimListenerThread::RequestDestroy() { SendShimRequest(TWAIN_REQUEST_QUIT); } + +bool Twain::ShimListenerThread::RequestSelectSource() +{ + assert(mbInitSucceeded); + return SendShimRequestWithResult(TWAIN_REQUEST_SELECTSOURCE); +} + +bool Twain::ShimListenerThread::RequestInitXfer() +{ + assert(mbInitSucceeded); + return SendShimRequestWithResult(TWAIN_REQUEST_INITXFER); +} + void Twain::ShimListenerThread::NotifyOwner(WPARAM nEvent) { if (!mbDontNotify) - mrOwner.Notify(nEvent); + aTwain.Notify(nEvent); } void Twain::ShimListenerThread::NotifyXFerOwner(LPARAM nHandle) { if (!mbDontNotify) - mrOwner.NotifyXFer(nHandle); + aTwain.NotifyXFer(nHandle); } // May only be called from the own thread, so no threading issues modifying self @@ -234,11 +278,7 @@ void Twain::ShimListenerThread::execute() // We need a WinAPI HANDLE of the process to be able to wait on it and detect the process // termination; so use WinAPI to start the process, not osl_executeProcess. - STARTUPINFOW si{}; // null-initialize - si.cb = sizeof(si); - si.dwFlags = STARTF_USESHOWWINDOW; - si.wShowWindow = SW_HIDE; - + STARTUPINFOW si{ sizeof(si) }; // null-initialize all but cb PROCESS_INFORMATION pi; if (!CreateProcessW(nullptr, const_cast<LPWSTR>(o3tl::toW(sCmdLine.getStr())), nullptr, @@ -317,9 +357,9 @@ bool Twain::InitializeNewShim(ScannerManager& rMgr) // hold reference to ScannerManager, to prevent premature death mxMgr.set(static_cast<OWeakObject*>(const_cast<ScannerManager*>(mpCurMgr = &rMgr)), - uno::UNO_QUERY); + css::uno::UNO_QUERY); - mpThread.set(new ShimListenerThread(*this)); + mpThread.set(new ShimListenerThread()); mpThread->launch(); const bool bSuccess = mpThread->WaitInitialization(); if (!bSuccess) @@ -354,7 +394,7 @@ bool Twain::SelectSource(ScannerManager& rMgr) } bool Twain::PerformTransfer(ScannerManager& rMgr, - const uno::Reference<lang::XEventListener>& rxListener) + const css::uno::Reference<css::lang::XEventListener>& rxListener) { osl::MutexGuard aGuard(maMutex); bool bRet = false; @@ -384,7 +424,7 @@ IMPL_LINK(Twain, ImpNotifyHdl, void*, pParam, void) if (meState != TWAIN_STATE_DONE) meState = TWAIN_STATE_CANCELED; - lang::EventObject event(mxMgr); // mxMgr will be cleared below + css::lang::EventObject event(mxMgr); // mxMgr will be cleared below if (mpThread) Reset(); @@ -410,18 +450,18 @@ IMPL_LINK(Twain, ImpNotifyXferHdl, void*, pParam, void) mpCurMgr->SetData(pParam); meState = pParam ? TWAIN_STATE_DONE : TWAIN_STATE_CANCELED; - lang::EventObject event(mxMgr); // mxMgr will be cleared below + css::lang::EventObject event(mxMgr); // mxMgr will be cleared below Reset(); if (mxListener.is()) - mxListener->disposing(lang::EventObject(mxMgr)); + mxListener->disposing(css::lang::EventObject(mxMgr)); } mxListener.clear(); } -static Twain aTwain; +} // namespace void ScannerManager::AcquireData() {} @@ -434,9 +474,9 @@ void ScannerManager::ReleaseData() } } -awt::Size ScannerManager::getSize() +css::awt::Size ScannerManager::getSize() { - awt::Size aRet; + css::awt::Size aRet; if (mpData) { @@ -456,9 +496,9 @@ awt::Size ScannerManager::getSize() return aRet; } -uno::Sequence<sal_Int8> ScannerManager::getDIB() +css::uno::Sequence<sal_Int8> ScannerManager::getDIB() { - uno::Sequence<sal_Int8> aRet; + css::uno::Sequence<sal_Int8> aRet; if (mpData) { @@ -494,7 +534,7 @@ uno::Sequence<sal_Int8> ScannerManager::getDIB() break; } - aRet = uno::Sequence<sal_Int8>(sizeof(BITMAPFILEHEADER) + nDIBSize); + aRet = css::uno::Sequence<sal_Int8>(sizeof(BITMAPFILEHEADER) + nDIBSize); sal_Int8* pBuf = aRet.getArray(); SvMemoryStream* pMemStm @@ -516,10 +556,10 @@ uno::Sequence<sal_Int8> ScannerManager::getDIB() return aRet; } -uno::Sequence<ScannerContext> SAL_CALL ScannerManager::getAvailableScanners() +css::uno::Sequence<ScannerContext> SAL_CALL ScannerManager::getAvailableScanners() { osl::MutexGuard aGuard(maProtector); - uno::Sequence<ScannerContext> aRet(1); + css::uno::Sequence<ScannerContext> aRet(1); aRet.getArray()[0].ScannerName = "TWAIN"; aRet.getArray()[0].InternalData = 0; @@ -528,10 +568,10 @@ uno::Sequence<ScannerContext> SAL_CALL ScannerManager::getAvailableScanners() } sal_Bool SAL_CALL ScannerManager::configureScannerAndScan( - ScannerContext& rContext, const uno::Reference<lang::XEventListener>&) + ScannerContext& rContext, const css::uno::Reference<css::lang::XEventListener>&) { osl::MutexGuard aGuard(maProtector); - uno::Reference<XScannerManager> xThis(this); + css::uno::Reference<XScannerManager> xThis(this); if (rContext.InternalData != 0 || rContext.ScannerName != "TWAIN") throw ScannerException("Scanner does not exist", xThis, ScanError_InvalidContext); @@ -542,10 +582,10 @@ sal_Bool SAL_CALL ScannerManager::configureScannerAndScan( } void SAL_CALL ScannerManager::startScan(const ScannerContext& rContext, - const uno::Reference<lang::XEventListener>& rxListener) + const css::uno::Reference<css::lang::XEventListener>& rxListener) { osl::MutexGuard aGuard(maProtector); - uno::Reference<XScannerManager> xThis(this); + css::uno::Reference<XScannerManager> xThis(this); if (rContext.InternalData != 0 || rContext.ScannerName != "TWAIN") throw ScannerException("Scanner does not exist", xThis, ScanError_InvalidContext); @@ -557,7 +597,7 @@ void SAL_CALL ScannerManager::startScan(const ScannerContext& rContext, ScanError SAL_CALL ScannerManager::getError(const ScannerContext& rContext) { osl::MutexGuard aGuard(maProtector); - uno::Reference<XScannerManager> xThis(this); + css::uno::Reference<XScannerManager> xThis(this); if (rContext.InternalData != 0 || rContext.ScannerName != "TWAIN") throw ScannerException("Scanner does not exist", xThis, ScanError_InvalidContext); @@ -566,10 +606,11 @@ ScanError SAL_CALL ScannerManager::getError(const ScannerContext& rContext) : ScanError_ScanErrorNone); } -uno::Reference<awt::XBitmap> SAL_CALL ScannerManager::getBitmap(const ScannerContext& /*rContext*/) + css::uno::Reference<css::awt::XBitmap> + SAL_CALL ScannerManager::getBitmap(const ScannerContext& /*rContext*/) { osl::MutexGuard aGuard(maProtector); - return uno::Reference<awt::XBitmap>(this); + return css::uno::Reference<css::awt::XBitmap>(this); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits