summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/windows/qwindowsclipboard.cpp
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@nokia.com>2011-08-17 15:58:39 +0200
committerFriedemann Kleint <Friedemann.Kleint@nokia.com>2011-08-18 12:00:46 +0200
commit0b8d0804219b7e2e6179112d663b989d5b749d17 (patch)
tree4660a721ed39cc3e806c382f0f9287cedaa2d1a2 /src/plugins/platforms/windows/qwindowsclipboard.cpp
parent6136a792bc54c07dc4cf66481530b79b40110614 (diff)
Add Windows to the Lighthouse.
Add an initial Lighthouse plugin for the Windows operating system. Change-Id: I6934562266e1aa0ac270bf6107df05a9e56ef82c Reviewed-on: http://codereview.qt.nokia.com/3107 Reviewed-by: Oliver Wolff <oliver.wolff@nokia.com> Reviewed-by: Samuel Rødal <samuel.rodal@nokia.com>
Diffstat (limited to 'src/plugins/platforms/windows/qwindowsclipboard.cpp')
-rw-r--r--src/plugins/platforms/windows/qwindowsclipboard.cpp366
1 files changed, 366 insertions, 0 deletions
diff --git a/src/plugins/platforms/windows/qwindowsclipboard.cpp b/src/plugins/platforms/windows/qwindowsclipboard.cpp
new file mode 100644
index 0000000000..93063441ba
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsclipboard.cpp
@@ -0,0 +1,366 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwindowsclipboard.h"
+#include "qwindowscontext.h"
+#include "qwindowsole.h"
+#include "qwindowsmime.h"
+#include "qwindowsguieventdispatcher.h"
+
+#include <QtGui/QGuiApplication>
+#include <QtGui/QClipboard>
+#include <QtGui/QColor>
+#include <QtGui/QImage>
+
+#include <QtCore/QDebug>
+#include <QtCore/QMimeData>
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+#include <QtCore/QUrl>
+
+QT_BEGIN_NAMESPACE
+
+static const char formatTextPlainC[] = "text/plain";
+static const char formatTextHtmlC[] = "text/html";
+
+/*!
+ \class QWindowsClipboard
+ \brief Clipboard implementation.
+
+ Registers a non-visible clipboard viewer window that
+ receives clipboard events in its own window procedure to be
+ able to receive clipboard-changed events, which
+ QPlatformClipboard needs to emit. That requires housekeeping
+ of the next in the viewer chain.
+
+ \note The OLE-functions used in this class require OleInitialize().
+
+ \ingroup qt-lighthouse-win
+*/
+
+QDebug operator<<(QDebug d, const QMimeData &m)
+{
+ QDebug nospace = d.nospace();
+ const QStringList formats = m.formats();
+ nospace << "QMimeData: " << formats.join(QStringLiteral(", ")) << '\n'
+ << " Text=" << m.hasText() << " HTML=" << m.hasHtml()
+ << " Color=" << m.hasColor() << " Image=" << m.hasImage()
+ << " URLs=" << m.hasUrls() << '\n';
+ if (m.hasText())
+ nospace << " Text: '" << m.text() << "'\n";
+ if (m.hasHtml())
+ nospace << " HTML: '" << m.html() << "'\n";
+ if (m.hasColor())
+ nospace << " Color: " << qvariant_cast<QColor>(m.colorData()) << '\n';
+ if (m.hasImage())
+ nospace << " Image: " << qvariant_cast<QImage>(m.imageData()).size() << '\n';
+ if (m.hasUrls())
+ nospace << " URLs: " << m.urls() << '\n';
+ return d;
+}
+
+/*!
+ \class QWindowsInternalMimeDataBase
+ \brief Base for implementations of QInternalMimeData using a IDataObject COM object.
+
+ In clipboard handling and Drag and drop, static instances
+ of QInternalMimeData implementations are kept and passed to the client.
+
+ QInternalMimeData provides virtuals that query the formats and retrieve
+ mime data on demand when the client invokes functions like QMimeData::hasHtml(),
+ QMimeData::html() on the instance returned. Otherwise, expensive
+ construction of a new QMimeData object containing all possible
+ formats would have to be done in each call to mimeData().
+
+ The base class introduces new virtuals to obtain and release
+ the instances IDataObject from the clipboard or Drag and Drop and
+ does conversion using QWindowsMime classes.
+
+ \sa QInternalMimeData, QWindowsMime, QWindowsMimeConverter
+ \ingroup qt-lighthouse-win
+*/
+
+bool QWindowsInternalMimeData::hasFormat_sys(const QString &mime) const
+{
+ IDataObject *pDataObj = retrieveDataObject();
+ if (!pDataObj)
+ return false;
+
+ const QWindowsMimeConverter &mc = QWindowsContext::instance()->mimeConverter();
+ const bool has = mc.converterToMime(mime, pDataObj) != 0;
+ releaseDataObject(pDataObj);
+ if (QWindowsContext::verboseOLE)
+ qDebug() << __FUNCTION__ << mime << has;
+ return has;
+}
+
+QStringList QWindowsInternalMimeData::formats_sys() const
+{
+ IDataObject *pDataObj = retrieveDataObject();
+ if (!pDataObj)
+ return QStringList();
+
+ const QWindowsMimeConverter &mc = QWindowsContext::instance()->mimeConverter();
+ const QStringList fmts = mc.allMimesForFormats(pDataObj);
+ releaseDataObject(pDataObj);
+ if (QWindowsContext::verboseOLE)
+ qDebug() << __FUNCTION__ << fmts;
+ return fmts;
+}
+
+QVariant QWindowsInternalMimeData::retrieveData_sys(const QString &mimeType,
+ QVariant::Type type) const
+{
+ IDataObject *pDataObj = retrieveDataObject();
+ if (!pDataObj)
+ return QVariant();
+
+ QVariant result;
+ const QWindowsMimeConverter &mc = QWindowsContext::instance()->mimeConverter();
+ if (const QWindowsMime *converter = mc.converterToMime(mimeType, pDataObj))
+ result = converter->convertToMime(mimeType, pDataObj, type);
+ releaseDataObject(pDataObj);
+ if (QWindowsContext::verboseOLE) {
+ QDebug nospace = qDebug().nospace();
+ nospace << __FUNCTION__ << ' ' << mimeType << ' ' << type
+ << " returns " << result.type();
+ if (result.type() != QVariant::ByteArray)
+ nospace << ' ' << result;
+ }
+ return result;
+}
+
+/*!
+ \class QWindowsClipboardRetrievalMimeData
+ \brief Special mime data class managing delayed retrieval of clipboard data.
+
+ Implementation of QWindowsInternalMimeDataBase that obtains the
+ IDataObject from the clipboard.
+
+ \sa QWindowsInternalMimeDataBase, QWindowsClipboard
+ \ingroup qt-lighthouse-win
+*/
+
+IDataObject *QWindowsClipboardRetrievalMimeData::retrieveDataObject() const
+{
+ IDataObject * pDataObj = 0;
+ if (OleGetClipboard(&pDataObj) == S_OK)
+ return pDataObj;
+ return 0;
+}
+
+void QWindowsClipboardRetrievalMimeData::releaseDataObject(IDataObject *dataObject) const
+{
+ dataObject->Release();
+}
+
+extern "C" LRESULT QT_WIN_CALLBACK qClipboardViewerWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT result = 0;
+ if (QWindowsClipboard::instance()
+ && QWindowsClipboard::instance()->clipboardViewerWndProc(hwnd, message, wParam, lParam, &result))
+ return result;
+ return DefWindowProc(hwnd, message, wParam, lParam);
+}
+
+QWindowsClipboard *QWindowsClipboard::m_instance = 0;
+
+QWindowsClipboard::QWindowsClipboard() :
+ m_data(0), m_clipboardViewer(0), m_nextClipboardViewer(0)
+{
+ QWindowsClipboard::m_instance = this;
+}
+
+QWindowsClipboard::~QWindowsClipboard()
+{
+ unregisterViewer(); // Should release data if owner.
+ releaseIData();
+ QWindowsClipboard::m_instance = 0;
+}
+
+void QWindowsClipboard::releaseIData()
+{
+ if (m_data) {
+ delete m_data->mimeData();
+ m_data->releaseQt();
+ m_data->Release();
+ m_data = 0;
+ }
+}
+
+void QWindowsClipboard::registerViewer()
+{
+ m_clipboardViewer = QWindowsContext::instance()->
+ createDummyWindow(QStringLiteral("Qt5ClipboardView"), L"Qt5ClipboardView",
+ qClipboardViewerWndProc, WS_OVERLAPPED);
+ m_nextClipboardViewer = SetClipboardViewer(m_clipboardViewer);
+
+ if (QWindowsContext::verboseOLE)
+ qDebug("%s m_clipboardViewer: %p next=%p", __FUNCTION__,
+ m_clipboardViewer, m_nextClipboardViewer);
+}
+
+void QWindowsClipboard::unregisterViewer()
+{
+ if (m_clipboardViewer) {
+ ChangeClipboardChain(m_clipboardViewer, m_nextClipboardViewer);
+ DestroyWindow(m_clipboardViewer);
+ m_clipboardViewer = m_nextClipboardViewer = 0;
+ }
+}
+
+void QWindowsClipboard::propagateClipboardMessage(UINT message, WPARAM wParam, LPARAM lParam) const
+{
+ if (!m_nextClipboardViewer)
+ return;
+ // In rare cases, a clipboard viewer can hang (application crashed,
+ // suspended by a shell prompt 'Select' or debugger).
+ if (QWindowsContext::user32dll.isHungAppWindow
+ && QWindowsContext::user32dll.isHungAppWindow(m_nextClipboardViewer)) {
+ qWarning("%s: Cowardly refusing to send clipboard message to hung application...", Q_FUNC_INFO);
+ return;
+ }
+ SendMessage(m_nextClipboardViewer, message, wParam, lParam);
+}
+
+/*!
+ \brief Windows procedure of the clipboard viewer. Emits changed and does
+ housekeeping of the viewer chain.
+*/
+
+bool QWindowsClipboard::clipboardViewerWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result)
+{
+ *result = 0;
+ if (QWindowsContext::verboseOLE)
+ qDebug("%s HWND=%p 0x%x %s", __FUNCTION__, hwnd, message,
+ QWindowsGuiEventDispatcher::windowsMessageName(message));
+
+ switch (message) {
+ case WM_CHANGECBCHAIN: {
+ const HWND toBeRemoved = (HWND)wParam;
+ if (toBeRemoved == m_nextClipboardViewer) {
+ m_nextClipboardViewer = (HWND)lParam;
+ } else {
+ propagateClipboardMessage(message, wParam, lParam);
+ }
+ }
+ return true;
+ case WM_DRAWCLIPBOARD:
+ if (QWindowsContext::verboseOLE)
+ qDebug("Clipboard changed");
+ emitChanged(QClipboard::Clipboard);
+ // clean up the clipboard object if we no longer own the clipboard
+ if (!ownsClipboard() && m_data)
+ releaseIData();
+ propagateClipboardMessage(message, wParam, lParam);
+ return true;
+ case WM_DESTROY:
+ // Recommended shutdown
+ if (ownsClipboard()) {
+ if (QWindowsContext::verboseOLE)
+ qDebug("Clipboard owner on shutdown, releasing.");
+ OleFlushClipboard();
+ releaseIData();
+ }
+ return true;
+ } // switch (message)
+ return false;
+}
+
+QMimeData *QWindowsClipboard::mimeData(QClipboard::Mode mode)
+{
+ if (QWindowsContext::verboseOLE)
+ qDebug() << __FUNCTION__ << mode;
+ if (mode != QClipboard::Clipboard)
+ return 0;
+ return &m_retrievalData;
+}
+
+void QWindowsClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode)
+{
+ if (QWindowsContext::verboseOLE)
+ qDebug() << __FUNCTION__ << mode << *mimeData;
+ if (mode != QClipboard::Clipboard)
+ return;
+
+ const bool newData = !m_data || m_data->mimeData() != mimeData;
+ if (newData) {
+ releaseIData();
+ m_data = new QWindowsOleDataObject(mimeData);
+ }
+
+ const HRESULT src = OleSetClipboard(m_data);
+ if (src != S_OK) {
+ qErrnoWarning("OleSetClipboard: Failed to set data on clipboard: %s",
+ QWindowsContext::comErrorString(src).constData());
+ releaseIData();
+ return;
+ }
+}
+
+void QWindowsClipboard::clear()
+{
+ const HRESULT src = OleSetClipboard(0);
+ if (src != S_OK)
+ qErrnoWarning("OleSetClipboard: Failed to clear the clipboard: 0x%lx", src);
+}
+
+bool QWindowsClipboard::supportsMode(QClipboard::Mode mode) const
+{
+ return mode == QClipboard::Clipboard;
+}
+
+// Need a non-virtual in destructor.
+bool QWindowsClipboard::ownsClipboard() const
+{
+ return m_data && OleIsCurrentClipboard(m_data) == S_OK;
+}
+
+bool QWindowsClipboard::ownsMode(QClipboard::Mode mode) const
+{
+ const bool result = mode == QClipboard::Clipboard ?
+ ownsClipboard() : false;
+ if (QWindowsContext::verboseOLE)
+ qDebug("%s %d returns %d", __FUNCTION__, mode, result);
+ return result;
+}
+
+QT_END_NAMESPACE