diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2009-03-23 09:18:55 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-03-23 09:18:55 (GMT) |
commit | e5fcad302d86d316390c6b0f62759a067313e8a9 (patch) | |
tree | c2afbf6f1066b6ce261f14341cf6d310e5595bc1 /src/gui/kernel/qclipboard_win.cpp | |
download | Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.zip Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.gz Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.bz2 |
Long live Qt 4.5!
Diffstat (limited to 'src/gui/kernel/qclipboard_win.cpp')
-rw-r--r-- | src/gui/kernel/qclipboard_win.cpp | 389 |
1 files changed, 389 insertions, 0 deletions
diff --git a/src/gui/kernel/qclipboard_win.cpp b/src/gui/kernel/qclipboard_win.cpp new file mode 100644 index 0000000..90d4362 --- /dev/null +++ b/src/gui/kernel/qclipboard_win.cpp @@ -0,0 +1,389 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qclipboard.h" + +#ifndef QT_NO_CLIPBOARD + +#include "qapplication.h" +#include "qapplication_p.h" +#include "qeventloop.h" +#include "qwidget.h" +#include "qevent.h" +#include "qmime.h" +#include "qt_windows.h" +#include "qdnd_p.h" + +QT_BEGIN_NAMESPACE + +#if defined(Q_OS_WINCE) +QT_BEGIN_INCLUDE_NAMESPACE +#include "qguifunctions_wince.h" +QT_END_INCLUDE_NAMESPACE + +HRESULT QtCeGetClipboard(IDataObject** obj); +HRESULT QtCeSetClipboard(IDataObject* obj); +void QtCeFlushClipboard(); + +#define OleGetClipboard QtCeGetClipboard +#define OleSetClipboard QtCeSetClipboard +#define OleFlushClipboard QtCeFlushClipboard + +#endif + + +class QClipboardWatcher : public QInternalMimeData { +public: + QClipboardWatcher() + : QInternalMimeData() + { + } + + bool hasFormat_sys(const QString &mimetype) const; + QStringList formats_sys() const; + QVariant retrieveData_sys(const QString &mimetype, QVariant::Type preferredType) const; +}; + + +bool QClipboardWatcher::hasFormat_sys(const QString &mime) const +{ + IDataObject * pDataObj = 0; + + if (OleGetClipboard(&pDataObj) != S_OK && !pDataObj) // Sanity + return false; + + bool has = QWindowsMime::converterToMime(mime, pDataObj) != 0; + + pDataObj->Release(); + + return has; +} + +QStringList QClipboardWatcher::formats_sys() const +{ + QStringList fmts; + IDataObject * pDataObj = 0; + + if (OleGetClipboard(&pDataObj) != S_OK && !pDataObj) // Sanity + return QStringList(); + + fmts = QWindowsMime::allMimesForFormats(pDataObj); + + pDataObj->Release(); + + return fmts; +} + +QVariant QClipboardWatcher::retrieveData_sys(const QString &mimeType, QVariant::Type type) const +{ + QVariant result; + IDataObject * pDataObj = 0; + + if (OleGetClipboard(&pDataObj) != S_OK && !pDataObj) // Sanity + return result; + + QWindowsMime *converter = QWindowsMime::converterToMime(mimeType, pDataObj); + + if (converter) + result = converter->convertToMime(mimeType, pDataObj, type); + + pDataObj->Release(); + + return result; +} + +class QClipboardData +{ +public: + QClipboardData() + : iData(0) + , nextClipboardViewer(0) + { + clipBoardViewer = new QWidget(); + clipBoardViewer->createWinId(); + clipBoardViewer->setObjectName(QLatin1String("internal clipboard owner")); + } + + ~QClipboardData() + { + Q_ASSERT(clipBoardViewer->testAttribute(Qt::WA_WState_Created)); + ChangeClipboardChain(clipBoardViewer->internalWinId(), nextClipboardViewer); + delete clipBoardViewer; + releaseIData(); + } + + void releaseIData() + { + if (iData) { + delete iData->mimeData(); + iData->releaseQt(); + iData->Release(); + iData = 0; + } + } + + QOleDataObject * iData; + QWidget *clipBoardViewer; + HWND nextClipboardViewer; + QClipboardWatcher watcher; +}; + +static QClipboardData *ptrClipboardData = 0; + +static QClipboardData *clipboardData() +{ + if (ptrClipboardData == 0) { + ptrClipboardData = new QClipboardData; + // this needs to be done here to avoid recursion + Q_ASSERT(ptrClipboardData->clipBoardViewer->testAttribute(Qt::WA_WState_Created)); + ptrClipboardData->nextClipboardViewer = SetClipboardViewer(ptrClipboardData->clipBoardViewer->internalWinId()); + } + return ptrClipboardData; +} + +static void cleanupClipboardData() +{ + delete ptrClipboardData; + ptrClipboardData = 0; +} + +#if defined(Q_OS_WINCE) +HRESULT QtCeGetClipboard(IDataObject** obj) +{ + HWND owner = ptrClipboardData->clipBoardViewer->internalWinId(); + if (!OpenClipboard(owner)) + return !S_OK; + + if (!IsClipboardFormatAvailable(CF_TEXT) && !IsClipboardFormatAvailable(CF_UNICODETEXT)) + return !S_OK; + + HANDLE clipData = GetClipboardData(CF_TEXT); + QString clipText; + if (clipData == 0) { + clipData = GetClipboardData(CF_UNICODETEXT); + if (clipData != 0) + clipText = QString::fromUtf16((unsigned short *)clipData); + } else { + clipText = QString::fromLatin1((const char*)clipData); + } + + QMimeData *mimeData = new QMimeData(); + mimeData->setText(clipText); + QOleDataObject* data = new QOleDataObject(mimeData); + *obj = data; + CloseClipboard(); + return S_OK; +} + +HRESULT QtCeSetClipboard(IDataObject* obj) +{ + HWND owner = ptrClipboardData->clipBoardViewer->internalWinId(); + if (!OpenClipboard(owner)) + return !S_OK; + + bool result = false; + if (obj == 0) { + result = true; + EmptyClipboard(); + CloseClipboard(); + } else { + QOleDataObject* qobj = static_cast<QOleDataObject*>(obj); + + const QMimeData* data = qobj->mimeData(); + if (data->hasText()) { + EmptyClipboard(); + result = SetClipboardData(CF_UNICODETEXT, wcsdup(reinterpret_cast<const wchar_t *> (data->text().utf16()))) != NULL; + CloseClipboard(); + result = true; + } + } + return result ? S_OK : !S_OK; +} + +void QtCeFlushClipboard() { } +#endif + + + +QClipboard::~QClipboard() +{ + cleanupClipboardData(); +} + +void QClipboard::setMimeData(QMimeData *src, Mode mode) +{ + if (mode != Clipboard) + return; + QClipboardData *d = clipboardData(); + + if (!(d->iData && d->iData->mimeData() == src)) { + d->releaseIData(); + d->iData = new QOleDataObject(src); + } + + if (OleSetClipboard(d->iData) != S_OK) { + d->releaseIData(); + qErrnoWarning("QClipboard::setMimeData: Failed to set data on clipboard"); + return; + } +#if defined(Q_OS_WINCE) + // As WinCE does not support notifications we send the signal here + // We will get no event when the clipboard changes outside... + emit dataChanged(); + emit changed(Clipboard); +#endif +} + +void QClipboard::clear(Mode mode) +{ + if (mode != Clipboard) return; + + QClipboardData *d = clipboardData(); + + d->releaseIData(); + + if (OleSetClipboard(0) != S_OK) { + qErrnoWarning("QClipboard::clear: Failed to clear data on clipboard"); + return; + } +#if defined(Q_OS_WINCE) + // As WinCE does not support notifications we send the signal here + // We will get no event when the clipboard changes outside... + emit dataChanged(); + emit changed(Clipboard); +#endif +} + +bool QClipboard::event(QEvent *e) +{ + if (e->type() != QEvent::Clipboard) + return QObject::event(e); + + QClipboardData *d = clipboardData(); + + MSG *m = (MSG *)((QClipboardEvent*)e)->data(); + if (!m) { + // this is sent to render all formats at app shut down + if (ownsClipboard()) { + OleFlushClipboard(); + d->releaseIData(); + } + return true; + } + + bool propagate = false; + + if (m->message == WM_CHANGECBCHAIN) { + if ((HWND)m->wParam == d->nextClipboardViewer) + d->nextClipboardViewer = (HWND)m->lParam; + else + propagate = true; + } else if (m->message == WM_DRAWCLIPBOARD) { + emitChanged(QClipboard::Clipboard); + if (!ownsClipboard() && d->iData) + // clean up the clipboard object if we no longer own the clipboard + d->releaseIData(); + propagate = true; + } + + if (propagate && d->nextClipboardViewer) { + QT_WA({ + SendMessage(d->nextClipboardViewer, m->message, + m->wParam, m->lParam); + } , { + SendMessageA(d->nextClipboardViewer, m->message, + m->wParam, m->lParam); + }); + } + + return true; +} + +void QClipboard::connectNotify(const char *signal) +{ + if (qstrcmp(signal,SIGNAL(dataChanged())) == 0) { + // ensure we are up and running but block signals so the dataChange signal + // is not emitted while being connected to. + bool blocked = blockSignals(true); + QClipboardData *d = clipboardData(); + blockSignals(blocked); + Q_UNUSED(d); + } +} + +const QMimeData *QClipboard::mimeData(Mode mode) const +{ + if (mode != Clipboard) + return 0; + + QClipboardData *data = clipboardData(); + // sort cut for local copy / paste + if (ownsClipboard() && data->iData->mimeData()) + return data->iData->mimeData(); + return &data->watcher; +} + +bool QClipboard::supportsMode(Mode mode) const +{ + return (mode == Clipboard); +} + +bool QClipboard::ownsMode(Mode mode) const +{ + if (mode == Clipboard) { + QClipboardData *d = clipboardData(); +#if !defined(Q_OS_WINCE) + return d->iData && OleIsCurrentClipboard(d->iData) == S_OK; +#else + return d->iData && GetClipboardOwner() == d->clipBoardViewer->internalWinId(); +#endif + } else { + return false; + } +} + +void QClipboard::ownerDestroyed() +{ +} + +QT_END_NAMESPACE + +#endif // QT_NO_CLIPBOARD |