source: trunk/src/gui/kernel/qclipboard_win.cpp@ 786

Last change on this file since 786 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 10.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qclipboard.h"
43
44#ifndef QT_NO_CLIPBOARD
45
46#include "qapplication.h"
47#include "qapplication_p.h"
48#include "qeventloop.h"
49#include "qwidget.h"
50#include "qevent.h"
51#include "qmime.h"
52#include "qt_windows.h"
53#include "qdnd_p.h"
54#include <private/qwidget_p.h>
55
56QT_BEGIN_NAMESPACE
57
58#if defined(Q_OS_WINCE)
59QT_BEGIN_INCLUDE_NAMESPACE
60#include "qguifunctions_wince.h"
61QT_END_INCLUDE_NAMESPACE
62
63HRESULT QtCeGetClipboard(IDataObject** obj);
64HRESULT QtCeSetClipboard(IDataObject* obj);
65void QtCeFlushClipboard();
66
67#define OleGetClipboard QtCeGetClipboard
68#define OleSetClipboard QtCeSetClipboard
69#define OleFlushClipboard QtCeFlushClipboard
70
71#endif
72
73
74class QClipboardWatcher : public QInternalMimeData {
75public:
76 QClipboardWatcher()
77 : QInternalMimeData()
78 {
79 }
80
81 bool hasFormat_sys(const QString &mimetype) const;
82 QStringList formats_sys() const;
83 QVariant retrieveData_sys(const QString &mimetype, QVariant::Type preferredType) const;
84};
85
86
87bool QClipboardWatcher::hasFormat_sys(const QString &mime) const
88{
89 IDataObject * pDataObj = 0;
90
91 if (OleGetClipboard(&pDataObj) != S_OK && !pDataObj) // Sanity
92 return false;
93
94 bool has = QWindowsMime::converterToMime(mime, pDataObj) != 0;
95
96 pDataObj->Release();
97
98 return has;
99}
100
101QStringList QClipboardWatcher::formats_sys() const
102{
103 QStringList fmts;
104 IDataObject * pDataObj = 0;
105
106 if (OleGetClipboard(&pDataObj) != S_OK && !pDataObj) // Sanity
107 return QStringList();
108
109 fmts = QWindowsMime::allMimesForFormats(pDataObj);
110
111 pDataObj->Release();
112
113 return fmts;
114}
115
116QVariant QClipboardWatcher::retrieveData_sys(const QString &mimeType, QVariant::Type type) const
117{
118 QVariant result;
119 IDataObject * pDataObj = 0;
120
121 if (OleGetClipboard(&pDataObj) != S_OK && !pDataObj) // Sanity
122 return result;
123
124 QWindowsMime *converter = QWindowsMime::converterToMime(mimeType, pDataObj);
125
126 if (converter)
127 result = converter->convertToMime(mimeType, pDataObj, type);
128
129 pDataObj->Release();
130
131 return result;
132}
133
134class QClipboardData
135{
136public:
137 QClipboardData()
138 : iData(0)
139 , nextClipboardViewer(0)
140 {
141 clipBoardViewer = new QWidget();
142 clipBoardViewer->createWinId();
143 clipBoardViewer->setObjectName(QLatin1String("internal clipboard owner"));
144 // We dont need this internal widget to appear in QApplication::topLevelWidgets()
145 if (QWidgetPrivate::allWidgets)
146 QWidgetPrivate::allWidgets->remove(clipBoardViewer);
147 }
148
149 ~QClipboardData()
150 {
151 Q_ASSERT(clipBoardViewer->testAttribute(Qt::WA_WState_Created));
152 ChangeClipboardChain(clipBoardViewer->internalWinId(), nextClipboardViewer);
153 delete clipBoardViewer;
154 releaseIData();
155 }
156
157 void releaseIData()
158 {
159 if (iData) {
160 delete iData->mimeData();
161 iData->releaseQt();
162 iData->Release();
163 iData = 0;
164 }
165 }
166
167 QOleDataObject * iData;
168 QWidget *clipBoardViewer;
169 HWND nextClipboardViewer;
170 QClipboardWatcher watcher;
171};
172
173static QClipboardData *ptrClipboardData = 0;
174
175static QClipboardData *clipboardData()
176{
177 if (ptrClipboardData == 0) {
178 ptrClipboardData = new QClipboardData;
179 // this needs to be done here to avoid recursion
180 Q_ASSERT(ptrClipboardData->clipBoardViewer->testAttribute(Qt::WA_WState_Created));
181 ptrClipboardData->nextClipboardViewer = SetClipboardViewer(ptrClipboardData->clipBoardViewer->internalWinId());
182 }
183 return ptrClipboardData;
184}
185
186static void cleanupClipboardData()
187{
188 delete ptrClipboardData;
189 ptrClipboardData = 0;
190}
191
192#if defined(Q_OS_WINCE)
193HRESULT QtCeGetClipboard(IDataObject** obj)
194{
195 HWND owner = ptrClipboardData->clipBoardViewer->internalWinId();
196 if (!OpenClipboard(owner))
197 return !S_OK;
198
199 if (!IsClipboardFormatAvailable(CF_TEXT) && !IsClipboardFormatAvailable(CF_UNICODETEXT))
200 return !S_OK;
201
202 HANDLE clipData = GetClipboardData(CF_TEXT);
203 QString clipText;
204 if (clipData == 0) {
205 clipData = GetClipboardData(CF_UNICODETEXT);
206 if (clipData != 0)
207 clipText = QString::fromWCharArray((wchar_t *)clipData);
208 } else {
209 clipText = QString::fromLatin1((const char*)clipData);
210 }
211
212 QMimeData *mimeData = new QMimeData();
213 mimeData->setText(clipText);
214 QOleDataObject* data = new QOleDataObject(mimeData);
215 *obj = data;
216 CloseClipboard();
217 return S_OK;
218}
219
220HRESULT QtCeSetClipboard(IDataObject* obj)
221{
222 HWND owner = ptrClipboardData->clipBoardViewer->internalWinId();
223 if (!OpenClipboard(owner))
224 return !S_OK;
225
226 bool result = false;
227 if (obj == 0) {
228 result = true;
229 EmptyClipboard();
230 CloseClipboard();
231 } else {
232 QOleDataObject* qobj = static_cast<QOleDataObject*>(obj);
233
234 const QMimeData* data = qobj->mimeData();
235 if (data->hasText()) {
236 EmptyClipboard();
237 result = SetClipboardData(CF_UNICODETEXT, wcsdup(reinterpret_cast<const wchar_t *> (data->text().utf16()))) != NULL;
238 CloseClipboard();
239 result = true;
240 }
241 }
242 return result ? S_OK : !S_OK;
243}
244
245void QtCeFlushClipboard() { }
246#endif
247
248
249
250QClipboard::~QClipboard()
251{
252 cleanupClipboardData();
253}
254
255void QClipboard::setMimeData(QMimeData *src, Mode mode)
256{
257 if (mode != Clipboard) {
258 delete src;
259 return;
260 }
261
262 QClipboardData *d = clipboardData();
263
264 if (!(d->iData && d->iData->mimeData() == src)) {
265 d->releaseIData();
266 d->iData = new QOleDataObject(src);
267 }
268
269 if (OleSetClipboard(d->iData) != S_OK) {
270 d->releaseIData();
271 qErrnoWarning("QClipboard::setMimeData: Failed to set data on clipboard");
272 return;
273 }
274#if defined(Q_OS_WINCE)
275 // As WinCE does not support notifications we send the signal here
276 // We will get no event when the clipboard changes outside...
277 emit dataChanged();
278 emit changed(Clipboard);
279#endif
280}
281
282void QClipboard::clear(Mode mode)
283{
284 if (mode != Clipboard) return;
285
286 QClipboardData *d = clipboardData();
287
288 d->releaseIData();
289
290 if (OleSetClipboard(0) != S_OK) {
291 qErrnoWarning("QClipboard::clear: Failed to clear data on clipboard");
292 return;
293 }
294#if defined(Q_OS_WINCE)
295 // As WinCE does not support notifications we send the signal here
296 // We will get no event when the clipboard changes outside...
297 emit dataChanged();
298 emit changed(Clipboard);
299#endif
300}
301
302bool QClipboard::event(QEvent *e)
303{
304 if (e->type() != QEvent::Clipboard)
305 return QObject::event(e);
306
307 QClipboardData *d = clipboardData();
308
309 MSG *m = (MSG *)((QClipboardEvent*)e)->data();
310 if (!m) {
311 // this is sent to render all formats at app shut down
312 if (ownsClipboard()) {
313 OleFlushClipboard();
314 d->releaseIData();
315 }
316 return true;
317 }
318
319 bool propagate = false;
320
321 if (m->message == WM_CHANGECBCHAIN) {
322 if ((HWND)m->wParam == d->nextClipboardViewer)
323 d->nextClipboardViewer = (HWND)m->lParam;
324 else
325 propagate = true;
326 } else if (m->message == WM_DRAWCLIPBOARD) {
327 emitChanged(QClipboard::Clipboard);
328 if (!ownsClipboard() && d->iData)
329 // clean up the clipboard object if we no longer own the clipboard
330 d->releaseIData();
331 propagate = true;
332 }
333
334 if (propagate && d->nextClipboardViewer) {
335 SendMessage(d->nextClipboardViewer, m->message, m->wParam, m->lParam);
336 }
337
338 return true;
339}
340
341void QClipboard::connectNotify(const char *signal)
342{
343 if (qstrcmp(signal,SIGNAL(dataChanged())) == 0) {
344 // ensure we are up and running but block signals so the dataChange signal
345 // is not emitted while being connected to.
346 bool blocked = blockSignals(true);
347 QClipboardData *d = clipboardData();
348 blockSignals(blocked);
349 Q_UNUSED(d);
350 }
351}
352
353const QMimeData *QClipboard::mimeData(Mode mode) const
354{
355 if (mode != Clipboard)
356 return 0;
357
358 QClipboardData *data = clipboardData();
359 // sort cut for local copy / paste
360 if (ownsClipboard() && data->iData->mimeData())
361 return data->iData->mimeData();
362 return &data->watcher;
363}
364
365bool QClipboard::supportsMode(Mode mode) const
366{
367 return (mode == Clipboard);
368}
369
370bool QClipboard::ownsMode(Mode mode) const
371{
372 if (mode == Clipboard) {
373 QClipboardData *d = clipboardData();
374#if !defined(Q_OS_WINCE)
375 return d->iData && OleIsCurrentClipboard(d->iData) == S_OK;
376#else
377 return d->iData && GetClipboardOwner() == d->clipBoardViewer->internalWinId();
378#endif
379 } else {
380 return false;
381 }
382}
383
384void QClipboard::ownerDestroyed()
385{
386}
387
388QT_END_NAMESPACE
389
390#endif // QT_NO_CLIPBOARD
Note: See TracBrowser for help on using the repository browser.