From f67b8df3ebdba2d398b9cce686b7c644adffff08 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Sat, 7 May 2011 00:02:01 +0200 Subject: library split --- src/widgets/platforms/win/qclipboard_win.cpp | 398 +++++++++++++++++++++++++++ 1 file changed, 398 insertions(+) create mode 100644 src/widgets/platforms/win/qclipboard_win.cpp (limited to 'src/widgets/platforms/win/qclipboard_win.cpp') diff --git a/src/widgets/platforms/win/qclipboard_win.cpp b/src/widgets/platforms/win/qclipboard_win.cpp new file mode 100644 index 0000000000..ea41165b9c --- /dev/null +++ b/src/widgets/platforms/win/qclipboard_win.cpp @@ -0,0 +1,398 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@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" +#include +#include + +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 + +typedef BOOL (WINAPI *PtrIsHungAppWindow)(HWND); + +static PtrIsHungAppWindow ptrIsHungAppWindow = 0; + +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")); + // We don't need this internal widget to appear in QApplication::topLevelWidgets() + if (QWidgetPrivate::allWidgets) + QWidgetPrivate::allWidgets->remove(clipBoardViewer); + } + + ~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::fromWCharArray((wchar_t *)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(obj); + + const QMimeData* data = qobj->mimeData(); + if (data->hasText()) { + EmptyClipboard(); + result = SetClipboardData(CF_UNICODETEXT, wcsdup(reinterpret_cast (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) { + if (ptrIsHungAppWindow == 0) { + QSystemLibrary library(QLatin1String("User32")); + ptrIsHungAppWindow = (PtrIsHungAppWindow)library.resolve("IsHungAppWindow"); + } + if (ptrIsHungAppWindow && ptrIsHungAppWindow(d->nextClipboardViewer)) { + qWarning("%s: Cowardly refusing to send clipboard message to hung application...", Q_FUNC_INFO); + } else { + SendMessage(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 -- cgit v1.2.3