nss: upgrade to release 3.73
[LibreOffice.git] / vcl / qt5 / Qt5Clipboard.cxx
blob41881f0be4b6139a6db9fd464a1ee03fee24d09c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 */
11 #include <Qt5Clipboard.hxx>
12 #include <Qt5Clipboard.moc>
14 #include <cppuhelper/supportsservice.hxx>
15 #include <sal/log.hxx>
17 #include <QtWidgets/QApplication>
19 #include <Qt5Instance.hxx>
20 #include <Qt5Transferable.hxx>
21 #include <Qt5Tools.hxx>
23 #include <cassert>
24 #include <map>
26 Qt5Clipboard::Qt5Clipboard(const OUString& aModeString, const QClipboard::Mode aMode)
27 : cppu::WeakComponentImplHelper<css::datatransfer::clipboard::XSystemClipboard,
28 css::datatransfer::clipboard::XFlushableClipboard,
29 XServiceInfo>(m_aMutex)
30 , m_aClipboardName(aModeString)
31 , m_aClipboardMode(aMode)
32 , m_bOwnClipboardChange(false)
33 , m_bDoClear(false)
35 assert(isSupported(m_aClipboardMode));
36 // DirectConnection guarantees the changed slot runs in the same thread as the QClipboard
37 connect(QApplication::clipboard(), &QClipboard::changed, this, &Qt5Clipboard::handleChanged,
38 Qt::DirectConnection);
40 // explicitly queue an event, so we can eventually ignore it
41 connect(this, &Qt5Clipboard::clearClipboard, this, &Qt5Clipboard::handleClearClipboard,
42 Qt::QueuedConnection);
45 css::uno::Reference<css::uno::XInterface> Qt5Clipboard::create(const OUString& aModeString)
47 static const std::map<OUString, QClipboard::Mode> aNameToClipboardMap
48 = { { "CLIPBOARD", QClipboard::Clipboard }, { "PRIMARY", QClipboard::Selection } };
50 assert(QApplication::clipboard()->thread() == qApp->thread());
52 auto iter = aNameToClipboardMap.find(aModeString);
53 if (iter != aNameToClipboardMap.end() && isSupported(iter->second))
54 return static_cast<cppu::OWeakObject*>(new Qt5Clipboard(aModeString, iter->second));
55 SAL_WARN("vcl.qt5", "Ignoring unrecognized clipboard type: '" << aModeString << "'");
56 return css::uno::Reference<css::uno::XInterface>();
59 void Qt5Clipboard::flushClipboard()
61 auto* pSalInst(static_cast<Qt5Instance*>(GetSalData()->m_pInstance));
62 SolarMutexGuard g;
63 pSalInst->RunInMainThread([&, this]() {
64 if (!isOwner(m_aClipboardMode))
65 return;
67 QClipboard* pClipboard = QApplication::clipboard();
68 const Qt5MimeData* pQt5MimeData
69 = dynamic_cast<const Qt5MimeData*>(pClipboard->mimeData(m_aClipboardMode));
70 assert(pQt5MimeData);
72 QMimeData* pMimeCopy = nullptr;
73 if (pQt5MimeData && pQt5MimeData->deepCopy(&pMimeCopy))
75 m_bOwnClipboardChange = true;
76 pClipboard->setMimeData(pMimeCopy, m_aClipboardMode);
77 m_bOwnClipboardChange = false;
79 });
82 css::uno::Reference<css::datatransfer::XTransferable> Qt5Clipboard::getContents()
84 osl::MutexGuard aGuard(m_aMutex);
86 // if we're the owner, we might have the XTransferable from setContents. but
87 // maybe a non-LO clipboard change from within LO, like some C'n'P in the
88 // QFileDialog, might have invalidated m_aContents, so we need to check it too.
89 if (isOwner(m_aClipboardMode) && m_aContents.is())
90 return m_aContents;
92 // check if we can still use the shared Qt5ClipboardTransferable
93 const QMimeData* pMimeData = QApplication::clipboard()->mimeData(m_aClipboardMode);
94 if (m_aContents.is())
96 const auto* pTrans = dynamic_cast<Qt5ClipboardTransferable*>(m_aContents.get());
97 assert(pTrans);
98 if (pTrans && pTrans->mimeData() == pMimeData)
99 return m_aContents;
102 m_aContents = new Qt5ClipboardTransferable(m_aClipboardMode, pMimeData);
103 return m_aContents;
106 void Qt5Clipboard::handleClearClipboard()
108 if (!m_bDoClear)
109 return;
110 QApplication::clipboard()->clear(m_aClipboardMode);
113 void Qt5Clipboard::setContents(
114 const css::uno::Reference<css::datatransfer::XTransferable>& xTrans,
115 const css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner>& xClipboardOwner)
117 // it's actually possible to get a non-empty xTrans and an empty xClipboardOwner!
118 osl::ClearableMutexGuard aGuard(m_aMutex);
120 css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner> xOldOwner(m_aOwner);
121 css::uno::Reference<css::datatransfer::XTransferable> xOldContents(m_aContents);
122 m_aContents = xTrans;
123 m_aOwner = xClipboardOwner;
125 m_bDoClear = !m_aContents.is();
126 if (!m_bDoClear)
128 m_bOwnClipboardChange = true;
129 QApplication::clipboard()->setMimeData(new Qt5MimeData(m_aContents), m_aClipboardMode);
130 m_bOwnClipboardChange = false;
132 else
134 assert(!m_aOwner.is());
135 Q_EMIT clearClipboard();
138 aGuard.clear();
140 // we have to notify only an owner change, since handleChanged can't
141 // access the previous owner anymore and can just handle lost ownership.
142 if (xOldOwner.is() && xOldOwner != xClipboardOwner)
143 xOldOwner->lostOwnership(this, xOldContents);
146 void Qt5Clipboard::handleChanged(QClipboard::Mode aMode)
148 if (aMode != m_aClipboardMode)
149 return;
151 osl::ClearableMutexGuard aGuard(m_aMutex);
153 // QtWayland will send a second change notification (seemingly without any
154 // trigger). And any C'n'P operation in the Qt file picker emits a signal,
155 // with LO still holding the clipboard ownership, but internally having lost
156 // it. So ignore any signal, which still delivers the internal Qt5MimeData
157 // as the clipboard content and is no "advertised" change.
158 if (!m_bOwnClipboardChange && isOwner(aMode)
159 && dynamic_cast<const Qt5MimeData*>(QApplication::clipboard()->mimeData(aMode)))
160 return;
162 css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner> xOldOwner(m_aOwner);
163 css::uno::Reference<css::datatransfer::XTransferable> xOldContents(m_aContents);
164 // ownership change from LO POV is handled in setContents
165 if (!m_bOwnClipboardChange)
167 m_aContents.clear();
168 m_aOwner.clear();
171 std::vector<css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>> aListeners(
172 m_aListeners);
173 css::datatransfer::clipboard::ClipboardEvent aEv;
174 aEv.Contents = getContents();
176 aGuard.clear();
178 if (!m_bOwnClipboardChange && xOldOwner.is())
179 xOldOwner->lostOwnership(this, xOldContents);
180 for (auto const& listener : aListeners)
181 listener->changedContents(aEv);
184 OUString Qt5Clipboard::getImplementationName() { return "com.sun.star.datatransfer.Qt5Clipboard"; }
186 css::uno::Sequence<OUString> Qt5Clipboard::getSupportedServiceNames()
188 return { "com.sun.star.datatransfer.clipboard.SystemClipboard" };
191 sal_Bool Qt5Clipboard::supportsService(const OUString& ServiceName)
193 return cppu::supportsService(this, ServiceName);
196 OUString Qt5Clipboard::getName() { return m_aClipboardName; }
198 sal_Int8 Qt5Clipboard::getRenderingCapabilities() { return 0; }
200 void Qt5Clipboard::addClipboardListener(
201 const css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>& listener)
203 osl::MutexGuard aGuard(m_aMutex);
204 m_aListeners.push_back(listener);
207 void Qt5Clipboard::removeClipboardListener(
208 const css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>& listener)
210 osl::MutexGuard aGuard(m_aMutex);
211 m_aListeners.erase(std::remove(m_aListeners.begin(), m_aListeners.end(), listener),
212 m_aListeners.end());
215 bool Qt5Clipboard::isSupported(const QClipboard::Mode aMode)
217 const QClipboard* pClipboard = QApplication::clipboard();
218 switch (aMode)
220 case QClipboard::Selection:
221 return pClipboard->supportsSelection();
223 case QClipboard::FindBuffer:
224 return pClipboard->supportsFindBuffer();
226 case QClipboard::Clipboard:
227 return true;
229 return false;
232 bool Qt5Clipboard::isOwner(const QClipboard::Mode aMode)
234 if (!isSupported(aMode))
235 return false;
237 const QClipboard* pClipboard = QApplication::clipboard();
238 switch (aMode)
240 case QClipboard::Selection:
241 return pClipboard->ownsSelection();
243 case QClipboard::FindBuffer:
244 return pClipboard->ownsFindBuffer();
246 case QClipboard::Clipboard:
247 return pClipboard->ownsClipboard();
249 return false;
252 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */