bump product version to 6.4.0.3
[LibreOffice.git] / vcl / qt5 / Qt5Clipboard.cxx
blobcadedbfd327e42f5e8db874013a2699cb2f53eac
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)
34 assert(isSupported(m_aClipboardMode));
35 // DirectConnection guarantees the changed slot runs in the same thread as the QClipboard
36 connect(QApplication::clipboard(), &QClipboard::changed, this, &Qt5Clipboard::handleChanged,
37 Qt::DirectConnection);
40 css::uno::Reference<css::uno::XInterface> Qt5Clipboard::create(const OUString& aModeString)
42 static const std::map<OUString, QClipboard::Mode> aNameToClipboardMap
43 = { { "CLIPBOARD", QClipboard::Clipboard }, { "PRIMARY", QClipboard::Selection } };
45 assert(QApplication::clipboard()->thread() == qApp->thread());
47 auto iter = aNameToClipboardMap.find(aModeString);
48 if (iter != aNameToClipboardMap.end() && isSupported(iter->second))
49 return static_cast<cppu::OWeakObject*>(new Qt5Clipboard(aModeString, iter->second));
50 SAL_WARN("vcl.qt5", "Ignoring unrecognized clipboard type: '" << aModeString << "'");
51 return css::uno::Reference<css::uno::XInterface>();
54 void Qt5Clipboard::flushClipboard()
56 auto* pSalInst(static_cast<Qt5Instance*>(GetSalData()->m_pInstance));
57 SolarMutexGuard g;
58 pSalInst->RunInMainThread([&, this]() {
59 if (!isOwner(m_aClipboardMode))
60 return;
62 QClipboard* pClipboard = QApplication::clipboard();
63 const Qt5MimeData* pQt5MimeData
64 = dynamic_cast<const Qt5MimeData*>(pClipboard->mimeData(m_aClipboardMode));
65 assert(pQt5MimeData);
67 QMimeData* pMimeCopy = nullptr;
68 if (pQt5MimeData && pQt5MimeData->deepCopy(&pMimeCopy))
70 m_bOwnClipboardChange = true;
71 pClipboard->setMimeData(pMimeCopy, m_aClipboardMode);
72 m_bOwnClipboardChange = false;
74 });
77 css::uno::Reference<css::datatransfer::XTransferable> Qt5Clipboard::getContents()
79 osl::MutexGuard aGuard(m_aMutex);
81 // if we're the owner, we might have the XTransferable from setContents. but
82 // maybe a non-LO clipboard change from within LO, like some C'n'P in the
83 // QFileDialog, might have invalidated m_aContents, so we need to check it too.
84 if (isOwner(m_aClipboardMode) && m_aContents.is())
85 return m_aContents;
87 // check if we can still use the shared Qt5ClipboardTransferable
88 const QMimeData* pMimeData = QApplication::clipboard()->mimeData(m_aClipboardMode);
89 if (m_aContents.is())
91 const auto* pTrans = dynamic_cast<Qt5ClipboardTransferable*>(m_aContents.get());
92 assert(pTrans);
93 if (pTrans && pTrans->mimeData() == pMimeData)
94 return m_aContents;
97 m_aContents = new Qt5ClipboardTransferable(m_aClipboardMode, pMimeData);
98 return m_aContents;
101 void Qt5Clipboard::setContents(
102 const css::uno::Reference<css::datatransfer::XTransferable>& xTrans,
103 const css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner>& xClipboardOwner)
105 // it's actually possible to get a non-empty xTrans and an empty xClipboardOwner!
106 osl::ClearableMutexGuard aGuard(m_aMutex);
108 css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner> xOldOwner(m_aOwner);
109 css::uno::Reference<css::datatransfer::XTransferable> xOldContents(m_aContents);
110 m_aContents = xTrans;
111 m_aOwner = xClipboardOwner;
113 m_bOwnClipboardChange = true;
114 if (m_aContents.is())
115 QApplication::clipboard()->setMimeData(new Qt5MimeData(m_aContents), m_aClipboardMode);
116 else
118 assert(!m_aOwner.is());
119 QApplication::clipboard()->clear(m_aClipboardMode);
121 m_bOwnClipboardChange = false;
123 aGuard.clear();
125 // we have to notify only an owner change, since handleChanged can't
126 // access the previous owner anymore and can just handle lost ownership.
127 if (xOldOwner.is() && xOldOwner != xClipboardOwner)
128 xOldOwner->lostOwnership(this, xOldContents);
131 void Qt5Clipboard::handleChanged(QClipboard::Mode aMode)
133 if (aMode != m_aClipboardMode)
134 return;
136 osl::ClearableMutexGuard aGuard(m_aMutex);
138 css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner> xOldOwner(m_aOwner);
139 css::uno::Reference<css::datatransfer::XTransferable> xOldContents(m_aContents);
140 // ownership change from LO POV is handled in setContents
141 if (!m_bOwnClipboardChange)
143 m_aContents.clear();
144 m_aOwner.clear();
147 std::vector<css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>> aListeners(
148 m_aListeners);
149 css::datatransfer::clipboard::ClipboardEvent aEv;
150 aEv.Contents = getContents();
152 aGuard.clear();
154 if (!m_bOwnClipboardChange && xOldOwner.is())
155 xOldOwner->lostOwnership(this, xOldContents);
156 for (auto const& listener : aListeners)
157 listener->changedContents(aEv);
160 OUString Qt5Clipboard::getImplementationName() { return "com.sun.star.datatransfer.Qt5Clipboard"; }
162 css::uno::Sequence<OUString> Qt5Clipboard::getSupportedServiceNames()
164 return { "com.sun.star.datatransfer.clipboard.SystemClipboard" };
167 sal_Bool Qt5Clipboard::supportsService(const OUString& ServiceName)
169 return cppu::supportsService(this, ServiceName);
172 OUString Qt5Clipboard::getName() { return m_aClipboardName; }
174 sal_Int8 Qt5Clipboard::getRenderingCapabilities() { return 0; }
176 void Qt5Clipboard::addClipboardListener(
177 const css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>& listener)
179 osl::MutexGuard aGuard(m_aMutex);
180 m_aListeners.push_back(listener);
183 void Qt5Clipboard::removeClipboardListener(
184 const css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>& listener)
186 osl::MutexGuard aGuard(m_aMutex);
187 m_aListeners.erase(std::remove(m_aListeners.begin(), m_aListeners.end(), listener),
188 m_aListeners.end());
191 bool Qt5Clipboard::isSupported(const QClipboard::Mode aMode)
193 const QClipboard* pClipboard = QApplication::clipboard();
194 switch (aMode)
196 case QClipboard::Selection:
197 return pClipboard->supportsSelection();
199 case QClipboard::FindBuffer:
200 return pClipboard->supportsFindBuffer();
202 case QClipboard::Clipboard:
203 return true;
205 return false;
208 bool Qt5Clipboard::isOwner(const QClipboard::Mode aMode)
210 if (!isSupported(aMode))
211 return false;
213 const QClipboard* pClipboard = QApplication::clipboard();
214 switch (aMode)
216 case QClipboard::Selection:
217 return pClipboard->ownsSelection();
219 case QClipboard::FindBuffer:
220 return pClipboard->ownsFindBuffer();
222 case QClipboard::Clipboard:
223 return pClipboard->ownsClipboard();
225 return false;
228 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */