/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
CXNotifyingDataObject* CWinClipboard::getOwnClipContent() const
{
assert(!m_pCurrentOwnClipContent || !m_pNewOwnClipContent); // Both can be null, or only one set return m_pCurrentOwnClipContent ? m_pCurrentOwnClipContent : m_pNewOwnClipContent;
}
// to avoid unnecessary traffic we check first if there is a clipboard // content which was set via setContent, in this case we don't need // to query the content from the clipboard, create a new wrapper object // and so on, we simply return the original XTransferable instead of our // DOTransferable
css::uno::Reference<css::datatransfer::XTransferable> CWinClipboard::getContents_noLock()
{ if (m_bDisposed) throw lang::DisposedException("object is already disposed", static_cast<XClipboardEx*>(this));
assert(!getOwnClipContent() || !m_foreignContent); // Both can be null, or only one set
// use the shortcut or create a transferable from // system clipboard if (auto pOwnClipContent = getOwnClipContent()) return pOwnClipContent->m_XTransferable;
// Content cached? if (m_foreignContent.is()) return m_foreignContent;
// get the current format list from clipboard if (UINT nFormats; !GetUpdatedClipboardFormats(nullptr, 0, &nFormats)
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
std::vector<UINT> aUINTFormats(nFormats); if (GetUpdatedClipboardFormats(aUINTFormats.data(), nFormats, &nFormats))
{
std::vector<sal_uInt32> aFormats(aUINTFormats.begin(), aUINTFormats.end());
rClipContent = new CDOTransferable(m_xContext, this, aFormats);
if (m_bDisposed) throw lang::DisposedException("object is already disposed", static_cast<XClipboardEx*>(this));
} // get the current dataobject from clipboard
IDataObjectPtr pIDataObject;
HRESULT hr = m_MtaOleClipboard.getClipboard(&pIDataObject);
if (SUCCEEDED(hr))
{ // create an apartment neutral dataobject and initialize it with a // com smart pointer to the IDataObject from clipboard
pIDataObject = new CAPNDataObject(pIDataObject);
}
if (m_bDisposed) throw lang::DisposedException("object is already disposed", static_cast<XClipboardEx*>(this));
IDataObjectPtr pIDataObj;
// The object must be destroyed only outside of the mutex lock, and in a different thread, // because it may call CWinClipboard::onReleaseDataObject, or try to lock solar mutex, in // another thread of this process synchronously
releaseAsync(m_foreignContent); // clear m_foreignContent
assert(!m_foreignContent.is());
m_pCurrentOwnClipContent = nullptr;
if (xTransferable.is())
{ // Store the new object's pointer to temporary m_pNewOwnClipContent, to be moved to // m_pCurrentOwnClipContent in handleClipboardContentChanged.
m_pNewOwnClipContent = new CXNotifyingDataObject(
CDTransObjFactory::createDataObjFromTransferable(m_xContext, xTransferable),
xTransferable, xClipboardOwner, this);
if (m_bDisposed) throw lang::DisposedException("object is already disposed", static_cast<XClipboardEx*>(this));
// FlushClipboard does a callback and frees DataObject, which calls onReleaseDataObject and // locks mutex. FlushClipboard has to be synchron in order to prevent shutdown until all // clipboard-formats are rendered. The request is needed to prevent flushing if we are not // clipboard owner (it is not known what happens if we flush but aren't clipboard owner). // It may be possible to move the request to the clipboard STA thread by saving the // DataObject and call OleIsCurrentClipboard before flushing.
if (getOwnClipContent())
{
aGuard.unlock();
m_MtaOleClipboard.flushClipboard();
}
}
// XClipboardEx
sal_Int8 SAL_CALL CWinClipboard::getRenderingCapabilities()
{ if (m_bDisposed) throw lang::DisposedException("object is already disposed", static_cast<XClipboardEx*>(this));
void CWinClipboard::handleClipboardContentChanged()
{
std::unique_lock aGuard(m_aMutex); if (m_bDisposed) return;
// The object must be destroyed only outside of the mutex lock, and in a different thread, // because it may call CWinClipboard::onReleaseDataObject, or try to lock solar mutex, in // another thread of this process synchronously
releaseAsync(m_foreignContent); // clear m_foreignContent
assert(!m_foreignContent.is()); // If new own content assignment is pending, do it; otherwise, clear it. // This makes sure that there will be no stuck clipboard content.
m_pCurrentOwnClipContent = std::exchange(m_pNewOwnClipContent, nullptr);
if (!maClipboardListeners.getLength(aGuard)) return;
try
{
uno::Reference<datatransfer::XTransferable> rXTransf(getContents_noLock());
datatransfer::clipboard::ClipboardEvent aClipbEvent(static_cast<XClipboard*>(this),
rXTransf);
maClipboardListeners.notifyEach(
aGuard, &datatransfer::clipboard::XClipboardListener::changedContents, aClipbEvent);
aGuard.unlock(); // for XTransferable dtor, that may delegate to another thread
} catch (const lang::DisposedException&)
{
OSL_FAIL("Service Manager disposed"); if (aGuard.owns_lock())
aGuard.unlock(); // no further clipboard changed notifications
unregisterClipboardViewer();
}
}
extern"C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
dtrans_CWinClipboard_get_implementation(css::uno::XComponentContext* context,
css::uno::Sequence<css::uno::Any> const& args)
{ // We run unit tests in parallel, which is a problem when touching a shared resource // like the system clipboard, so rather use the dummy GenericClipboard. staticconstbool bRunningUnitTest = o3tl::IsRunningUnitTest() || o3tl::IsRunningUITest();
if (bRunningUnitTest)
{
SolarMutexGuard aGuard; auto xClipboard = ImplGetSVData()->mpDefInst->CreateClipboard(args); if (xClipboard.is())
xClipboard->acquire(); return xClipboard.get();
} else
{ return cppu::acquire(new CWinClipboard(context, ""));
}
}
// if the current caller is the one we currently hold, then set it to NULL // because an external source must be the clipboardowner now
std::unique_lock aGuard(m_aMutex);
if (getOwnClipContent() == &theCaller)
m_pCurrentOwnClipContent = m_pNewOwnClipContent = nullptr;
}
void WINAPI CWinClipboard::onClipboardContentChanged()
{
rtl::Reference<CWinClipboard> pWinClipboard;
{ // Only hold the mutex to obtain a safe reference to the impl, to avoid deadlock
std::unique_lock aGuard(s_aClipboardSingletonMutex);
pWinClipboard.set(s_pCWinClipbImpl);
}
if (pWinClipboard)
pWinClipboard->handleClipboardContentChanged();
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.