diff options
author | Michael Meeks <michael.meeks@collabora.com> | 2019-07-20 10:43:39 +0100 |
---|---|---|
committer | Michael Meeks <michael.meeks@collabora.com> | 2019-08-02 11:41:48 -0400 |
commit | f59e986d0dc04a2d62cc1f236acedfcf727449ce (patch) | |
tree | d4739978f593ba969cac9467f1d87e5c1a109186 /desktop | |
parent | 482419ffeab01642db00cd16a2b46a5790a3323e (diff) |
lok: clipboard: per view clipboard creation.
A bit brutal, but the mess around clipboard instantiation is awful.
Change-Id: I62d6af8bf6813e6bab81123417ea8bfb28394e29
Diffstat (limited to 'desktop')
-rw-r--r-- | desktop/qa/desktop_lib/test_desktop_lib.cxx | 6 | ||||
-rw-r--r-- | desktop/source/lib/init.cxx | 71 | ||||
-rw-r--r-- | desktop/source/lib/lokclipboard.cxx | 98 | ||||
-rw-r--r-- | desktop/source/lib/lokclipboard.hxx | 73 |
4 files changed, 209 insertions, 39 deletions
diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx b/desktop/qa/desktop_lib/test_desktop_lib.cxx index 4ebb21cdfe0a..6874c92f4cf7 100644 --- a/desktop/qa/desktop_lib/test_desktop_lib.cxx +++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx @@ -2772,9 +2772,13 @@ void DesktopLOKTest::testABI() CPPUNIT_ASSERT_EQUAL(documentClassOffset(49), offsetof(struct _LibreOfficeKitDocumentClass, selectPart)); CPPUNIT_ASSERT_EQUAL(documentClassOffset(50), offsetof(struct _LibreOfficeKitDocumentClass, moveSelectedParts)); CPPUNIT_ASSERT_EQUAL(documentClassOffset(51), offsetof(struct _LibreOfficeKitDocumentClass, resizeWindow)); + CPPUNIT_ASSERT_EQUAL(documentClassOffset(52), offsetof(struct _LibreOfficeKitDocumentClass, getSelection)); + CPPUNIT_ASSERT_EQUAL(documentClassOffset(53), offsetof(struct _LibreOfficeKitDocumentClass, setClipboard)); + CPPUNIT_ASSERT_EQUAL(documentClassOffset(54), offsetof(struct _LibreOfficeKitDocumentClass, getSelectionType)); + // Extending is fine, update this, and add new assert for the offsetof the // new method - CPPUNIT_ASSERT_EQUAL(documentClassOffset(52), sizeof(struct _LibreOfficeKitDocumentClass)); + CPPUNIT_ASSERT_EQUAL(documentClassOffset(55), sizeof(struct _LibreOfficeKitDocumentClass)); } CPPUNIT_TEST_SUITE_REGISTRATION(DesktopLOKTest); diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx index eb9c7854bc13..2eb862c07564 100644 --- a/desktop/source/lib/init.cxx +++ b/desktop/source/lib/init.cxx @@ -790,7 +790,7 @@ static char* doc_getTextSelection(LibreOfficeKitDocument* pThis, const char* pMimeType, char** pUsedMimeType); static int doc_getSelectionType(LibreOfficeKitDocument* pThis); -static int doc_getSelection (LibreOfficeKitDocument* pThis, +static int doc_getClipboard (LibreOfficeKitDocument* pThis, const char **pMimeTypes, size_t *pOutCount, char ***pOutMimeTypes, @@ -863,6 +863,34 @@ static size_t doc_renderShapeSelection(LibreOfficeKitDocument* pThis, char** pOu static void doc_resizeWindow(LibreOfficeKitDocument* pThis, unsigned nLOKWindowId, const int nWidth, const int nHeight); +} // extern "C" + +namespace { +ITiledRenderable* getTiledRenderable(LibreOfficeKitDocument* pThis) +{ + LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis); + return dynamic_cast<ITiledRenderable*>(pDocument->mxComponent.get()); +} + +/* + * Unfortunately clipboard creation using UNO is insanely baroque. + * we also need to ensure that this works for the first view which + * has no clear 'createView' called for it (unfortunately). + */ + +rtl::Reference<LOKClipboard> forceSetClipboardForCurrentView(LibreOfficeKitDocument *pThis) +{ + ITiledRenderable* pDoc = getTiledRenderable(pThis); + rtl::Reference<LOKClipboard> xClip(LOKClipboardFactory::getClipboardForCurView()); + + SAL_INFO("lok", "Set to clipboard for view " << xClip.get()); + // FIXME: using a hammer here - should not be necessary if all tests used createView. + pDoc->setClipboard(uno::Reference<datatransfer::clipboard::XClipboard>(xClip->getXI(), UNO_QUERY)); + + return xClip; +} +} // anonymous namespace + LibLODocument_Impl::LibLODocument_Impl(const uno::Reference <css::lang::XComponent> &xComponent) : mxComponent(xComponent) { @@ -901,7 +929,7 @@ LibLODocument_Impl::LibLODocument_Impl(const uno::Reference <css::lang::XCompone m_pDocumentClass->setTextSelection = doc_setTextSelection; m_pDocumentClass->getTextSelection = doc_getTextSelection; m_pDocumentClass->getSelectionType = doc_getSelectionType; - m_pDocumentClass->getSelection = doc_getSelection; + m_pDocumentClass->getClipboard = doc_getClipboard; m_pDocumentClass->setClipboard = doc_setClipboard; m_pDocumentClass->paste = doc_paste; m_pDocumentClass->setGraphicSelection = doc_setGraphicSelection; @@ -942,6 +970,8 @@ LibLODocument_Impl::LibLODocument_Impl(const uno::Reference <css::lang::XCompone gDocumentClass = m_pDocumentClass; } pClass = m_pDocumentClass.get(); + + forceSetClipboardForCurrentView(this); } LibLODocument_Impl::~LibLODocument_Impl() @@ -956,6 +986,8 @@ LibLODocument_Impl::~LibLODocument_Impl() } } +extern "C" { + CallbackFlushHandler::CallbackFlushHandler(LibreOfficeKitDocument* pDocument, LibreOfficeKitCallback pCallback, void* pData) : Idle( "lokit timer callback" ), m_pDocument(pDocument), @@ -1691,12 +1723,6 @@ LibLibreOffice_Impl::~LibLibreOffice_Impl() namespace { -ITiledRenderable* getTiledRenderable(LibreOfficeKitDocument* pThis) -{ - LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis); - return dynamic_cast<ITiledRenderable*>(pDocument->mxComponent.get()); -} - #ifdef IOS void paintTileToCGContext(ITiledRenderable* pDocument, void* rCGContext, const Size nCanvasSize, @@ -3535,7 +3561,7 @@ static int doc_getSelectionType(LibreOfficeKitDocument* pThis) return aRet.getLength() ? LOK_SELTYPE_TEXT : LOK_SELTYPE_NONE; } -static int doc_getSelection(LibreOfficeKitDocument* pThis, +static int doc_getClipboard(LibreOfficeKitDocument* pThis, const char **pMimeTypes, size_t *pOutCount, char ***pOutMimeTypes, @@ -3562,7 +3588,10 @@ static int doc_getSelection(LibreOfficeKitDocument* pThis, return 0; } - css::uno::Reference<css::datatransfer::XTransferable> xTransferable = pDoc->getSelection(); + rtl::Reference<LOKClipboard> xClip(LOKClipboardFactory::getClipboardForCurView()); + SAL_INFO("lok", "Got clipboard for view " << xClip.get()); + + css::uno::Reference<css::datatransfer::XTransferable> xTransferable = xClip->getContents(); if (!xTransferable) { SetLastExceptionMsg("No selection available"); @@ -3637,9 +3666,9 @@ static int doc_setClipboard(LibreOfficeKitDocument* pThis, } uno::Reference<datatransfer::XTransferable> xTransferable(new LOKTransferable(nInCount, pInMimeTypes, pInSizes, pInStreams)); - uno::Reference<datatransfer::clipboard::XClipboard> xClipboard(new LOKClipboard); - xClipboard->setContents(xTransferable, uno::Reference<datatransfer::clipboard::XClipboardOwner>()); - pDoc->setClipboard(xClipboard); + + auto xClip = forceSetClipboardForCurrentView(pThis); + xClip->setContents(xTransferable, uno::Reference<datatransfer::clipboard::XClipboardOwner>()); if (!pDoc->isMimeTypeSupported()) { @@ -4305,7 +4334,7 @@ static void doc_setOutlineState(LibreOfficeKitDocument* pThis, bool bColumn, int pDoc->setOutlineState(bColumn, nLevel, nIndex, bHidden); } -static int doc_createViewWithOptions(SAL_UNUSED_PARAMETER LibreOfficeKitDocument* /*pThis*/, +static int doc_createViewWithOptions(LibreOfficeKitDocument* pThis, const char* pOptions) { comphelper::ProfileZone aZone("doc_createView"); @@ -4322,7 +4351,11 @@ static int doc_createViewWithOptions(SAL_UNUSED_PARAMETER LibreOfficeKitDocument comphelper::LibreOfficeKit::setLanguageTag(LanguageTag(aLanguage)); } - return SfxLokHelper::createView(); + int nId = SfxLokHelper::createView(); + + forceSetClipboardForCurrentView(pThis); + + return nId; } static int doc_createView(LibreOfficeKitDocument* pThis) @@ -5498,14 +5531,10 @@ static void lo_destroy(LibreOfficeKit* pThis) SAL_INFO("lok", "LO Destroy Done"); } -} - #ifdef IOS // Used by the unmaintained LibreOfficeLight app. Once that has been retired, get rid of this, too. -extern "C" -{ __attribute__((visibility("default"))) void temporaryHackToInvokeCallbackHandlers(LibreOfficeKitDocument* pThis) { @@ -5519,7 +5548,9 @@ void temporaryHackToInvokeCallbackHandlers(LibreOfficeKitDocument* pThis) pDocument->mpCallbackFlushHandlers[nOrigViewId]->Invoke(); } } -} + #endif +} // extern "C" + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/lib/lokclipboard.cxx b/desktop/source/lib/lokclipboard.cxx index 015690bd9bc4..74e5131f435d 100644 --- a/desktop/source/lib/lokclipboard.cxx +++ b/desktop/source/lib/lokclipboard.cxx @@ -8,23 +8,103 @@ */ #include "lokclipboard.hxx" -#include <comphelper/sequence.hxx> +#include <sfx2/lokhelper.hxx> -using namespace com::sun::star; +using namespace css; +using namespace css::uno; -uno::Reference<datatransfer::XTransferable> SAL_CALL LOKClipboard::getContents() +osl::Mutex LOKClipboardFactory::gMutex; +std::unordered_map<int, rtl::Reference<LOKClipboard>> LOKClipboardFactory::gClipboards; + +rtl::Reference<LOKClipboard> LOKClipboardFactory::getClipboardForCurView() +{ + int nViewId = SfxLokHelper::getView(); // currently active. + + osl::MutexGuard aGuard(gMutex); + + auto it = gClipboards.find(nViewId); + if (it != gClipboards.end()) + return it->second; + rtl::Reference<LOKClipboard> xClip(new LOKClipboard()); + gClipboards[nViewId] = xClip; + SAL_INFO("lok", "Created clipboard for view " << nViewId << " as " << xClip.get()); + return xClip; +} + +uno::Reference<uno::XInterface> + SAL_CALL LOKClipboardFactory::createInstanceWithArguments(const Sequence<Any>& /* rArgs */) +{ + return uno::Reference<uno::XInterface>( + static_cast<cppu::OWeakObject*>(getClipboardForCurView().get())); +} + +LOKClipboard::LOKClipboard() + : cppu::WeakComponentImplHelper<css::datatransfer::clipboard::XSystemClipboard, + css::lang::XServiceInfo>(m_aMutex) +{ +} + +Sequence<OUString> LOKClipboard::getSupportedServiceNames_static() +{ + Sequence<OUString> aRet{ "com.sun.star.datatransfer.clipboard.SystemClipboard" }; + return aRet; +} + +OUString LOKClipboard::getImplementationName() +{ + return OUString("com.sun.star.datatransfer.LOKClipboard"); +} + +Sequence<OUString> LOKClipboard::getSupportedServiceNames() +{ + return getSupportedServiceNames_static(); +} + +sal_Bool LOKClipboard::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +Reference<css::datatransfer::XTransferable> LOKClipboard::getContents() { return m_xTransferable; } + +void LOKClipboard::setContents( + const Reference<css::datatransfer::XTransferable>& xTrans, + const Reference<css::datatransfer::clipboard::XClipboardOwner>& xClipboardOwner) { - return m_xTransferable; + osl::ClearableMutexGuard aGuard(m_aMutex); + Reference<datatransfer::clipboard::XClipboardOwner> xOldOwner(m_aOwner); + Reference<datatransfer::XTransferable> xOldContents(m_xTransferable); + m_xTransferable = xTrans; + m_aOwner = xClipboardOwner; + + std::vector<Reference<datatransfer::clipboard::XClipboardListener>> aListeners(m_aListeners); + datatransfer::clipboard::ClipboardEvent aEv; + aEv.Contents = m_xTransferable; + + aGuard.clear(); + + if (xOldOwner.is() && xOldOwner != xClipboardOwner) + xOldOwner->lostOwnership(this, xOldContents); + for (auto const& listener : aListeners) + { + listener->changedContents(aEv); + } } -void SAL_CALL LOKClipboard::setContents( - const uno::Reference<datatransfer::XTransferable>& xTransferable, - const uno::Reference<datatransfer::clipboard::XClipboardOwner>& /*xClipboardOwner*/) +void LOKClipboard::addClipboardListener( + const Reference<datatransfer::clipboard::XClipboardListener>& listener) { - m_xTransferable = xTransferable; + osl::ClearableMutexGuard aGuard(m_aMutex); + m_aListeners.push_back(listener); } -OUString SAL_CALL LOKClipboard::getName() { return OUString(); } +void LOKClipboard::removeClipboardListener( + const Reference<datatransfer::clipboard::XClipboardListener>& listener) +{ + osl::ClearableMutexGuard aGuard(m_aMutex); + m_aListeners.erase(std::remove(m_aListeners.begin(), m_aListeners.end(), listener), + m_aListeners.end()); +} LOKTransferable::LOKTransferable(const char* pMimeType, const char* pData, std::size_t nSize) : m_aMimeType(OUString::fromUtf8(pMimeType)) diff --git a/desktop/source/lib/lokclipboard.hxx b/desktop/source/lib/lokclipboard.hxx index 5da8b3e2b63e..d917a377eb11 100644 --- a/desktop/source/lib/lokclipboard.hxx +++ b/desktop/source/lib/lokclipboard.hxx @@ -11,24 +11,60 @@ #define INCLUDED_DESKTOP_SOURCE_LIB_LOKCLIPBOARD_HXX #include <vector> +#include <unordered_map> +#include <rtl/ref.hxx> #include <cppuhelper/implbase.hxx> -#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp> +#include <cppuhelper/compbase.hxx> +#include <comphelper/sequence.hxx> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/datatransfer/clipboard/XSystemClipboard.hpp> + +using namespace css::uno; /// A clipboard implementation for LibreOfficeKit. -class LOKClipboard : public cppu::WeakImplHelper<css::datatransfer::clipboard::XClipboard> +class LOKClipboard + : public cppu::WeakComponentImplHelper<css::datatransfer::clipboard::XSystemClipboard, + css::lang::XServiceInfo> { - css::uno::Reference<css::datatransfer::XTransferable> m_xTransferable; + osl::Mutex m_aMutex; + css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner> m_aOwner; + std::vector<css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>> m_aListeners; public: - css::uno::Reference<css::datatransfer::XTransferable> SAL_CALL getContents() override; + LOKClipboard(); + + /// get an XInterface easily. + css::uno::Reference<css::uno::XInterface> getXI() + { + return css::uno::Reference<css::uno::XInterface>(static_cast<cppu::OWeakObject*>(this)); + } + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + static Sequence<OUString> getSupportedServiceNames_static(); + // XClipboard + css::uno::Reference<css::datatransfer::XTransferable> SAL_CALL getContents() override; void SAL_CALL setContents( const css::uno::Reference<css::datatransfer::XTransferable>& xTransferable, const css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner>& xClipboardOwner) override; + OUString SAL_CALL getName() override { return OUString("CLIPBOARD"); } + + // XClipboardEx + sal_Int8 SAL_CALL getRenderingCapabilities() override { return 0; } - OUString SAL_CALL getName() override; + // XClipboardNotifier + void SAL_CALL addClipboardListener( + const css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>& listener) + override; + void SAL_CALL removeClipboardListener( + const css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>& listener) + override; }; /// Represents the contents of LOKClipboard. @@ -38,10 +74,8 @@ class LOKTransferable : public cppu::WeakImplHelper<css::datatransfer::XTransfer std::vector<css::uno::Any> m_aContent; public: - LOKTransferable(const size_t nInCount, - const char **pInMimeTypes, - const size_t *pInSizes, - const char **pInStreams); + LOKTransferable(const size_t nInCount, const char** pInMimeTypes, const size_t* pInSizes, + const char** pInStreams); css::uno::Any SAL_CALL getTransferData(const css::datatransfer::DataFlavor& rFlavor) override; @@ -50,6 +84,27 @@ public: sal_Bool SAL_CALL isDataFlavorSupported(const css::datatransfer::DataFlavor& rFlavor) override; }; +/// Theoretically to hook into the (horrible) vcl dtranscomp.cxx code. +class LOKClipboardFactory : public ::cppu::WeakComponentImplHelper<css::lang::XSingleServiceFactory> +{ + static osl::Mutex gMutex; + static std::unordered_map<int, rtl::Reference<LOKClipboard>> gClipboards; + +public: + LOKClipboardFactory() + : cppu::WeakComponentImplHelper<css::lang::XSingleServiceFactory>(gMutex) + { + } + + css::uno::Reference<css::uno::XInterface> SAL_CALL createInstance() override + { + return createInstanceWithArguments(css::uno::Sequence<css::uno::Any>()); + } + css::uno::Reference<css::uno::XInterface> SAL_CALL + createInstanceWithArguments(const css::uno::Sequence<css::uno::Any>& /* rArgs */) override; + static rtl::Reference<LOKClipboard> getClipboardForCurView(); +}; + #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |