QtClipboard::QtClipboard(OUString aModeString, const QClipboard::Mode aMode)
: cppu::WeakComponentImplHelper<css::datatransfer::clipboard::XSystemClipboard,
css::datatransfer::clipboard::XFlushableClipboard,
XServiceInfo>(m_aMutex)
, m_aClipboardName(std::move(aModeString))
, m_aClipboardMode(aMode)
, m_bOwnClipboardChange(false)
, m_bDoClear(false)
{
assert(isSupported(m_aClipboardMode)); // DirectConnection guarantees the changed slot runs in the same thread as the QClipboard
connect(QApplication::clipboard(), &QClipboard::changed, this, &QtClipboard::handleChanged,
Qt::DirectConnection);
// explicitly queue an event, so we can eventually ignore it
connect(this, &QtClipboard::clearClipboard, this, &QtClipboard::handleClearClipboard,
Qt::QueuedConnection);
}
// if we're the owner, we might have the XTransferable from setContents. but // maybe a non-LO clipboard change from within LO, like some C'n'P in the // QFileDialog, might have invalidated m_aContents, so we need to check it too. if (isOwner(m_aClipboardMode) && m_aContents.is()) return m_aContents;
// check if we can still use the shared QtClipboardTransferable const QMimeData* pMimeData = QApplication::clipboard()->mimeData(m_aClipboardMode); #ifdefined(EMSCRIPTEN) if (!pMimeData)
pMimeData = &aMimeData; #endif if (m_aContents.is())
{ constauto* pTrans = dynamic_cast<QtClipboardTransferable*>(m_aContents.get());
assert(pTrans); if (pTrans && pTrans->hasMimeData(pMimeData)) return m_aContents;
}
m_aContents = new QtClipboardTransferable(m_aClipboardMode, pMimeData); return m_aContents;
}
void QtClipboard::handleClearClipboard()
{ if (!m_bDoClear) return;
QApplication::clipboard()->clear(m_aClipboardMode);
}
void QtClipboard::setContents( const css::uno::Reference<css::datatransfer::XTransferable>& xTrans, const css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner>& xClipboardOwner)
{ // it's actually possible to get a non-empty xTrans and an empty xClipboardOwner!
osl::ClearableMutexGuard aGuard(m_aMutex);
#ifdefined EMSCRIPTEN && QT_VERSION < QT_VERSION_CHECK(6, 0, 0) // At least Qt5, in QWasmEventTranslator::processKeyboard in qbase // src/plugins/platforms/wasm/qwasmeventtranslator.cpp, listens for Ctrl-C and initiates a // browser Clipboard API writeText call, but (a) calls it before LO has sent the to-be-copied // data to Qt (so calls it with old data), and (b) only works for Ctrl-C, not for Ctrl-X nor for // cut/copy operations not initiated via the keyboard; so always do a writeText call here, and // hope that the browser gives permission:
OUString textContents;
css::datatransfer::DataFlavor flav{ u"text/plain;charset=utf-16"_ustr, u""_ustr,
cppu::UnoType<OUString>::get() }; if (xTrans->isDataFlavorSupported(flav))
{ try
{
xTrans->getTransferData(flav) >>= textContents;
} catch (css::io::IOException)
{
TOOLS_WARN_EXCEPTION("vcl.qt", "");
}
}
MAIN_THREAD_EM_ASM(
{ // clang-format off try { //TODO: Support embedded NULs:
navigator.clipboard.writeText(Module.UTF16ToString($0, 2 * $1));
} catch (e) {
console.warn("clipboard.writeText failed:", e);
} // clang-format on
},
textContents.getStr(), textContents.getLength()); #endif
// we have to notify only an owner change, since handleChanged can't // access the previous owner anymore and can just handle lost ownership. if (xOldOwner.is() && xOldOwner != xClipboardOwner)
xOldOwner->lostOwnership(this, xOldContents);
}
void QtClipboard::handleChanged(QClipboard::Mode aMode)
{ if (aMode != m_aClipboardMode) return;
osl::ClearableMutexGuard aGuard(m_aMutex);
if (!m_bOwnClipboardChange && isOwner(aMode))
{ autoconst mimeData = QApplication::clipboard()->mimeData(aMode);
// QtWayland will send a second change notification (seemingly without any // trigger). And any C'n'P operation in the Qt file picker emits a signal, // with LO still holding the clipboard ownership, but internally having lost // it. So ignore any signal, which still delivers the internal QtMimeData // as the clipboard content and is no "advertised" change. if (qobject_cast<const QtMimeData*>(mimeData)) return;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) && defined EMSCRIPTEN // At least for the Qt5 Wasm backend, copying text from LO and then pasting it back into LO // will, for whatever reason, call here with an empty text/plain mimeData; while that // doesn't seem to be an issue at least with the current upstream Qt6 dev branch (again, for // whatever reason), for at least our Qt 5.15.2+wasm branch the below m_aContents.clear() // would make us lose the text just copied from LO into the clipboard and thus make us paste // an empty text into LO, so, as a hack, filter out this unhelpful event here: if (mimeData != nullptr && mimeData->hasText() && mimeData->text().isEmpty())
{ return;
} #endif
}
css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner> xOldOwner(m_aOwner);
css::uno::Reference<css::datatransfer::XTransferable> xOldContents(m_aContents); // ownership change from LO POV is handled in setContents if (!m_bOwnClipboardChange)
{
m_aContents.clear();
m_aOwner.clear();
}
case QClipboard::FindBuffer: return pClipboard->ownsFindBuffer();
case QClipboard::Clipboard: if (pClipboard->ownsClipboard())
{ returntrue;
} #ifdefined EMSCRIPTEN // QWasmClipboard::ownsMode (in qtbase/src/plugins/platforms/wasm/qwasmclipboard.cpp, // which is the actual implementation of the above ownsClipboard call) unconditionally // returns false, so as a hack use "m_aContents is a LO-internal XTransferable type" as // a poor approximation of "LO owns the clipboard": if (m_aContents.is()
&& dynamic_cast<QtClipboardTransferable*>(m_aContents.get()) == nullptr)
{ returntrue;
} #endif returnfalse;
} returnfalse;
}
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.