8#include <QtGui/qguiapplication.h>
9#include <QtGui/qclipboard.h>
10#include <QtGui/qcolor.h>
11#include <QtGui/qimage.h>
13#include <QtCore/qdebug.h>
14#include <QtCore/qmimedata.h>
15#include <QtCore/qstringlist.h>
16#include <QtCore/qthread.h>
17#include <QtCore/qvariant.h>
18#include <QtCore/qurl.h>
19#include <QtCore/private/qsystemerror_p.h>
21#include <QtGui/private/qwindowsguieventdispatcher_p.h>
26
27
28
29
30
31
32
33
34
35
36
37
38
40#ifndef QT_NO_DEBUG_STREAM
41static QDebug operator<<(QDebug d,
const QMimeData *mimeData)
43 QDebugStateSaver saver(d);
47 const QStringList formats = mimeData->formats();
48 d <<
"formats=" << formats.join(u", ");
49 if (mimeData->hasText())
50 d <<
", text=" << mimeData->text();
51 if (mimeData->hasHtml())
52 d <<
", html=" << mimeData->html();
53 if (mimeData->hasColor())
54 d <<
", colorData=" << qvariant_cast<QColor>(mimeData->colorData());
55 if (mimeData->hasImage())
56 d <<
", imageData=" << qvariant_cast<QImage>(mimeData->imageData());
57 if (mimeData->hasUrls())
58 d <<
", urls=" << mimeData->urls();
68
69
70
71
72
73
74
75
76
80 enum :
int { attempts = 3 };
81 IDataObject * pDataObj =
nullptr;
83 for (
int i = 1; i <= attempts; ++i) {
84 if (SUCCEEDED(OleGetClipboard(&pDataObj))) {
85 if (QWindowsContext::verbose > 1)
86 qCDebug(lcQpaMime) <<
__FUNCTION__ << pDataObj;
89 qCWarning(lcQpaMime, i == attempts
90 ?
"Unable to obtain clipboard."
91 :
"Retrying to obtain clipboard.");
100 dataObject->Release();
103LRESULT QT_WIN_CALLBACK qClipboardViewerWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
106 if (QWindowsClipboard::instance()
107 && QWindowsClipboard::instance()->clipboardViewerWndProc(hwnd, message, wParam, lParam, &result))
109 return DefWindowProc(hwnd, message, wParam, lParam);
154 m_clipboardViewer = QWindowsContext::instance()->
155 createDummyWindow(QStringLiteral(
"ClipboardView"), L"QtClipboardView",
156 qClipboardViewerWndProc, WS_OVERLAPPED);
158 m_formatListenerRegistered = AddClipboardFormatListener(m_clipboardViewer);
159 if (!m_formatListenerRegistered)
160 qErrnoWarning(
"AddClipboardFormatListener() failed.");
162 if (!m_formatListenerRegistered)
163 m_nextClipboardViewer = SetClipboardViewer(m_clipboardViewer);
165 qCDebug(lcQpaMime) <<
__FUNCTION__ <<
"m_clipboardViewer:" << m_clipboardViewer
166 <<
"format listener:" << m_formatListenerRegistered
167 <<
"next:" << m_nextClipboardViewer;
172 if (m_clipboardViewer) {
173 if (m_formatListenerRegistered) {
174 RemoveClipboardFormatListener(m_clipboardViewer);
175 m_formatListenerRegistered =
false;
177 ChangeClipboardChain(m_clipboardViewer, m_nextClipboardViewer);
178 m_nextClipboardViewer =
nullptr;
180 DestroyWindow(m_clipboardViewer);
181 m_clipboardViewer =
nullptr;
191 if (!GetWindowThreadProcessId(hwnd, &pid) || !pid)
193 const HANDLE processHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
196 BOOL debugged = FALSE;
197 CheckRemoteDebuggerPresent(processHandle, &debugged);
198 CloseHandle(processHandle);
199 return debugged != FALSE;
202void QWindowsClipboard::propagateClipboardMessage(UINT message, WPARAM wParam, LPARAM lParam)
const
204 if (!m_nextClipboardViewer)
208 if (IsHungAppWindow(m_nextClipboardViewer)) {
209 qWarning(
"Cowardly refusing to send clipboard message to hung application...");
214 if (isProcessBeingDebugged(m_nextClipboardViewer))
215 PostMessage(m_nextClipboardViewer, message, wParam, lParam);
217 SendMessage(m_nextClipboardViewer, message, wParam, lParam);
221
222
223
227 enum { wMClipboardUpdate = 0x031D };
230 if (QWindowsContext::verbose)
231 qCDebug(lcQpaMime) <<
__FUNCTION__ << hwnd << message << QWindowsGuiEventDispatcher::windowsMessageName(message);
234 case WM_CHANGECBCHAIN: {
235 const HWND toBeRemoved =
reinterpret_cast<HWND>(wParam);
236 if (toBeRemoved == m_nextClipboardViewer) {
237 m_nextClipboardViewer =
reinterpret_cast<HWND>(lParam);
239 propagateClipboardMessage(message, wParam, lParam);
243 case wMClipboardUpdate:
244 case WM_DRAWCLIPBOARD: {
245 const bool owned = ownsClipboard();
246 qCDebug(lcQpaMime) <<
"Clipboard changed owned " << owned;
247 emitChanged(QClipboard::Clipboard);
249 if (!owned && m_data)
251 if (!m_formatListenerRegistered)
252 propagateClipboardMessage(message, wParam, lParam);
257 if (ownsClipboard()) {
258 qCDebug(lcQpaMime) <<
"Clipboard owner on shutdown, releasing.";
269 qCDebug(lcQpaMime) <<
__FUNCTION__ << mode;
270 if (mode != QClipboard::Clipboard)
274 return &m_retrievalData;
279 qCDebug(lcQpaMime) <<
__FUNCTION__ << mode << mimeData;
280 if (mode != QClipboard::Clipboard)
283 const bool newData = !m_data || m_data
->mimeData() != mimeData;
290 HRESULT src = S_FALSE;
292 for (; attempts < 3; ++attempts) {
293 src = OleSetClipboard(m_data);
294 if (src != CLIPBRD_E_CANT_OPEN || QWindowsContext::isSessionLocked())
296 QThread::msleep(100);
300 QString mimeDataFormats = mimeData ?
301 mimeData->formats().join(u", ") : QString(QStringLiteral(
"NULL"));
302 qErrnoWarning(
"OleSetClipboard: Failed to set mime data (%s) on clipboard: %s",
303 qPrintable(mimeDataFormats),
304 qPrintable(QSystemError::windowsComString(src)));
312 const HRESULT src = OleSetClipboard(
nullptr);
314 qErrnoWarning(
"OleSetClipboard: Failed to clear the clipboard: 0x%lx", src);
319 return mode == QClipboard::Clipboard;
325 return m_data && OleIsCurrentClipboard(m_data) == S_OK;
330 const bool result = mode == QClipboard::Clipboard ?
331 ownsClipboard() :
false;
332 qCDebug(lcQpaMime) <<
__FUNCTION__ << mode << result;
Special mime data class managing delayed retrieval of clipboard data.
void releaseDataObject(IDataObject *) const override
IDataObject * retrieveDataObject() const override
Clipboard implementation.
bool supportsMode(QClipboard::Mode mode) const override
QMimeData * mimeData(QClipboard::Mode mode=QClipboard::Clipboard) override
~QWindowsClipboard() override
bool ownsMode(QClipboard::Mode mode) const override
static QWindowsClipboard * instance()
bool clipboardViewerWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result)
Windows procedure of the clipboard viewer.
QWindowsOleDataObject(QMimeData *mimeData)
QMimeData * mimeData() const
static bool isProcessBeingDebugged(HWND hwnd)
static void cleanClipboardPostRoutine()