src/gui/kernel/qclipboard_win.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gui/kernel/qclipboard_win.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,383 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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"
+
+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::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<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) {
+        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