9#include <QtGui/qguiapplication.h>
10#include <QtGui/qclipboard.h>
11#include <QtGui/qcolor.h>
12#include <QtGui/qimage.h>
14#include <QtCore/qdebug.h>
15#include <QtCore/qmimedata.h>
16#include <QtCore/qstringlist.h>
17#include <QtCore/qthread.h>
18#include <QtCore/qvariant.h>
19#include <QtCore/qurl.h>
20#include <QtCore/private/qsystemerror_p.h>
22#include <QtGui/private/qwindowsguieventdispatcher_p.h>
27
28
29
30
31
32
33
34
35
36
37
38
39
41#ifndef QT_NO_DEBUG_STREAM
42static QDebug operator<<(QDebug d,
const QMimeData *mimeData)
44 QDebugStateSaver saver(d);
48 const QStringList formats = mimeData->formats();
49 d <<
"formats=" << formats.join(u", ");
50 if (mimeData->hasText())
51 d <<
", text=" << mimeData->text();
52 if (mimeData->hasHtml())
53 d <<
", html=" << mimeData->html();
54 if (mimeData->hasColor())
55 d <<
", colorData=" << qvariant_cast<QColor>(mimeData->colorData());
56 if (mimeData->hasImage())
57 d <<
", imageData=" << qvariant_cast<QImage>(mimeData->imageData());
58 if (mimeData->hasUrls())
59 d <<
", urls=" << mimeData->urls();
69
70
71
72
73
74
75
76
77
81 enum :
int { attempts = 3 };
82 IDataObject * pDataObj =
nullptr;
84 for (
int i = 1; i <= attempts; ++i) {
85 if (SUCCEEDED(OleGetClipboard(&pDataObj))) {
87 qCDebug(lcQpaMime) <<
__FUNCTION__ << pDataObj;
90 qCWarning(lcQpaMime, i == attempts
91 ?
"Unable to obtain clipboard."
92 :
"Retrying to obtain clipboard.");
101 dataObject->Release();
104LRESULT QT_WIN_CALLBACK qClipboardViewerWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
107 if (QWindowsClipboard::instance()
108 && QWindowsClipboard::instance()->clipboardViewerWndProc(hwnd, message, wParam, lParam, &result))
110 return DefWindowProc(hwnd, message, wParam, lParam);
155 m_clipboardViewer = QWindowsContext::instance()->
156 createDummyWindow(QStringLiteral(
"ClipboardView"), L"QtClipboardView",
157 qClipboardViewerWndProc, WS_OVERLAPPED);
159 m_formatListenerRegistered = AddClipboardFormatListener(m_clipboardViewer);
160 if (!m_formatListenerRegistered)
161 qErrnoWarning(
"AddClipboardFormatListener() failed.");
163 if (!m_formatListenerRegistered)
164 m_nextClipboardViewer = SetClipboardViewer(m_clipboardViewer);
166 qCDebug(lcQpaMime) <<
__FUNCTION__ <<
"m_clipboardViewer:" << m_clipboardViewer
167 <<
"format listener:" << m_formatListenerRegistered
168 <<
"next:" << m_nextClipboardViewer;
173 if (m_clipboardViewer) {
174 if (m_formatListenerRegistered) {
175 RemoveClipboardFormatListener(m_clipboardViewer);
176 m_formatListenerRegistered =
false;
178 ChangeClipboardChain(m_clipboardViewer, m_nextClipboardViewer);
179 m_nextClipboardViewer =
nullptr;
181 DestroyWindow(m_clipboardViewer);
182 m_clipboardViewer =
nullptr;
192 if (!GetWindowThreadProcessId(hwnd, &pid) || !pid)
194 const HANDLE processHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
197 BOOL debugged = FALSE;
198 CheckRemoteDebuggerPresent(processHandle, &debugged);
199 CloseHandle(processHandle);
200 return debugged != FALSE;
203void QWindowsClipboard::propagateClipboardMessage(UINT message, WPARAM wParam, LPARAM lParam)
const
205 if (!m_nextClipboardViewer)
209 if (IsHungAppWindow(m_nextClipboardViewer)) {
210 qWarning(
"Cowardly refusing to send clipboard message to hung application...");
215 if (isProcessBeingDebugged(m_nextClipboardViewer))
216 PostMessage(m_nextClipboardViewer, message, wParam, lParam);
218 SendMessage(m_nextClipboardViewer, message, wParam, lParam);
222
223
224
228 enum { wMClipboardUpdate = 0x031D };
231 if (QWindowsContext::verbose)
232 qCDebug(lcQpaMime) <<
__FUNCTION__ << hwnd << message << QWindowsGuiEventDispatcher::windowsMessageName(message);
235 case WM_CHANGECBCHAIN: {
236 const HWND toBeRemoved =
reinterpret_cast<HWND>(wParam);
237 if (toBeRemoved == m_nextClipboardViewer) {
238 m_nextClipboardViewer =
reinterpret_cast<HWND>(lParam);
240 propagateClipboardMessage(message, wParam, lParam);
244 case wMClipboardUpdate:
245 case WM_DRAWCLIPBOARD: {
246 const bool owned = ownsClipboard();
247 qCDebug(lcQpaMime) <<
"Clipboard changed owned " << owned;
248 emitChanged(QClipboard::Clipboard);
250 if (!owned && m_data)
252 if (!m_formatListenerRegistered)
253 propagateClipboardMessage(message, wParam, lParam);
258 if (ownsClipboard()) {
259 qCDebug(lcQpaMime) <<
"Clipboard owner on shutdown, releasing.";
270 qCDebug(lcQpaMime) <<
__FUNCTION__ << mode;
271 if (mode != QClipboard::Clipboard)
275 return &m_retrievalData;
280 qCDebug(lcQpaMime) <<
__FUNCTION__ << mode << mimeData;
281 if (mode != QClipboard::Clipboard)
284 const bool newData = !m_data || m_data
->mimeData() != mimeData;
291 HRESULT src = S_FALSE;
293 for (; attempts < 3; ++attempts) {
294 src = OleSetClipboard(m_data);
295 if (src != CLIPBRD_E_CANT_OPEN || QWindowsContext::isSessionLocked())
297 QThread::msleep(100);
301 QString mimeDataFormats = mimeData ?
302 mimeData->formats().join(u", ") : QString(QStringLiteral(
"NULL"));
303 qErrnoWarning(
"OleSetClipboard: Failed to set mime data (%s) on clipboard: %s",
304 qPrintable(mimeDataFormats),
305 qPrintable(QSystemError::windowsComString(src)));
313 const HRESULT src = OleSetClipboard(
nullptr);
315 qErrnoWarning(
"OleSetClipboard: Failed to clear the clipboard: 0x%lx", src);
320 return mode == QClipboard::Clipboard;
326 return m_data && OleIsCurrentClipboard(m_data) == S_OK;
331 const bool result = mode == QClipboard::Clipboard ?
332 ownsClipboard() :
false;
333 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.
Singleton container for all relevant information.
QWindowsOleDataObject(QMimeData *mimeData)
QMimeData * mimeData() const
Combined button and popup list for selecting options.
static bool isProcessBeingDebugged(HWND hwnd)
static void cleanClipboardPostRoutine()