summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/windows
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
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')
-rw-r--r--src/plugins/platforms/windows/array.h103
-rw-r--r--src/plugins/platforms/windows/main.cpp112
-rw-r--r--src/plugins/platforms/windows/pixmaputils.cpp316
-rw-r--r--src/plugins/platforms/windows/pixmaputils.h71
-rw-r--r--src/plugins/platforms/windows/qtwindows_additional.h118
-rw-r--r--src/plugins/platforms/windows/qtwindowsglobal.h159
-rw-r--r--src/plugins/platforms/windows/qwindows.qdocconf27
-rw-r--r--src/plugins/platforms/windows/qwindowsbackingstore.cpp143
-rw-r--r--src/plugins/platforms/windows/qwindowsbackingstore.h77
-rw-r--r--src/plugins/platforms/windows/qwindowsclipboard.cpp366
-rw-r--r--src/plugins/platforms/windows/qwindowsclipboard.h94
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp734
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.h171
-rw-r--r--src/plugins/platforms/windows/qwindowscursor.cpp451
-rw-r--r--src/plugins/platforms/windows/qwindowscursor.h93
-rw-r--r--src/plugins/platforms/windows/qwindowsdrag.cpp721
-rw-r--r--src/plugins/platforms/windows/qwindowsdrag.h116
-rw-r--r--src/plugins/platforms/windows/qwindowsfontdatabase.cpp950
-rw-r--r--src/plugins/platforms/windows/qwindowsfontdatabase.h107
-rw-r--r--src/plugins/platforms/windows/qwindowsfontengine.cpp1223
-rw-r--r--src/plugins/platforms/windows/qwindowsfontengine.h186
-rw-r--r--src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp737
-rw-r--r--src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h133
-rw-r--r--src/plugins/platforms/windows/qwindowsglcontext.cpp974
-rw-r--r--src/plugins/platforms/windows/qwindowsglcontext.h165
-rw-r--r--src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp209
-rw-r--r--src/plugins/platforms/windows/qwindowsguieventdispatcher.h71
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.cpp275
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.h81
-rw-r--r--src/plugins/platforms/windows/qwindowsinternalmimedata.h70
-rw-r--r--src/plugins/platforms/windows/qwindowskeymapper.cpp1076
-rw-r--r--src/plugins/platforms/windows/qwindowskeymapper.h114
-rw-r--r--src/plugins/platforms/windows/qwindowsmime.cpp1557
-rw-r--r--src/plugins/platforms/windows/qwindowsmime.h102
-rw-r--r--src/plugins/platforms/windows/qwindowsmousehandler.cpp288
-rw-r--r--src/plugins/platforms/windows/qwindowsmousehandler.h98
-rw-r--r--src/plugins/platforms/windows/qwindowsnativeimage.cpp152
-rw-r--r--src/plugins/platforms/windows/qwindowsnativeimage.h82
-rw-r--r--src/plugins/platforms/windows/qwindowsole.cpp476
-rw-r--r--src/plugins/platforms/windows/qwindowsole.h127
-rw-r--r--src/plugins/platforms/windows/qwindowsprintersupport.cpp134
-rw-r--r--src/plugins/platforms/windows/qwindowsprintersupport.h62
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.cpp230
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.h100
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp1317
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.h284
-rw-r--r--src/plugins/platforms/windows/windows.pro70
47 files changed, 15322 insertions, 0 deletions
diff --git a/src/plugins/platforms/windows/array.h b/src/plugins/platforms/windows/array.h
new file mode 100644
index 0000000000..216f1e8945
--- /dev/null
+++ b/src/plugins/platforms/windows/array.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef ARRAY_H
+#define ARRAY_H
+
+#include <QtCore/QtAlgorithms>
+
+QT_BEGIN_NAMESPACE
+
+/* A simple, non-shared array. */
+
+template <class T>
+class Array
+{
+ Q_DISABLE_COPY(Array)
+public:
+ enum { initialSize = 5 };
+
+ typedef T* const_iterator;
+
+ explicit Array(size_t size= 0) : data(0), m_capacity(0), m_size(0)
+ { if (size) resize(size); }
+ ~Array() { delete [] data; }
+
+ T *data;
+ inline size_t size() const { return m_size; }
+ inline const_iterator begin() const { return data; }
+ inline const_iterator end() const { return data + m_size; }
+
+ inline void append(const T &value)
+ {
+ const size_t oldSize = m_size;
+ resize(m_size + 1);
+ data[oldSize] = value;
+ }
+
+ inline void resize(size_t size)
+ {
+ if (size > m_size)
+ reserve(size > 1 ? size + size / 2 : size_t(initialSize));
+ m_size = size;
+ }
+
+ void reserve(size_t capacity)
+ {
+ if (capacity > m_capacity) {
+ const T *oldData = data;
+ data = new T[capacity];
+ if (oldData) {
+ qCopy(oldData, oldData + m_size, data);
+ delete [] oldData;
+ }
+ m_capacity = capacity;
+ }
+ }
+
+private:
+ size_t m_capacity;
+ size_t m_size;
+};
+
+QT_END_NAMESPACE
+
+#endif // ARRAY_H
diff --git a/src/plugins/platforms/windows/main.cpp b/src/plugins/platforms/windows/main.cpp
new file mode 100644
index 0000000000..933aa76df8
--- /dev/null
+++ b/src/plugins/platforms/windows/main.cpp
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** 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 <QtGui/QPlatformIntegrationPlugin>
+#include <QtCore/QStringList>
+
+#include "qwindowsintegration.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \group qt-lighthouse-win
+ \title Qt Lighthouse plugin for Windows
+
+ \brief Class documentation of the Qt Lighthouse plugin for Windows.
+
+ \section1 Tips
+
+ \list
+ \o The environment variable \c QT_LIGHTHOUSE_WINDOWS_VERBOSE controls
+ the debug level. It takes the form
+ \c{<keyword1>:<level1>,<keyword2>:<level2>}, where
+ keyword is one of \c integration, \c windows, \c backingstore and
+ \c fonts. Level is an integer 0..9.
+ \endlist
+ */
+
+/*!
+ \class QWindowsIntegrationPlugin
+ \brief Plugin.
+ \ingroup qt-lighthouse-win
+ */
+
+/*!
+ \namespace QtWindows
+
+ \brief Namespace for enumerations, etc.
+ \ingroup qt-lighthouse-win
+*/
+
+/*!
+ \enum QtWindows::WindowsEventType
+
+ \brief Enumerations for WM_XX events.
+
+ With flags that should help to structure the code.
+
+ \ingroup qt-lighthouse-win
+*/
+
+class QWindowsIntegrationPlugin : public QPlatformIntegrationPlugin
+{
+public:
+ QStringList keys() const;
+ QPlatformIntegration *create(const QString&, const QStringList&);
+};
+
+QStringList QWindowsIntegrationPlugin::keys() const
+{
+ return QStringList(QStringLiteral("windows"));
+}
+
+QPlatformIntegration *QWindowsIntegrationPlugin::create(const QString& system, const QStringList& paramList)
+{
+ Q_UNUSED(paramList);
+ if (system.compare(system, QStringLiteral("windows"), Qt::CaseInsensitive) == 0)
+ return new QWindowsIntegration;
+ return 0;
+}
+
+Q_EXPORT_PLUGIN2(windows, QWindowsIntegrationPlugin)
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/pixmaputils.cpp b/src/plugins/platforms/windows/pixmaputils.cpp
new file mode 100644
index 0000000000..111df5a4b9
--- /dev/null
+++ b/src/plugins/platforms/windows/pixmaputils.cpp
@@ -0,0 +1,316 @@
+/****************************************************************************
+**
+** 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 "pixmaputils.h"
+
+#include <QtGui/QBitmap>
+#include <QtGui/QImage>
+#include <QtGui/QPlatformPixmap>
+#include <QtGui/private/qpixmap_raster_p.h>
+
+#include <QtCore/QScopedArrayPointer>
+#include <QtCore/QDebug>
+
+#include <string.h>
+
+QT_BEGIN_NAMESPACE
+
+HBITMAP createIconMask(const QBitmap &bitmap)
+{
+ QImage bm = bitmap.toImage().convertToFormat(QImage::Format_Mono);
+ const int w = bm.width();
+ const int h = bm.height();
+ const int bpl = ((w+15)/16)*2; // bpl, 16 bit alignment
+ QScopedArrayPointer<uchar> bits(new uchar[bpl * h]);
+ bm.invertPixels();
+ for (int y = 0; y < h; ++y)
+ memcpy(bits.data() + y * bpl, bm.scanLine(y), bpl);
+ HBITMAP hbm = CreateBitmap(w, h, 1, 1, bits.data());
+ return hbm;
+}
+
+HBITMAP qPixmapToWinHBITMAP(const QPixmap &p, HBitmapFormat format)
+{
+ if (p.isNull())
+ return 0;
+
+ HBITMAP bitmap = 0;
+ if (p.handle()->classId() != QPlatformPixmap::RasterClass) {
+ QRasterPlatformPixmap *data = new QRasterPlatformPixmap(p.depth() == 1 ?
+ QRasterPlatformPixmap::BitmapType : QRasterPlatformPixmap::PixmapType);
+ data->fromImage(p.toImage(), Qt::AutoColor);
+ return qPixmapToWinHBITMAP(QPixmap(data), format);
+ }
+
+ QRasterPlatformPixmap *d = static_cast<QRasterPlatformPixmap*>(p.handle());
+ const QImage *rasterImage = d->buffer();
+ const int w = rasterImage->width();
+ const int h = rasterImage->height();
+
+ HDC display_dc = GetDC(0);
+
+ // Define the header
+ BITMAPINFO bmi;
+ memset(&bmi, 0, sizeof(bmi));
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = w;
+ bmi.bmiHeader.biHeight = -h;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ bmi.bmiHeader.biSizeImage = w * h * 4;
+
+ // Create the pixmap
+ uchar *pixels = 0;
+ bitmap = CreateDIBSection(display_dc, &bmi, DIB_RGB_COLORS, (void **) &pixels, 0, 0);
+ ReleaseDC(0, display_dc);
+ if (!bitmap) {
+ qErrnoWarning("%s, failed to create dibsection", __FUNCTION__);
+ return 0;
+ }
+ if (!pixels) {
+ qErrnoWarning("%s, did not allocate pixel data", __FUNCTION__);
+ return 0;
+ }
+
+ // Copy over the data
+ QImage::Format imageFormat = QImage::Format_ARGB32;
+ if (format == HBitmapAlpha)
+ imageFormat = QImage::Format_RGB32;
+ else if (format == HBitmapPremultipliedAlpha)
+ imageFormat = QImage::Format_ARGB32_Premultiplied;
+ const QImage image = rasterImage->convertToFormat(imageFormat);
+ const int bytes_per_line = w * 4;
+ for (int y=0; y < h; ++y)
+ memcpy(pixels + y * bytes_per_line, image.scanLine(y), bytes_per_line);
+
+ return bitmap;
+}
+
+QPixmap qPixmapFromWinHBITMAP(HBITMAP bitmap, HBitmapFormat format)
+{
+ // Verify size
+ BITMAP bitmap_info;
+ memset(&bitmap_info, 0, sizeof(BITMAP));
+
+ const int res = GetObject(bitmap, sizeof(BITMAP), &bitmap_info);
+ if (!res) {
+ qErrnoWarning("QPixmap::fromWinHBITMAP(), failed to get bitmap info");
+ return QPixmap();
+ }
+ const int w = bitmap_info.bmWidth;
+ const int h = bitmap_info.bmHeight;
+
+ BITMAPINFO bmi;
+ memset(&bmi, 0, sizeof(bmi));
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = w;
+ bmi.bmiHeader.biHeight = -h;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ bmi.bmiHeader.biSizeImage = w * h * 4;
+
+ // Get bitmap bits
+ QScopedArrayPointer<uchar> data(new uchar[bmi.bmiHeader.biSizeImage]);
+ HDC display_dc = GetDC(0);
+ if (!GetDIBits(display_dc, bitmap, 0, h, data.data(), &bmi, DIB_RGB_COLORS)) {
+ ReleaseDC(0, display_dc);
+ qWarning("%s, failed to get bitmap bits", __FUNCTION__);
+ return QPixmap();
+ }
+
+ QImage::Format imageFormat = QImage::Format_ARGB32_Premultiplied;
+ uint mask = 0;
+ if (format == HBitmapNoAlpha) {
+ imageFormat = QImage::Format_RGB32;
+ mask = 0xff000000;
+ }
+
+ // Create image and copy data into image.
+ QImage image(w, h, imageFormat);
+ if (image.isNull()) { // failed to alloc?
+ ReleaseDC(0, display_dc);
+ qWarning("%s, failed create image of %dx%d", __FUNCTION__, w, h);
+ return QPixmap();
+ }
+ const int bytes_per_line = w * sizeof(QRgb);
+ for (int y = 0; y < h; ++y) {
+ QRgb *dest = (QRgb *) image.scanLine(y);
+ const QRgb *src = (const QRgb *) (data.data() + y * bytes_per_line);
+ for (int x = 0; x < w; ++x) {
+ const uint pixel = src[x];
+ if ((pixel & 0xff000000) == 0 && (pixel & 0x00ffffff) != 0)
+ dest[x] = pixel | 0xff000000;
+ else
+ dest[x] = pixel | mask;
+ }
+ }
+ ReleaseDC(0, display_dc);
+ return QPixmap::fromImage(image);
+}
+
+HICON qPixmapToWinHICON(const QPixmap &p)
+{
+ QBitmap maskBitmap = p.mask();
+ if (maskBitmap.isNull()) {
+ maskBitmap = QBitmap(p.size());
+ maskBitmap.fill(Qt::color1);
+ }
+
+ ICONINFO ii;
+ ii.fIcon = true;
+ ii.hbmMask = createIconMask(maskBitmap);
+ ii.hbmColor = qPixmapToWinHBITMAP(p, HBitmapAlpha);
+ ii.xHotspot = 0;
+ ii.yHotspot = 0;
+
+ HICON hIcon = CreateIconIndirect(&ii);
+
+ DeleteObject(ii.hbmColor);
+ DeleteObject(ii.hbmMask);
+
+ return hIcon;
+}
+
+static QImage qImageFromWinHBITMAP(HDC hdc, HBITMAP bitmap, int w, int h)
+{
+ BITMAPINFO bmi;
+ memset(&bmi, 0, sizeof(bmi));
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = w;
+ bmi.bmiHeader.biHeight = -h;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ bmi.bmiHeader.biSizeImage = w * h * 4;
+
+ QImage image(w, h, QImage::Format_ARGB32_Premultiplied);
+ if (image.isNull())
+ return image;
+
+ // Get bitmap bits
+ QScopedPointer<uchar> data(new uchar [bmi.bmiHeader.biSizeImage]);
+ if (!GetDIBits(hdc, bitmap, 0, h, data.data(), &bmi, DIB_RGB_COLORS)) {
+ qErrnoWarning("%s: failed to get bitmap bits", __FUNCTION__);
+ return QImage();
+ }
+ // Create image and copy data into image.
+ for (int y = 0; y < h; ++y) {
+ void *dest = (void *) image.scanLine(y);
+ void *src = data.data() + y * image.bytesPerLine();
+ memcpy(dest, src, image.bytesPerLine());
+ }
+ return image;
+}
+
+QPixmap qPixmapFromWinHICON(HICON icon)
+{
+ bool foundAlpha = false;
+ HDC screenDevice = GetDC(0);
+ HDC hdc = CreateCompatibleDC(screenDevice);
+ ReleaseDC(0, screenDevice);
+
+ ICONINFO iconinfo;
+ const bool result = GetIconInfo(icon, &iconinfo); //x and y Hotspot describes the icon center
+ if (!result) {
+ qErrnoWarning("QPixmap::fromWinHICON(), failed to GetIconInfo()");
+ return QPixmap();
+ }
+
+ const int w = iconinfo.xHotspot * 2;
+ const int h = iconinfo.yHotspot * 2;
+
+ BITMAPINFOHEADER bitmapInfo;
+ bitmapInfo.biSize = sizeof(BITMAPINFOHEADER);
+ bitmapInfo.biWidth = w;
+ bitmapInfo.biHeight = h;
+ bitmapInfo.biPlanes = 1;
+ bitmapInfo.biBitCount = 32;
+ bitmapInfo.biCompression = BI_RGB;
+ bitmapInfo.biSizeImage = 0;
+ bitmapInfo.biXPelsPerMeter = 0;
+ bitmapInfo.biYPelsPerMeter = 0;
+ bitmapInfo.biClrUsed = 0;
+ bitmapInfo.biClrImportant = 0;
+ DWORD* bits;
+
+ HBITMAP winBitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bitmapInfo, DIB_RGB_COLORS, (VOID**)&bits, NULL, 0);
+ HGDIOBJ oldhdc = (HBITMAP)SelectObject(hdc, winBitmap);
+ DrawIconEx( hdc, 0, 0, icon, iconinfo.xHotspot * 2, iconinfo.yHotspot * 2, 0, 0, DI_NORMAL);
+ QImage image = qImageFromWinHBITMAP(hdc, winBitmap, w, h);
+
+ for (int y = 0 ; y < h && !foundAlpha ; y++) {
+ const QRgb *scanLine= reinterpret_cast<const QRgb *>(image.scanLine(y));
+ for (int x = 0; x < w ; x++) {
+ if (qAlpha(scanLine[x]) != 0) {
+ foundAlpha = true;
+ break;
+ }
+ }
+ }
+ if (!foundAlpha) {
+ //If no alpha was found, we use the mask to set alpha values
+ DrawIconEx( hdc, 0, 0, icon, w, h, 0, 0, DI_MASK);
+ const QImage mask = qImageFromWinHBITMAP(hdc, winBitmap, w, h);
+
+ for (int y = 0 ; y < h ; y++){
+ QRgb *scanlineImage = reinterpret_cast<QRgb *>(image.scanLine(y));
+ const QRgb *scanlineMask = mask.isNull() ? 0 : reinterpret_cast<const QRgb *>(mask.scanLine(y));
+ for (int x = 0; x < w ; x++){
+ if (scanlineMask && qRed(scanlineMask[x]) != 0)
+ scanlineImage[x] = 0; //mask out this pixel
+ else
+ scanlineImage[x] |= 0xff000000; // set the alpha channel to 255
+ }
+ }
+ }
+ //dispose resources created by iconinfo call
+ DeleteObject(iconinfo.hbmMask);
+ DeleteObject(iconinfo.hbmColor);
+
+ SelectObject(hdc, oldhdc); //restore state
+ DeleteObject(winBitmap);
+ DeleteDC(hdc);
+ return QPixmap::fromImage(image);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/pixmaputils.h b/src/plugins/platforms/windows/pixmaputils.h
new file mode 100644
index 0000000000..bf94a2695c
--- /dev/null
+++ b/src/plugins/platforms/windows/pixmaputils.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef PIXMAPUTILS_H
+#define PIXMAPUTILS_H
+
+#include "qtwindows_additional.h"
+
+#include <QtCore/QtGlobal>
+
+QT_BEGIN_NAMESPACE
+
+class QBitmap;
+class QPixmap;
+
+enum HBitmapFormat
+{
+ HBitmapNoAlpha,
+ HBitmapPremultipliedAlpha,
+ HBitmapAlpha
+};
+
+HBITMAP createIconMask(const QBitmap &bitmap);
+
+HBITMAP qPixmapToWinHBITMAP(const QPixmap &p, HBitmapFormat format);
+HICON qPixmapToWinHICON(const QPixmap &p);
+
+QPixmap qPixmapFromWinHBITMAP(HBITMAP bitmap, HBitmapFormat format);
+QPixmap qPixmapFromWinHICON(HICON icon);
+
+QT_END_NAMESPACE
+
+#endif // PIXMAPUTILS_H
diff --git a/src/plugins/platforms/windows/qtwindows_additional.h b/src/plugins/platforms/windows/qtwindows_additional.h
new file mode 100644
index 0000000000..707d28559a
--- /dev/null
+++ b/src/plugins/platforms/windows/qtwindows_additional.h
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QTWINDOWS_ADDITIONAL_H
+#define QTWINDOWS_ADDITIONAL_H
+
+#include <QtCore/QtGlobal> // get compiler define
+#include <QtCore/qt_windows.h>
+
+/* Complement the definitions and declarations missing
+ * when using MinGW or older Windows SDKs. */
+
+#if defined(Q_CC_MINGW)
+# if !defined(ULW_ALPHA)
+# define ULW_ALPHA 0x00000002
+# define LWA_ALPHA 0x00000002
+# endif // !defined(ULW_ALPHA)
+# define SPI_GETFONTSMOOTHINGTYPE 0x200A
+# define FE_FONTSMOOTHINGCLEARTYPE 0x0002
+# define CLEARTYPE_QUALITY 5
+
+# define CF_DIBV5 17
+
+#define CO_E_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x80004021L)
+
+typedef struct tagUPDATELAYEREDWINDOWINFO {
+ DWORD cbSize;
+ HDC hdcDst;
+ const POINT *pptDst;
+ const SIZE *psize;
+ HDC hdcSrc;
+ const POINT *pptSrc;
+ COLORREF crKey;
+ const BLENDFUNCTION *pblend;
+ DWORD dwFlags;
+ const RECT *prcDirty;
+} UPDATELAYEREDWINDOWINFO, *PUPDATELAYEREDWINDOWINFO;
+
+// OpenGL Pixelformat flags.
+#define PFD_SUPPORT_DIRECTDRAW 0x00002000
+#define PFD_DIRECT3D_ACCELERATED 0x00004000
+#define PFD_SUPPORT_COMPOSITION 0x00008000
+
+#endif // if defined(Q_CC_MINGW)
+
+/* Touch is supported from Windows 7 onwards and data structures
+ * are present in the Windows SDK's, but not in older MSVC Express
+ * versions. */
+
+#if defined(Q_CC_MINGW) || !defined(TOUCHEVENTF_MOVE)
+
+#define WM_TOUCH 0x0240
+
+typedef struct tagTOUCHINPUT {
+ LONG x;
+ LONG y;
+ HANDLE hSource;
+ DWORD dwID;
+ DWORD dwFlags;
+ DWORD dwMask;
+ DWORD dwTime;
+ ULONG_PTR dwExtraInfo;
+ DWORD cxContact;
+ DWORD cyContact;
+} TOUCHINPUT, *PTOUCHINPUT;
+typedef TOUCHINPUT const * PCTOUCHINPUT;
+
+# define TOUCHEVENTF_MOVE 0x0001
+# define TOUCHEVENTF_DOWN 0x0002
+# define TOUCHEVENTF_UP 0x0004
+# define TOUCHEVENTF_INRANGE 0x0008
+# define TOUCHEVENTF_PRIMARY 0x0010
+# define TOUCHEVENTF_NOCOALESCE 0x0020
+# define TOUCHEVENTF_PALM 0x0080
+# define TOUCHINPUTMASKF_CONTACTAREA 0x0004
+# define TOUCHINPUTMASKF_EXTRAINFO 0x0002
+
+#endif // if defined(Q_CC_MINGW) || !defined(TOUCHEVENTF_MOVE)
+
+#endif // QTWINDOWS_ADDITIONAL_H
diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h
new file mode 100644
index 0000000000..792792a136
--- /dev/null
+++ b/src/plugins/platforms/windows/qtwindowsglobal.h
@@ -0,0 +1,159 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QTWINDOWSGLOBAL_H
+#define QTWINDOWSGLOBAL_H
+
+#include "qtwindows_additional.h"
+#include <QtCore/qnamespace.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWindows
+{
+
+enum
+{
+ WindowEventFlag = 0x10000,
+ MouseEventFlag = 0x20000,
+ NonClientEventFlag = 0x40000,
+ InputMethodEventFlag = 0x80000,
+ KeyEventFlag = 0x100000,
+ KeyDownEventFlag = 0x200000,
+ TouchEventFlag = 0x400000,
+ ClipboardEventFlag = 0x800000,
+ ApplicationEventFlag = 0x1000000
+};
+
+enum WindowsEventType // Simplify event types
+{
+ ExposeEvent = WindowEventFlag + 1,
+ ActivateWindowEvent = WindowEventFlag + 2,
+ DeactivateWindowEvent = WindowEventFlag + 3,
+ LeaveEvent = WindowEventFlag + 5,
+ CloseEvent = WindowEventFlag + 6,
+ ShowEvent = WindowEventFlag + 7,
+ HideEvent = WindowEventFlag + 8,
+ DestroyEvent = WindowEventFlag + 9,
+ MoveEvent = WindowEventFlag + 10,
+ ResizeEvent = WindowEventFlag + 12,
+ QuerySizeHints = WindowEventFlag + 15,
+ CalculateSize = WindowEventFlag + 16,
+ MouseEvent = MouseEventFlag + 1,
+ MouseWheelEvent = MouseEventFlag + 2,
+ TouchEvent = TouchEventFlag + 1,
+ NonClientMouseEvent = NonClientEventFlag + MouseEventFlag + 1,
+ KeyEvent = KeyEventFlag + 1,
+ KeyDownEvent = KeyEventFlag + KeyDownEventFlag + 1,
+ InputMethodKeyEvent = InputMethodEventFlag + KeyEventFlag + 1,
+ InputMethodKeyDownEvent = InputMethodEventFlag + KeyEventFlag + KeyDownEventFlag + 1,
+ ClipboardEvent = ClipboardEventFlag + 1,
+ ActivateApplicationEvent = ApplicationEventFlag + 1,
+ DeactivateApplicationEvent = ApplicationEventFlag + 2,
+ UnknownEvent = 542
+};
+
+} // namespace QtWindows
+
+inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamIn)
+{
+ switch (message) {
+ case WM_PAINT:
+ case WM_ERASEBKGND:
+ return QtWindows::ExposeEvent;
+ case WM_CLOSE:
+ return QtWindows::CloseEvent;
+ case WM_DESTROY:
+ return QtWindows::DestroyEvent;
+ case WM_ACTIVATEAPP:
+ return (int)wParamIn ?
+ QtWindows::ActivateApplicationEvent : QtWindows::DeactivateApplicationEvent;
+ case WM_ACTIVATE:
+ return LOWORD(wParamIn) == WA_INACTIVE ?
+ QtWindows::DeactivateWindowEvent : QtWindows::ActivateWindowEvent;
+ case WM_MOUSELEAVE:
+ return QtWindows::MouseEvent;
+ case WM_MOUSEWHEEL:
+ case WM_MOUSEHWHEEL:
+ return QtWindows::MouseWheelEvent;
+ case WM_MOVE:
+ return QtWindows::MoveEvent;
+ case WM_SHOWWINDOW:
+ return wParamIn ? QtWindows::ShowEvent : QtWindows::HideEvent;
+ case WM_SIZE:
+ return QtWindows::ResizeEvent;
+ case WM_NCCALCSIZE:
+ return QtWindows::CalculateSize;
+ case WM_GETMINMAXINFO:
+ return QtWindows::QuerySizeHints;
+ case WM_KEYDOWN: // keyboard event
+ case WM_SYSKEYDOWN:
+ return QtWindows::KeyDownEvent;
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ case WM_CHAR:
+ return QtWindows::KeyEvent;
+ case WM_IME_CHAR:
+ return QtWindows::InputMethodKeyEvent;
+ case WM_IME_KEYDOWN:
+ return QtWindows::InputMethodKeyDownEvent;
+ case WM_TOUCH:
+ return QtWindows::TouchEvent;
+ case WM_CHANGECBCHAIN:
+ case WM_DRAWCLIPBOARD:
+ case WM_RENDERFORMAT:
+ case WM_RENDERALLFORMATS:
+ case WM_DESTROYCLIPBOARD:
+ return QtWindows::ClipboardEvent;
+ default:
+ break;
+ }
+ if (message >= WM_NCMOUSEMOVE && message <= WM_NCMBUTTONDBLCLK)
+ return QtWindows::NonClientMouseEvent; //
+ if ((message >= WM_MOUSEFIRST && message <= WM_MOUSELAST)
+ || (message >= WM_XBUTTONDOWN && message <= WM_XBUTTONDBLCLK))
+ return QtWindows::MouseEvent;
+ return QtWindows::UnknownEvent;
+}
+
+QT_END_NAMESPACE
+
+#endif // QTWINDOWSGLOBAL_H
diff --git a/src/plugins/platforms/windows/qwindows.qdocconf b/src/plugins/platforms/windows/qwindows.qdocconf
new file mode 100644
index 0000000000..c5a1ee904a
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindows.qdocconf
@@ -0,0 +1,27 @@
+project = "Qt Windows Lighthouse Plugin"
+description = "Documentation of the Qt Windows Lighthouse Plugin"
+
+language = Cpp
+
+headerdirs = .
+
+sourcedirs = .
+
+showinternal = true
+
+headers.fileextensions = "*.h"
+sources.fileextensions = "*.cpp *.qdoc"
+
+outputdir = doc
+
+qhp.projects = QtLighthouseWindows
+qhp.QtLighthouseWindowsDev.file = qtlighthousewindows-dev.qhp
+qhp.QtLighthouseWindowsDev.namespace = com.nokia.qt.developer.lighthouse
+qhp.QtLighthouseWindowsDev.virtualFolder = doc
+qhp.QtLighthouseWindowsDev.indexTitle = Qt Windows Lighthouse Plugin
+qhp.QtLighthouseWindowsDev.indexRoot =
+
+# Doxygen compatibility commands
+
+macro.see = "\\sa"
+macro.function = "\\fn"
diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.cpp b/src/plugins/platforms/windows/qwindowsbackingstore.cpp
new file mode 100644
index 0000000000..a3698c4a7c
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsbackingstore.cpp
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** 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 "qwindowsbackingstore.h"
+#include "qwindowswindow.h"
+#include "qwindowsnativeimage.h"
+#include "qwindowscontext.h"
+
+#include <QtGui/QWindow>
+
+#include <QtCore/QDebug>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QWindowsBackingStore
+ \brief Backing store for windows.
+ \ingroup qt-lighthouse-win
+*/
+
+QWindowsBackingStore::QWindowsBackingStore(QWindow *window) :
+ QPlatformBackingStore(window)
+{
+ if (QWindowsContext::verboseBackingStore)
+ qDebug() << __FUNCTION__ << this << window;
+}
+
+QWindowsBackingStore::~QWindowsBackingStore()
+{
+ if (QWindowsContext::verboseBackingStore)
+ qDebug() << __FUNCTION__ << this;
+}
+
+QPaintDevice *QWindowsBackingStore::paintDevice()
+{
+ Q_ASSERT(!m_image.isNull());
+ return &m_image->image();
+}
+
+void QWindowsBackingStore::flush(QWindow *window, const QRegion &region,
+ const QPoint &offset)
+{
+ // TODO: Prepare paint for translucent windows.
+ const QRect br = region.boundingRect();
+ if (QWindowsContext::verboseBackingStore > 1)
+ qDebug() << __FUNCTION__ << window << offset << br;
+ QWindowsWindow *rw = rasterWindow();
+ const HDC dc = rw->getDC();
+ if (!dc) {
+ qErrnoWarning("%s: GetDC failed", __FUNCTION__);
+ return;
+ }
+
+ if (!BitBlt(dc, br.x(), br.y(), br.width(), br.height(),
+ m_image->hdc(), br.x() + offset.x(), br.y() + offset.y(), SRCCOPY))
+ qErrnoWarning("%s: BitBlt failed", __FUNCTION__);
+ rw->releaseDC();
+ // Write image for debug purposes.
+ if (QWindowsContext::verboseBackingStore > 2) {
+ static int n = 0;
+ const QString fileName = QString::fromAscii("win%1_%2.png").
+ arg(rw->winId()).arg(n++);
+ m_image->image().save(fileName);
+ qDebug() << "Wrote " << m_image->image().size() << fileName;
+ }
+}
+
+void QWindowsBackingStore::resize(const QSize &size, const QRegion &region)
+{
+ if (m_image.isNull() || m_image->image().size() != size) {
+ if (QWindowsContext::verboseBackingStore) {
+ QDebug nsp = qDebug().nospace();
+ nsp << __FUNCTION__ << ' ' << rasterWindow()->window()
+ << ' ' << size << ' ' << region;
+ if (!m_image.isNull())
+ nsp << " from: " << m_image->image().size();
+ }
+ m_image.reset(new QWindowsNativeImage(size.width(), size.height(),
+ QWindowsNativeImage::systemFormat()));
+ }
+}
+
+void QWindowsBackingStore::beginPaint(const QRegion &region)
+{
+ Q_UNUSED(region);
+ if (QWindowsContext::verboseBackingStore > 1)
+ qDebug() << __FUNCTION__;
+}
+
+QWindowsWindow *QWindowsBackingStore::rasterWindow() const
+{
+ if (const QWindow *w = window())
+ if (QPlatformWindow *pw = w->handle())
+ return static_cast<QWindowsWindow *>(pw);
+ return 0;
+}
+
+HDC QWindowsBackingStore::getDC() const
+{
+ if (!m_image.isNull())
+ return m_image->hdc();
+ return 0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.h b/src/plugins/platforms/windows/qwindowsbackingstore.h
new file mode 100644
index 0000000000..53f033d14b
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsbackingstore.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSBACKINGSTORE_H
+#define QWINDOWSBACKINGSTORE_H
+
+#include "qtwindows_additional.h"
+
+#include <QtGui/QPlatformBackingStore>
+#include <QtCore/QScopedPointer>
+
+QT_BEGIN_NAMESPACE
+
+class QWindowsWindow;
+class QWindowsNativeImage;
+
+class QWindowsBackingStore : public QPlatformBackingStore
+{
+ Q_DISABLE_COPY(QWindowsBackingStore)
+public:
+ QWindowsBackingStore(QWindow *window);
+ ~QWindowsBackingStore();
+
+ virtual QPaintDevice *paintDevice();
+ virtual void flush(QWindow *window, const QRegion &region, const QPoint &offset);
+ virtual void resize(const QSize &size, const QRegion &r);
+ virtual void beginPaint(const QRegion &);
+
+ HDC getDC() const;
+
+private:
+ QWindowsWindow *rasterWindow() const;
+
+ QScopedPointer<QWindowsNativeImage> m_image;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSBACKINGSTORE_H
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
diff --git a/src/plugins/platforms/windows/qwindowsclipboard.h b/src/plugins/platforms/windows/qwindowsclipboard.h
new file mode 100644
index 0000000000..fab6871012
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsclipboard.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSCLIPBOARD_H
+#define QWINDOWSCLIPBOARD_H
+
+#include "qwindowsinternalmimedata.h"
+
+#include <QtGui/QPlatformClipboard>
+
+QT_BEGIN_NAMESPACE
+
+class QWindowsOleDataObject;
+
+class QWindowsClipboardRetrievalMimeData : public QWindowsInternalMimeData {
+public:
+
+protected:
+ virtual IDataObject *retrieveDataObject() const;
+ virtual void releaseDataObject(IDataObject *) const;
+};
+
+class QWindowsClipboard : public QPlatformClipboard
+{
+public:
+ QWindowsClipboard();
+ ~QWindowsClipboard();
+ void registerViewer(); // Call in initialization, when context is up.
+
+ virtual QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard);
+ virtual void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard);
+ virtual bool supportsMode(QClipboard::Mode mode) const;
+ virtual bool ownsMode(QClipboard::Mode mode) const;
+
+ inline bool clipboardViewerWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result);
+
+ static QWindowsClipboard *instance() { return m_instance; }
+
+private:
+ void clear();
+ void releaseIData();
+ inline void propagateClipboardMessage(UINT message, WPARAM wParam, LPARAM lParam) const;
+ inline void unregisterViewer();
+ inline bool ownsClipboard() const;
+
+ static QWindowsClipboard *m_instance;
+
+ QWindowsClipboardRetrievalMimeData m_retrievalData;
+ QWindowsOleDataObject *m_data;
+ HWND m_clipboardViewer;
+ HWND m_nextClipboardViewer;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSCLIPBOARD_H
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
new file mode 100644
index 0000000000..d62cbfb4c6
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -0,0 +1,734 @@
+/****************************************************************************
+**
+** 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 "qwindowscontext.h"
+#include "qwindowswindow.h"
+#include "qwindowskeymapper.h"
+#include "qwindowsguieventdispatcher.h"
+#include "qwindowsmousehandler.h"
+#include "qtwindowsglobal.h"
+#include "qwindowsmime.h"
+
+#include <QtGui/QWindow>
+#include <QtGui/QWindowSystemInterface>
+
+#include <QtCore/QSet>
+#include <QtCore/QHash>
+#include <QtCore/QStringList>
+#include <QtCore/QDebug>
+#include <QtCore/QSysInfo>
+#include <QtCore/QScopedArrayPointer>
+#include <QtCore/private/qsystemlibrary_p.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <windowsx.h>
+
+QT_BEGIN_NAMESPACE
+
+// Verbosity of components
+int QWindowsContext::verboseIntegration = 0;
+int QWindowsContext::verboseWindows = 0;
+int QWindowsContext::verboseEvents = 0;
+int QWindowsContext::verboseBackingStore = 0;
+int QWindowsContext::verboseFonts = 0;
+int QWindowsContext::verboseGL = 0;
+int QWindowsContext::verboseOLE = 0;
+
+// Get verbosity of components from "foo:2,bar:3"
+static inline int componentVerbose(const char *v, const char *keyWord)
+{
+ if (const char *k = strstr(v, keyWord)) {
+ k += qstrlen(keyWord);
+ if (*k == ':') {
+ ++k;
+ if (isdigit(*k))
+ return *k - '0';
+ }
+ }
+ return 0;
+}
+
+static inline bool hasTouchSupport(QSysInfo::WinVersion wv)
+{
+ enum { QT_SM_DIGITIZER = 94, QT_NID_INTEGRATED_TOUCH = 0x1,
+ QT_NID_EXTERNAL_TOUCH = 0x02, QT_NID_MULTI_INPUT = 0x40 };
+
+ return wv < QSysInfo::WV_WINDOWS7 ? false :
+ (GetSystemMetrics(QT_SM_DIGITIZER) & (QT_NID_INTEGRATED_TOUCH | QT_NID_EXTERNAL_TOUCH | QT_NID_MULTI_INPUT)) != 0;
+}
+
+#if !defined(LANG_SYRIAC)
+# define LANG_SYRIAC 0x5a
+#endif
+
+static inline bool useRTL_Extensions(QSysInfo::WinVersion ver)
+{
+ if ((ver & QSysInfo::WV_NT_based) && (ver >= QSysInfo::WV_VISTA)) {
+ // Since the IsValidLanguageGroup/IsValidLocale functions always return true on
+ // Vista, check the Keyboard Layouts for enabling RTL.
+ if (const UINT nLayouts = GetKeyboardLayoutList(0, 0)) {
+ QScopedArrayPointer<HKL> lpList(new HKL[nLayouts]);
+ GetKeyboardLayoutList(nLayouts, lpList.data());
+ for (UINT i = 0; i < nLayouts; ++i) {
+ switch (PRIMARYLANGID((quintptr)lpList[i])) {
+ case LANG_ARABIC:
+ case LANG_HEBREW:
+ case LANG_FARSI:
+ case LANG_SYRIAC:
+ return true;
+ default:
+ break;
+ }
+ }
+ }
+ return false;
+ } // NT/Vista
+ // Pre-NT: figure out whether a RTL language is installed
+ return IsValidLanguageGroup(LGRPID_ARABIC, LGRPID_INSTALLED)
+ || IsValidLanguageGroup(LGRPID_HEBREW, LGRPID_INSTALLED)
+ || IsValidLocale(MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), SORT_DEFAULT), LCID_INSTALLED)
+ || IsValidLocale(MAKELCID(MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT), SORT_DEFAULT), LCID_INSTALLED)
+ || IsValidLocale(MAKELCID(MAKELANGID(LANG_SYRIAC, SUBLANG_DEFAULT), SORT_DEFAULT), LCID_INSTALLED)
+ || IsValidLocale(MAKELCID(MAKELANGID(LANG_FARSI, SUBLANG_DEFAULT), SORT_DEFAULT), LCID_INSTALLED);
+}
+
+/*!
+ \class QWindowsUser32DLL
+ \brief Struct that contains dynamically resolved symbols of User32.dll.
+
+ The stub libraries shipped with the MinGW compiler miss some of the
+ functions. They need to be retrieved dynamically.
+
+ In addition, touch-related functions are available only from Windows onwards.
+ These need to resolved dynamically for Q_CC_MSVC as well.
+
+ \ingroup qt-lighthouse-win
+*/
+
+QWindowsUser32DLL::QWindowsUser32DLL() :
+ setLayeredWindowAttributes(0), updateLayeredWindow(0),
+ updateLayeredWindowIndirect(0),
+ isHungAppWindow(0),
+ registerTouchWindow(0), getTouchInputInfo(0), closeTouchInputHandle(0)
+{
+}
+
+void QWindowsUser32DLL::init()
+{
+ QSystemLibrary library(QStringLiteral("user32"));
+ // MinGW (g++ 3.4.5) accepts only C casts.
+ setLayeredWindowAttributes = (SetLayeredWindowAttributes)(library.resolve("SetLayeredWindowAttributes"));
+ updateLayeredWindow = (UpdateLayeredWindow)(library.resolve("UpdateLayeredWindow"));
+ updateLayeredWindowIndirect = (UpdateLayeredWindowIndirect)(library.resolve("UpdateLayeredWindowIndirect"));
+
+ Q_ASSERT(setLayeredWindowAttributes && updateLayeredWindow
+ && updateLayeredWindowIndirect);
+
+ isHungAppWindow = (IsHungAppWindow)library.resolve("IsHungAppWindow");
+}
+
+bool QWindowsUser32DLL::initTouch()
+{
+ QSystemLibrary library(QStringLiteral("user32"));
+ registerTouchWindow = (RegisterTouchWindow)(library.resolve("RegisterTouchWindow"));
+ getTouchInputInfo = (GetTouchInputInfo)(library.resolve("GetTouchInputInfo"));
+ closeTouchInputHandle = (CloseTouchInputHandle)(library.resolve("CloseTouchInputHandle"));
+ return registerTouchWindow && getTouchInputInfo && getTouchInputInfo;
+}
+
+QWindowsUser32DLL QWindowsContext::user32dll;
+
+QWindowsContext *QWindowsContext::m_instance = 0;
+
+/*!
+ \class QWindowsContext
+ \brief Singleton container for all relevant information.
+
+ Holds state information formerly stored in \c qapplication_win.cpp.
+ \ingroup qt-lighthouse-win
+*/
+
+typedef QHash<HWND, QWindowsWindow *> HandleBaseWindowHash;
+
+struct QWindowsContextPrivate {
+ explicit QWindowsContextPrivate(bool isOpenGL);
+
+ const bool m_isOpenGL;
+ unsigned m_systemInfo;
+ QSet<QString> m_registeredWindowClassNames;
+ HandleBaseWindowHash m_windows;
+ HDC m_displayContext;
+ const int m_defaultDPI;
+ QWindowsKeyMapper m_keyMapper;
+ QWindowsMouseHandler m_mouseHandler;
+ QWindowsMimeConverter m_mimeConverter;
+ QSharedPointer<QWindowCreationContext> m_creationContext;
+ const HRESULT m_oleInitializeResult;
+};
+
+QWindowsContextPrivate::QWindowsContextPrivate(bool isOpenGL) :
+ m_isOpenGL(isOpenGL),
+ m_systemInfo(0),
+ m_displayContext(GetDC(0)),
+ m_defaultDPI(GetDeviceCaps(m_displayContext,LOGPIXELSY)),
+ m_oleInitializeResult(OleInitialize(NULL))
+{
+ QWindowsContext::user32dll.init();
+
+ const QSysInfo::WinVersion ver = QSysInfo::windowsVersion();
+
+ if (hasTouchSupport(ver) && QWindowsContext::user32dll.initTouch())
+ m_systemInfo |= QWindowsContext::SI_SupportsTouch;
+
+ if (useRTL_Extensions(ver)) {
+ m_systemInfo |= QWindowsContext::SI_RTL_Extensions;
+ m_keyMapper.setUseRTLExtensions(true);
+ }
+}
+
+QWindowsContext::QWindowsContext(bool isOpenGL) :
+ d(new QWindowsContextPrivate(isOpenGL))
+{
+#ifdef Q_CC_MSVC
+# pragma warning( disable : 4996 )
+#endif
+ m_instance = this;
+ if (const char *v = getenv("QT_LIGHTHOUSE_WINDOWS_VERBOSE")) {
+ QWindowsContext::verboseIntegration = componentVerbose(v, "integration");
+ QWindowsContext::verboseWindows = componentVerbose(v, "windows");
+ QWindowsContext::verboseEvents = componentVerbose(v, "events");
+ QWindowsContext::verboseBackingStore = componentVerbose(v, "backingstore");
+ QWindowsContext::verboseFonts = componentVerbose(v, "fonts");
+ QWindowsContext::verboseGL = componentVerbose(v, "gl");
+ QWindowsContext::verboseOLE = componentVerbose(v, "ole");
+ }
+}
+
+QWindowsContext::~QWindowsContext()
+{
+ unregisterWindowClasses();
+ if (d->m_oleInitializeResult == S_OK || d->m_oleInitializeResult == S_FALSE)
+ OleUninitialize();
+
+ m_instance = 0;
+}
+
+QWindowsContext *QWindowsContext::instance()
+{
+ return m_instance;
+}
+
+unsigned QWindowsContext::systemInfo() const
+{
+ return d->m_systemInfo;
+}
+
+void QWindowsContext::setWindowCreationContext(const QSharedPointer<QWindowCreationContext> &ctx)
+{
+ d->m_creationContext = ctx;
+}
+
+bool QWindowsContext::isOpenGL() const
+{
+ return d->m_isOpenGL;
+}
+
+int QWindowsContext::defaultDPI() const
+{
+ return d->m_defaultDPI;
+}
+
+HDC QWindowsContext::displayContext() const
+{
+ return d->m_displayContext;
+}
+
+QWindow *QWindowsContext::keyGrabber() const
+{
+ return d->m_keyMapper.keyGrabber();
+}
+
+void QWindowsContext::setKeyGrabber(QWindow *w)
+{
+ d->m_keyMapper.setKeyGrabber(w);
+}
+
+// Window class registering code (from qapplication_win.cpp)
+// If 0 is passed as the widget pointer, register a window class
+// for QWidget as default. This is used in QGLTemporaryContext
+// during GL initialization, where we don't want to use temporary
+// QWidgets or QGLWidgets, neither do we want to have separate code
+// to register window classes.
+
+QString QWindowsContext::registerWindowClass(const QWindow *w, bool isGL)
+{
+ const Qt::WindowFlags flags = w ? w->windowFlags() : (Qt::WindowFlags)0;
+ const Qt::WindowFlags type = flags & Qt::WindowType_Mask;
+
+ uint style = 0;
+ bool icon = false;
+ QString cname = "Qt5";
+ if (w && isGL) {
+ cname += QStringLiteral("QGLWindow");
+ style = CS_DBLCLKS|CS_OWNDC;
+ icon = true;
+ } else if (w && (flags & Qt::MSWindowsOwnDC)) {
+ cname += QStringLiteral("QWindowOwnDC");
+ style = CS_DBLCLKS|CS_OWNDC;
+ icon = true;
+ } else if (w && (type == Qt::Tool || type == Qt::ToolTip)) {
+ style = CS_DBLCLKS;
+ if (w->inherits("QTipLabel") || w->inherits("QAlphaWidget")) {
+ if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP
+ && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)) {
+ style |= CS_DROPSHADOW;
+ }
+ cname += QStringLiteral("QToolTip");
+ } else {
+ cname += QStringLiteral("QTool");
+ }
+ style |= CS_SAVEBITS;
+ icon = false;
+ } else if (w && (type == Qt::Popup)) {
+ cname += QStringLiteral("QPopup");
+ style = CS_DBLCLKS|CS_SAVEBITS;
+ if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP
+ && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based))
+ style |= CS_DROPSHADOW;
+ icon = false;
+ } else {
+ cname += QStringLiteral("QWindow");
+ style = CS_DBLCLKS;
+ icon = true;
+ }
+
+ // force CS_OWNDC when the GL graphics system is
+ // used as the default renderer
+ if (d->m_isOpenGL)
+ style |= CS_OWNDC;
+
+ HBRUSH brush = 0;
+ if (w && !isGL)
+ brush = GetSysColorBrush(COLOR_WINDOW);
+ return registerWindowClass(cname, qWindowsWndProc, style, brush, icon);
+}
+
+QString QWindowsContext::registerWindowClass(QString cname,
+ WNDPROC proc,
+ unsigned style,
+ HBRUSH brush,
+ bool icon)
+{
+ // since multiple Qt versions can be used in one process
+ // each one has to have window class names with a unique name
+ // The first instance gets the unmodified name; if the class
+ // has already been registered by another instance of Qt then
+ // add an instance-specific ID, the address of the window proc.
+ static int classExists = -1;
+
+ const HINSTANCE appInstance = (HINSTANCE)GetModuleHandle(0);
+ if (classExists == -1) {
+ WNDCLASS wcinfo;
+ classExists = GetClassInfo(appInstance, (wchar_t*)cname.utf16(), &wcinfo);
+ classExists = classExists && wcinfo.lpfnWndProc != proc;
+ }
+
+ if (classExists)
+ cname += QString::number((quintptr)proc);
+
+ if (d->m_registeredWindowClassNames.contains(cname)) // already registered in our list
+ return cname;
+
+ WNDCLASSEX wc;
+ wc.cbSize = sizeof(WNDCLASSEX);
+ wc.style = style;
+ wc.lpfnWndProc = proc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = appInstance;
+ if (icon) {
+ wc.hIcon = (HICON)LoadImage(appInstance, L"IDI_ICON1", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);
+ if (wc.hIcon) {
+ int sw = GetSystemMetrics(SM_CXSMICON);
+ int sh = GetSystemMetrics(SM_CYSMICON);
+ wc.hIconSm = (HICON)LoadImage(appInstance, L"IDI_ICON1", IMAGE_ICON, sw, sh, 0);
+ } else {
+ wc.hIcon = (HICON)LoadImage(0, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
+ wc.hIconSm = 0;
+ }
+ } else {
+ wc.hIcon = 0;
+ wc.hIconSm = 0;
+ }
+ wc.hCursor = 0;
+ wc.hbrBackground = brush;
+ wc.lpszMenuName = 0;
+ wc.lpszClassName = (wchar_t*)cname.utf16();
+ ATOM atom = RegisterClassEx(&wc);
+
+ if (!atom)
+ qErrnoWarning("QApplication::regClass: Registering window class '%s' failed.",
+ qPrintable(cname));
+
+ d->m_registeredWindowClassNames.insert(cname);
+ if (QWindowsContext::verboseIntegration || QWindowsContext::verboseWindows)
+ qDebug().nospace() << __FUNCTION__ << ' ' << cname
+ << " style=0x" << QString::number(style, 16)
+ << " brush=" << brush << " icon=" << icon << " atom=" << atom;
+ return cname;
+}
+
+void QWindowsContext::unregisterWindowClasses()
+{
+ const HINSTANCE appInstance = (HINSTANCE)GetModuleHandle(0);
+
+ foreach (const QString &name, d->m_registeredWindowClassNames) {
+ if (QWindowsContext::verboseIntegration)
+ qDebug() << __FUNCTION__ << name;
+ UnregisterClass((wchar_t*)name.utf16(), appInstance);
+ }
+ d->m_registeredWindowClassNames.clear();
+}
+
+int QWindowsContext::screenDepth() const
+{
+ return GetDeviceCaps(d->m_displayContext, BITSPIXEL);
+}
+
+QString QWindowsContext::windowsErrorMessage(unsigned long errorCode)
+{
+ QString rc = QString::fromLatin1("#%1: ").arg(errorCode);
+ ushort *lpMsgBuf;
+
+ const int len = FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, errorCode, 0, (LPTSTR)&lpMsgBuf, 0, NULL);
+ if (len) {
+ rc = QString::fromUtf16(lpMsgBuf, len);
+ LocalFree(lpMsgBuf);
+ } else {
+ rc += QString::fromLatin1("<unknown error>");
+ }
+ return rc;
+}
+
+void QWindowsContext::addWindow(HWND hwnd, QWindowsWindow *w)
+{
+ d->m_windows.insert(hwnd, w);
+}
+
+void QWindowsContext::removeWindow(HWND hwnd)
+{
+ const HandleBaseWindowHash::iterator it = d->m_windows.find(hwnd);
+ if (it != d->m_windows.end()) {
+ if (d->m_keyMapper.keyGrabber() == it.value()->window())
+ d->m_keyMapper.setKeyGrabber(0);
+ d->m_windows.erase(it);
+ }
+}
+
+QWindowsWindow *QWindowsContext::findPlatformWindow(HWND hwnd) const
+{
+ return d->m_windows.value(hwnd);
+}
+
+QWindow *QWindowsContext::findWindow(HWND hwnd) const
+{
+ if (const QWindowsWindow *bw = findPlatformWindow(hwnd))
+ return bw->window();
+ return 0;
+}
+
+QWindow *QWindowsContext::windowUnderMouse() const
+{
+ return d->m_mouseHandler.windowUnderMouse();
+}
+
+/*!
+ \brief Find a child window at a screen point.
+
+ Deep search for a QWindow at global point, skipping non-owned
+ windows (accessibility?). Implemented using ChildWindowFromPointEx()
+ instead of (historically used) WindowFromPoint() to get a well-defined
+ behaviour for hidden/transparent windows.
+
+ \a cwex_flags are flags of ChildWindowFromPointEx().
+ \a parent is the parent window, pass GetDesktopWindow() for top levels.
+*/
+
+QWindowsWindow *QWindowsContext::findPlatformWindowAt(HWND parent,
+ const QPoint &screenPointIn,
+ unsigned cwex_flags) const
+{
+ QWindowsWindow *result = 0;
+ const POINT screenPoint = { screenPointIn.x(), screenPointIn.y() };
+ while (true) {
+ POINT point = screenPoint;
+ ScreenToClient(parent, &point);
+ // Returns parent if inside & none matched.
+ const HWND child = ChildWindowFromPointEx(parent, point, cwex_flags);
+ if (child && child != parent) {
+ if (QWindowsWindow *window = findPlatformWindow(child))
+ result = window;
+ parent = child;
+ } else {
+ break;
+ }
+ }
+ return result;
+}
+
+QWindowsMimeConverter &QWindowsContext::mimeConverter() const
+{
+ return d->m_mimeConverter;
+}
+
+/*!
+ \brief Convenience to create a non-visible dummy window
+ for example used as clipboard watcher or for GL.
+*/
+
+HWND QWindowsContext::createDummyWindow(const QString &classNameIn,
+ const wchar_t *windowName,
+ WNDPROC wndProc, DWORD style)
+{
+ if (!wndProc)
+ wndProc = DefWindowProc;
+ QString className = registerWindowClass(classNameIn, wndProc);
+ return CreateWindowEx(0, (wchar_t*)className.utf16(),
+ windowName, style,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ 0, NULL, (HINSTANCE)GetModuleHandle(0), NULL);
+}
+
+/*!
+ \brief Common COM error strings.
+*/
+
+QByteArray QWindowsContext::comErrorString(HRESULT hr)
+{
+ switch (hr) {
+ case S_OK:
+ return QByteArray("S_OK");
+ case S_FALSE:
+ return QByteArray("S_FALSE");
+ case E_UNEXPECTED:
+ return QByteArray("E_UNEXPECTED");
+ case CO_E_ALREADYINITIALIZED:
+ return QByteArray("CO_E_ALREADYINITIALIZED");
+ case CO_E_NOTINITIALIZED:
+ return QByteArray("CO_E_NOTINITIALIZED");
+ case RPC_E_CHANGED_MODE:
+ return QByteArray("RPC_E_CHANGED_MODE");
+ case OLE_E_WRONGCOMPOBJ:
+ return QByteArray("OLE_E_WRONGCOMPOBJ");
+ case CO_E_NOT_SUPPORTED:
+ return QByteArray("CO_E_NOT_SUPPORTED");
+ case E_NOTIMPL:
+ return QByteArray("E_NOTIMPL");
+ case E_INVALIDARG:
+ return QByteArray("");
+ case E_NOINTERFACE:
+ return QByteArray("");
+ case E_POINTER:
+ return QByteArray("");
+ case E_HANDLE:
+ return QByteArray("");
+ case E_ABORT:
+ return QByteArray("");
+ case E_FAIL:
+ return QByteArray("");
+ case E_ACCESSDENIED:
+ return QByteArray("");
+ default:
+ break;
+ }
+ return "Unknown error 0x" + QByteArray::number(quint64(hr), 16);
+}
+
+/*!
+ \brief Main windows procedure registered for windows.
+
+ \sa QWindowsGuiEventDispatcher
+*/
+
+bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
+ QtWindows::WindowsEventType et,
+ WPARAM wParam, LPARAM lParam, LRESULT *result)
+{
+ *result = 0;
+ // Events without an associated QWindow or events we are not interested in.
+ switch (et) {
+ case QtWindows::DeactivateApplicationEvent:
+ case QtWindows::DeactivateWindowEvent:
+ QWindowSystemInterface::handleWindowActivated(0);
+ return true;
+ case QtWindows::ClipboardEvent:
+ case QtWindows::DestroyEvent:
+ case QtWindows::UnknownEvent:
+ return false;
+ default:
+ break;
+ }
+
+ QWindowsWindow *platformWindow = findPlatformWindow(hwnd);
+ // Before CreateWindowEx() returns, some events are sent,
+ // for example WM_GETMINMAXINFO asking for size constraints for top levels.
+ // Pass on to current creation context
+ if (!platformWindow && !d->m_creationContext.isNull()) {
+ switch (et) {
+ case QtWindows::QuerySizeHints:
+ d->m_creationContext->applyToMinMaxInfo(reinterpret_cast<MINMAXINFO *>(lParam));
+ return true;
+ case QtWindows::ResizeEvent:
+ d->m_creationContext->obtainedGeometry.setSize(QSize(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
+ return true;
+ case QtWindows::MoveEvent:
+ d->m_creationContext->obtainedGeometry.moveTo(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
+ return true;
+ case QtWindows::CalculateSize:
+ return false;
+ default:
+ break;
+ }
+ }
+ if (platformWindow) {
+ if (QWindowsContext::verboseEvents > 1)
+ qDebug().nospace() << "Event window: " << platformWindow->window();
+ } else {
+ qWarning("%s: No Qt Window found for event 0x%x (%s), hwnd=0x%p.",
+ __FUNCTION__, message,
+ QWindowsGuiEventDispatcher::windowsMessageName(message), hwnd);
+ return false;
+ }
+
+ MSG msg;
+ msg.hwnd = hwnd; // re-create MSG structure
+ msg.message = message; // time and pt fields ignored
+ msg.wParam = wParam;
+ msg.lParam = lParam;
+ msg.pt.x = GET_X_LPARAM(lParam);
+ msg.pt.y = GET_Y_LPARAM(lParam);
+
+ switch (et) {
+ case QtWindows::KeyDownEvent:
+ case QtWindows::KeyEvent:
+ case QtWindows::InputMethodKeyEvent:
+ case QtWindows::InputMethodKeyDownEvent:
+ return d->m_keyMapper.translateKeyEvent(platformWindow->window(), hwnd, msg, result);
+ case QtWindows::MoveEvent:
+ platformWindow->handleMoved();
+ return true;
+ case QtWindows::ResizeEvent:
+ platformWindow->handleResized((int)wParam);
+ return true;
+ case QtWindows::QuerySizeHints:
+ platformWindow->getSizeHints(reinterpret_cast<MINMAXINFO *>(lParam));
+ return true;
+ case QtWindows::CalculateSize:
+ // NCCALCSIZE_PARAMS structure if wParam==TRUE
+ if (wParam && QWindowsContext::verboseWindows) {
+ const NCCALCSIZE_PARAMS *ncp = reinterpret_cast<NCCALCSIZE_PARAMS *>(lParam);
+ qDebug() << platformWindow->window() << *ncp;
+ }
+ break;
+ case QtWindows::ExposeEvent:
+ platformWindow->handleWmPaint(hwnd, message, wParam, lParam);
+ return true;
+ case QtWindows::MouseWheelEvent:
+ case QtWindows::MouseEvent:
+ case QtWindows::NonClientMouseEvent:
+ case QtWindows::LeaveEvent:
+ return d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
+ case QtWindows::TouchEvent:
+ return d->m_mouseHandler.translateTouchEvent(platformWindow->window(), hwnd, et, msg, result);
+ case QtWindows::ActivateWindowEvent:
+ QWindowSystemInterface::handleWindowActivated(platformWindow->window());
+ return true;
+ case QtWindows::ShowEvent:
+ platformWindow->handleShown();
+ return true;
+ case QtWindows::HideEvent:
+ platformWindow->handleHidden();
+ return true;
+ case QtWindows::CloseEvent:
+ QWindowSystemInterface::handleCloseEvent(platformWindow->window());
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+/*!
+ \brief Windows functions for actual windows.
+
+ There is another one for timers, sockets, etc in
+ QEventDispatcherWin32.
+
+ \ingroup qt-lighthouse-win
+*/
+
+extern "C" LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT result;
+ const QtWindows::WindowsEventType et = windowsEventType(message, wParam);
+ const bool handled = QWindowsContext::instance()->windowsProc(hwnd, message, et, wParam, lParam, &result);
+ const bool guiEventsQueued = QWindowSystemInterface::windowSystemEventsQueued();
+ if (QWindowsContext::verboseEvents > 1)
+ if (const char *eventName = QWindowsGuiEventDispatcher::windowsMessageName(message))
+ qDebug("EVENT: hwd=%p %s msg=0x%x et=0x%x wp=%d at %d,%d handled=%d gui=%d",
+ hwnd, eventName, message, et, int(wParam),
+ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), handled, guiEventsQueued);
+ if (guiEventsQueued) {
+ const QWindowsGuiEventDispatcher::DispatchContext dispatchContext =
+ QWindowsGuiEventDispatcher::currentDispatchContext();
+ if (dispatchContext.first)
+ QWindowSystemInterface::sendWindowSystemEvents(dispatchContext.first, dispatchContext.second);
+ }
+ if (!handled)
+ result = DefWindowProc(hwnd, message, wParam, lParam);
+ return result;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h
new file mode 100644
index 0000000000..8985c7f0f9
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowscontext.h
@@ -0,0 +1,171 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSCONTEXT_H
+#define QWINDOWSCONTEXT_H
+
+#include "qtwindowsglobal.h"
+#include "qtwindows_additional.h"
+
+#include <QtCore/QScopedPointer>
+#include <QtCore/QSharedPointer>
+
+QT_BEGIN_NAMESPACE
+
+class QWindow;
+class QPlatformScreen;
+class QWindowsWindow;
+class QWindowsMimeConverter;
+struct QWindowCreationContext;
+struct QWindowsContextPrivate;
+class QPoint;
+
+struct QWindowsUser32DLL
+{
+ QWindowsUser32DLL();
+ inline void init();
+ inline bool initTouch();
+
+ typedef BOOL (WINAPI *RegisterTouchWindow)(HWND, ULONG);
+ typedef BOOL (WINAPI *GetTouchInputInfo)(HANDLE, UINT, PVOID, int);
+ typedef BOOL (WINAPI *CloseTouchInputHandle)(HANDLE);
+ typedef BOOL (WINAPI *SetLayeredWindowAttributes)(HWND, COLORREF, BYTE, DWORD);
+ typedef BOOL (WINAPI *UpdateLayeredWindow)(HWND, HDC , const POINT *,
+ const SIZE *, HDC, const POINT *, COLORREF,
+ const BLENDFUNCTION *, DWORD);
+ typedef BOOL (WINAPI *UpdateLayeredWindowIndirect)(HWND, const UPDATELAYEREDWINDOWINFO *);
+ typedef BOOL (WINAPI *IsHungAppWindow)(HWND);
+
+ // Functions missing in Q_CC_GNU stub libraries.
+ SetLayeredWindowAttributes setLayeredWindowAttributes;
+ UpdateLayeredWindow updateLayeredWindow;
+ UpdateLayeredWindowIndirect updateLayeredWindowIndirect;
+
+ // Functions missing in older versions of Windows
+ IsHungAppWindow isHungAppWindow;
+
+ // Touch functions from Windows 7 onwards (also for use with Q_CC_MSVC).
+ RegisterTouchWindow registerTouchWindow;
+ GetTouchInputInfo getTouchInputInfo;
+ CloseTouchInputHandle closeTouchInputHandle;
+};
+
+class QWindowsContext
+{
+ Q_DISABLE_COPY(QWindowsContext)
+public:
+ enum SystemInfoFlags
+ {
+ SI_RTL_Extensions = 0x1,
+ SI_SupportsTouch = 0x2
+ };
+
+ // Verbose flag set by environment variable QT_LIGHTHOUSE_WINDOWS_VERBOSE
+ static int verboseIntegration;
+ static int verboseWindows;
+ static int verboseBackingStore;
+ static int verboseEvents;
+ static int verboseFonts;
+ static int verboseGL;
+ static int verboseOLE;
+
+ explicit QWindowsContext(bool isOpenGL);
+ ~QWindowsContext();
+
+ bool isOpenGL() const;
+
+ int defaultDPI() const;
+
+ QString registerWindowClass(const QWindow *w, bool isGL);
+ QString registerWindowClass(QString cname, WNDPROC proc,
+ unsigned style = 0, HBRUSH brush = 0,
+ bool icon = false);
+ HWND createDummyWindow(const QString &classNameIn,
+ const wchar_t *windowName,
+ WNDPROC wndProc = 0, DWORD style = WS_OVERLAPPED);
+
+ HDC displayContext() const;
+ int screenDepth() const;
+
+ static QWindowsContext *instance();
+
+ static QString windowsErrorMessage(unsigned long errorCode);
+
+ void addWindow(HWND, QWindowsWindow *w);
+ void removeWindow(HWND);
+
+ QWindowsWindow *findPlatformWindow(HWND) const;
+ QWindow *findWindow(HWND) const;
+ QWindowsWindow *findPlatformWindowAt(HWND parent, const QPoint &screenPoint,
+ unsigned cwex_flags) const;
+
+ QWindow *windowUnderMouse() const;
+
+ inline bool windowsProc(HWND hwnd, UINT message,
+ QtWindows::WindowsEventType et,
+ WPARAM wParam, LPARAM lParam, LRESULT *result);
+
+ QWindow *keyGrabber() const;
+ void setKeyGrabber(QWindow *hwnd);
+
+ void setWindowCreationContext(const QSharedPointer<QWindowCreationContext> &ctx);
+
+ // Returns a combination of SystemInfoFlags
+ unsigned systemInfo() const;
+
+ QWindowsMimeConverter &mimeConverter() const;
+
+ static QWindowsUser32DLL user32dll;
+
+ static QByteArray comErrorString(HRESULT hr);
+
+private:
+ void unregisterWindowClasses();
+
+ QScopedPointer<QWindowsContextPrivate> d;
+ static QWindowsContext *m_instance;
+};
+
+extern "C" LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND, UINT, WPARAM, LPARAM);
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSCONTEXT_H
diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp
new file mode 100644
index 0000000000..1ad2079962
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowscursor.cpp
@@ -0,0 +1,451 @@
+/****************************************************************************
+**
+** 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 "qwindowscursor.h"
+#include "qwindowscontext.h"
+#include "qwindowswindow.h"
+#include "qwindowsscreen.h"
+#include "pixmaputils.h"
+
+#include <QtGui/QPixmap>
+#include <QtGui/QImage>
+#include <QtGui/QBitmap>
+#include <QtGui/QGuiApplication>
+#include <QtGui/QScreen>
+#include <QtGui/private/qguiapplication_p.h> // getPixmapCursor()
+
+#include <QtCore/QDebug>
+#include <QtCore/QScopedArrayPointer>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QWindowsCursor
+ \brief Platform cursor implementation
+
+ Note that whereas under X11, a cursor can be set as a property of
+ a window, there is only a global SetCursor() function on Windows.
+ Each Window sets on the global cursor on receiving a Enter-event
+ as do the Window manager frames (resize/move handles).
+
+ \ingroup qt-lighthouse-win
+ \sa QWindowsWindowCursor
+*/
+
+QWindowsCursor::QWindowsCursor(QPlatformScreen *s) :
+ QPlatformCursor(s)
+{
+}
+
+HCURSOR QWindowsCursor::createPixmapCursor(const QPixmap &pixmap, int hotX, int hotY)
+{
+ HCURSOR cur = 0;
+ QBitmap mask = pixmap.mask();
+ if (mask.isNull()) {
+ mask = QBitmap(pixmap.size());
+ mask.fill(Qt::color1);
+ }
+
+ HBITMAP ic = qPixmapToWinHBITMAP(pixmap, HBitmapAlpha);
+ const HBITMAP im = createIconMask(mask);
+
+ ICONINFO ii;
+ ii.fIcon = 0;
+ ii.xHotspot = hotX;
+ ii.yHotspot = hotY;
+ ii.hbmMask = im;
+ ii.hbmColor = ic;
+
+ cur = CreateIconIndirect(&ii);
+
+ DeleteObject(ic);
+ DeleteObject(im);
+ return cur;
+}
+
+HCURSOR QWindowsCursor::createSystemCursor(const QCursor &c)
+{
+ int hx = c.hotSpot().x();
+ int hy = c.hotSpot().y();
+ const Qt::CursorShape cshape = c.shape();
+ if (cshape == Qt::BitmapCursor) {
+ const QPixmap pixmap = c.pixmap();
+ if (!pixmap.isNull())
+ if (const HCURSOR hc = createPixmapCursor(pixmap, hx, hy))
+ return hc;
+ }
+
+ // Non-standard Windows cursors are created from bitmaps
+
+ static const uchar vsplit_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00,
+ 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ static const uchar vsplitm_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xf0, 0x07, 0x00,
+ 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00,
+ 0x00, 0xc0, 0x01, 0x00, 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00,
+ 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00,
+ 0x80, 0xff, 0xff, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00,
+ 0x00, 0xc0, 0x01, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00,
+ 0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ static const uchar hsplit_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
+ 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
+ 0x00, 0x41, 0x82, 0x00, 0x80, 0x41, 0x82, 0x01, 0xc0, 0x7f, 0xfe, 0x03,
+ 0x80, 0x41, 0x82, 0x01, 0x00, 0x41, 0x82, 0x00, 0x00, 0x40, 0x02, 0x00,
+ 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
+ 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ static const uchar hsplitm_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00,
+ 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe2, 0x47, 0x00, 0x00, 0xe3, 0xc7, 0x00,
+ 0x80, 0xe3, 0xc7, 0x01, 0xc0, 0xff, 0xff, 0x03, 0xe0, 0xff, 0xff, 0x07,
+ 0xc0, 0xff, 0xff, 0x03, 0x80, 0xe3, 0xc7, 0x01, 0x00, 0xe3, 0xc7, 0x00,
+ 0x00, 0xe2, 0x47, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00,
+ 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ static const uchar phand_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00,
+ 0x80, 0x04, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00,
+ 0x80, 0x1c, 0x00, 0x00, 0x80, 0xe4, 0x00, 0x00, 0x80, 0x24, 0x03, 0x00,
+ 0x80, 0x24, 0x05, 0x00, 0xb8, 0x24, 0x09, 0x00, 0xc8, 0x00, 0x09, 0x00,
+ 0x88, 0x00, 0x08, 0x00, 0x90, 0x00, 0x08, 0x00, 0xa0, 0x00, 0x08, 0x00,
+ 0x20, 0x00, 0x08, 0x00, 0x40, 0x00, 0x08, 0x00, 0x40, 0x00, 0x04, 0x00,
+ 0x80, 0x00, 0x04, 0x00, 0x80, 0x00, 0x04, 0x00, 0x00, 0x01, 0x02, 0x00,
+ 0x00, 0x01, 0x02, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ static const uchar phandm_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00,
+ 0x80, 0x07, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00,
+ 0x80, 0x1f, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x80, 0xff, 0x03, 0x00,
+ 0x80, 0xff, 0x07, 0x00, 0xb8, 0xff, 0x0f, 0x00, 0xf8, 0xff, 0x0f, 0x00,
+ 0xf8, 0xff, 0x0f, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0xe0, 0xff, 0x0f, 0x00,
+ 0xe0, 0xff, 0x0f, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0xc0, 0xff, 0x07, 0x00,
+ 0x80, 0xff, 0x07, 0x00, 0x80, 0xff, 0x07, 0x00, 0x00, 0xff, 0x03, 0x00,
+ 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ static const uchar openhand_bits[] = {
+ 0x80,0x01,0x58,0x0e,0x64,0x12,0x64,0x52,0x48,0xb2,0x48,0x92,
+ 0x16,0x90,0x19,0x80,0x11,0x40,0x02,0x40,0x04,0x40,0x04,0x20,
+ 0x08,0x20,0x10,0x10,0x20,0x10,0x00,0x00};
+ static const uchar openhandm_bits[] = {
+ 0x80,0x01,0xd8,0x0f,0xfc,0x1f,0xfc,0x5f,0xf8,0xff,0xf8,0xff,
+ 0xf6,0xff,0xff,0xff,0xff,0x7f,0xfe,0x7f,0xfc,0x7f,0xfc,0x3f,
+ 0xf8,0x3f,0xf0,0x1f,0xe0,0x1f,0x00,0x00};
+ static const uchar closedhand_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x0d,0x48,0x32,0x08,0x50,
+ 0x10,0x40,0x18,0x40,0x04,0x40,0x04,0x20,0x08,0x20,0x10,0x10,
+ 0x20,0x10,0x20,0x10,0x00,0x00,0x00,0x00};
+ static const uchar closedhandm_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x0d,0xf8,0x3f,0xf8,0x7f,
+ 0xf0,0x7f,0xf8,0x7f,0xfc,0x7f,0xfc,0x3f,0xf8,0x3f,0xf0,0x1f,
+ 0xe0,0x1f,0xe0,0x1f,0x00,0x00,0x00,0x00};
+
+ static const uchar * const cursor_bits32[] = {
+ vsplit_bits, vsplitm_bits, hsplit_bits, hsplitm_bits,
+ phand_bits, phandm_bits
+ };
+
+ wchar_t *sh = 0;
+ switch (c.shape()) { // map to windows cursor
+ case Qt::ArrowCursor:
+ sh = IDC_ARROW;
+ break;
+ case Qt::UpArrowCursor:
+ sh = IDC_UPARROW;
+ break;
+ case Qt::CrossCursor:
+ sh = IDC_CROSS;
+ break;
+ case Qt::WaitCursor:
+ sh = IDC_WAIT;
+ break;
+ case Qt::IBeamCursor:
+ sh = IDC_IBEAM;
+ break;
+ case Qt::SizeVerCursor:
+ sh = IDC_SIZENS;
+ break;
+ case Qt::SizeHorCursor:
+ sh = IDC_SIZEWE;
+ break;
+ case Qt::SizeBDiagCursor:
+ sh = IDC_SIZENESW;
+ break;
+ case Qt::SizeFDiagCursor:
+ sh = IDC_SIZENWSE;
+ break;
+ case Qt::SizeAllCursor:
+ sh = IDC_SIZEALL;
+ break;
+ case Qt::ForbiddenCursor:
+ sh = IDC_NO;
+ break;
+ case Qt::WhatsThisCursor:
+ sh = IDC_HELP;
+ break;
+ case Qt::BusyCursor:
+ sh = IDC_APPSTARTING;
+ break;
+ case Qt::PointingHandCursor:
+ sh = IDC_HAND;
+ break;
+ case Qt::BlankCursor:
+ case Qt::SplitVCursor:
+ case Qt::SplitHCursor:
+ case Qt::OpenHandCursor:
+ case Qt::ClosedHandCursor:
+ case Qt::BitmapCursor: {
+ QImage bbits, mbits;
+ bool invb, invm;
+ if (cshape == Qt::BlankCursor) {
+ bbits = QImage(32, 32, QImage::Format_Mono);
+ bbits.fill(0); // ignore color table
+ mbits = bbits.copy();
+ hx = hy = 16;
+ invb = invm = false;
+ } else if (cshape == Qt::OpenHandCursor || cshape == Qt::ClosedHandCursor) {
+ bool open = cshape == Qt::OpenHandCursor;
+ QBitmap cb = QBitmap::fromData(QSize(16, 16), open ? openhand_bits : closedhand_bits);
+ QBitmap cm = QBitmap::fromData(QSize(16, 16), open ? openhandm_bits : closedhandm_bits);
+ bbits = cb.toImage().convertToFormat(QImage::Format_Mono);
+ mbits = cm.toImage().convertToFormat(QImage::Format_Mono);
+ hx = hy = 8;
+ invb = invm = false;
+ } else if (cshape != Qt::BitmapCursor) {
+ int i = cshape - Qt::SplitVCursor;
+ QBitmap cb = QBitmap::fromData(QSize(32, 32), cursor_bits32[i * 2]);
+ QBitmap cm = QBitmap::fromData(QSize(32, 32), cursor_bits32[i * 2 + 1]);
+ bbits = cb.toImage().convertToFormat(QImage::Format_Mono);
+ mbits = cm.toImage().convertToFormat(QImage::Format_Mono);
+ if (cshape == Qt::PointingHandCursor) {
+ hx = 7;
+ hy = 0;
+ } else
+ hx = hy = 16;
+ invb = invm = false;
+ } else {
+ bbits = c.bitmap()->toImage().convertToFormat(QImage::Format_Mono);
+ mbits = c.mask()->toImage().convertToFormat(QImage::Format_Mono);
+ invb = bbits.colorCount() > 1 && qGray(bbits.color(0)) < qGray(bbits.color(1));
+ invm = mbits.colorCount() > 1 && qGray(mbits.color(0)) < qGray(mbits.color(1));
+ }
+ const int n = qMax(1, bbits.width() / 8);
+ const int h = bbits.height();
+ QScopedArrayPointer<uchar> xBits(new uchar[h * n]);
+ QScopedArrayPointer<uchar> xMask(new uchar[h * n]);
+ int x = 0;
+ for (int i = 0; i < h; ++i) {
+ uchar *bits = bbits.scanLine(i);
+ uchar *mask = mbits.scanLine(i);
+ for (int j = 0; j < n; ++j) {
+ uchar b = bits[j];
+ uchar m = mask[j];
+ if (invb)
+ b ^= 0xff;
+ if (invm)
+ m ^= 0xff;
+ xBits[x] = ~m;
+ xMask[x] = b ^ m;
+ ++x;
+ }
+ }
+ return CreateCursor(GetModuleHandle(0), hx, hy, bbits.width(), bbits.height(),
+ xBits.data(), xMask.data());
+ }
+ case Qt::DragCopyCursor:
+ case Qt::DragMoveCursor:
+ case Qt::DragLinkCursor: {
+ const QPixmap pixmap = QGuiApplicationPrivate::instance()->getPixmapCursor(cshape);
+ return createPixmapCursor(pixmap, hx, hy);
+ }
+ default:
+ qWarning("%s: Invalid cursor shape %d", __FUNCTION__, cshape);
+ return 0;
+ }
+ return (HCURSOR)LoadImage(0, sh, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
+}
+
+/*!
+ \brief Return cached standard cursor resources or create new ones.
+*/
+
+QWindowsWindowCursor QWindowsCursor::standardWindowCursor(Qt::CursorShape shape)
+{
+ StandardCursorCache::iterator it = m_standardCursorCache.find(shape);
+ if (it == m_standardCursorCache.end())
+ it = m_standardCursorCache.insert(shape, QWindowsWindowCursor(QCursor(shape)));
+ return it.value();
+}
+
+/*!
+ \brief Set a cursor on a window.
+
+ This is called frequently as the mouse moves over widgets in the window
+ (QLineEdits, etc).
+*/
+
+void QWindowsCursor::changeCursor(QCursor *cursorIn, QWindow *window)
+{
+
+ if (QWindowsContext::verboseWindows)
+ qDebug() << __FUNCTION__ << cursorIn << window;
+ if (!cursorIn || !window)
+ return;
+ const QWindowsWindowCursor wcursor =
+ cursorIn->shape() == Qt::BitmapCursor ?
+ QWindowsWindowCursor(*cursorIn) : standardWindowCursor(cursorIn->shape());
+ if (wcursor.handle()) {
+ QWindowsWindow::baseWindowOf(window)->setCursor(wcursor);
+ } else {
+ qWarning("%s: Unable to obtain system cursor for %d",
+ __FUNCTION__, cursorIn->shape());
+ }
+}
+
+QPoint QWindowsCursor::mousePosition()
+{
+ POINT p;
+ GetCursorPos(&p);
+ if (QWindowsContext::verboseWindows)
+ qDebug("%s %ld,%ld", __FUNCTION__, p.x, p.y);
+ return QPoint(p.x, p.y);
+}
+
+void QWindowsCursor::setPos(const QPoint &pos)
+{
+ if (QWindowsContext::verboseWindows)
+ qDebug("%s %d,%d", __FUNCTION__, pos.x(), pos.y());
+ SetCursorPos(pos.x(), pos.y());
+}
+
+/*!
+ \class QWindowsWindowCursor
+ \brief Per-Window cursor. Contains a QCursor and manages its associated system
+ cursor handle resource.
+
+ Based on QSharedDataPointer, so that it can be passed around and
+ used as a property of QWindowsBaseWindow.
+
+ \ingroup qt-lighthouse-win
+ \sa QWindowsCursor
+*/
+
+class QWindowsWindowCursorData : public QSharedData
+{
+public:
+ explicit QWindowsWindowCursorData(const QCursor &c);
+ ~QWindowsWindowCursorData();
+
+ const QCursor m_cursor;
+ const HCURSOR m_handle;
+};
+
+QWindowsWindowCursorData::QWindowsWindowCursorData(const QCursor &c) :
+ m_cursor(c),
+ m_handle(QWindowsCursor::createSystemCursor(c))
+{
+}
+
+QWindowsWindowCursorData::~QWindowsWindowCursorData()
+{
+ DestroyCursor(m_handle);
+}
+
+QWindowsWindowCursor::QWindowsWindowCursor(const QCursor &c) :
+ m_data(new QWindowsWindowCursorData(c))
+{
+}
+
+QWindowsWindowCursor::~QWindowsWindowCursor()
+{
+}
+
+QWindowsWindowCursor::QWindowsWindowCursor(const QWindowsWindowCursor &rhs) :
+ m_data(rhs.m_data)
+{
+}
+
+QWindowsWindowCursor & QWindowsWindowCursor::operator =(const QWindowsWindowCursor &rhs)
+{
+ if (this != &rhs)
+ m_data.operator =(rhs.m_data);
+ return *this;
+}
+
+QCursor QWindowsWindowCursor::cursor() const
+{
+ return m_data->m_cursor;
+}
+
+HCURSOR QWindowsWindowCursor::handle() const
+{
+ return m_data->m_handle;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowscursor.h b/src/plugins/platforms/windows/qwindowscursor.h
new file mode 100644
index 0000000000..bf8cb837d9
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowscursor.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSCURSOR_H
+#define QWINDOWSCURSOR_H
+
+#include "qtwindows_additional.h"
+
+#include <QtGui/QPlatformCursor>
+#include <QtCore/QSharedDataPointer>
+#include <QtCore/QHash>
+
+QT_BEGIN_NAMESPACE
+
+class QWindowsWindowCursorData;
+
+class QWindowsWindowCursor
+{
+public:
+ explicit QWindowsWindowCursor(const QCursor &c);
+ ~QWindowsWindowCursor();
+ QWindowsWindowCursor(const QWindowsWindowCursor &c);
+ QWindowsWindowCursor &operator=(const QWindowsWindowCursor &c);
+
+ QCursor cursor() const;
+ HCURSOR handle() const;
+
+private:
+ QSharedDataPointer<QWindowsWindowCursorData> m_data;
+};
+
+class QWindowsCursor : public QPlatformCursor
+{
+public:
+ explicit QWindowsCursor(QPlatformScreen *);
+
+ virtual void changeCursor(QCursor * widgetCursor, QWindow * widget);
+ virtual QPoint pos() const { return mousePosition(); }
+ virtual void setPos(const QPoint &pos);
+
+ static HCURSOR createPixmapCursor(const QPixmap &pixmap, int hotX, int hotY);
+ static HCURSOR createSystemCursor(const QCursor &c);
+ static QPoint mousePosition();
+
+ QWindowsWindowCursor standardWindowCursor(Qt::CursorShape s = Qt::ArrowCursor);
+
+private:
+ typedef QHash<Qt::CursorShape, QWindowsWindowCursor> StandardCursorCache;
+
+ StandardCursorCache m_standardCursorCache;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSCURSOR_H
diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp
new file mode 100644
index 0000000000..1535437a32
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsdrag.cpp
@@ -0,0 +1,721 @@
+/****************************************************************************
+**
+** 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 "qwindowsdrag.h"
+#include "qwindowscontext.h"
+#include "qwindowsclipboard.h"
+#include "qwindowsintegration.h"
+#include "qwindowsole.h"
+#include "qtwindows_additional.h"
+#include "qwindowswindow.h"
+#include "qwindowsmousehandler.h"
+#include "qwindowscursor.h"
+
+#include <QtGui/QMouseEvent>
+#include <QtGui/QPixmap>
+#include <QtGui/QPainter>
+#include <QtGui/QGuiApplication>
+
+#include <QtCore/QDebug>
+#include <QtCore/QPoint>
+
+#include <shlobj.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QWindowsDropMimeData
+ \brief Special mime data class for data retrieval from Drag operations.
+
+ Implementation of QWindowsInternalMimeDataBase which retrieves the
+ current drop data object from QWindowsDrag.
+
+ \sa QWindowsDrag
+ \ingroup qt-lighthouse-win
+*/
+
+IDataObject *QWindowsDropMimeData::retrieveDataObject() const
+{
+ return QWindowsDrag::instance()->dropDataObject();
+}
+
+static inline Qt::DropActions translateToQDragDropActions(DWORD pdwEffects)
+{
+ Qt::DropActions actions = Qt::IgnoreAction;
+ if (pdwEffects & DROPEFFECT_LINK)
+ actions |= Qt::LinkAction;
+ if (pdwEffects & DROPEFFECT_COPY)
+ actions |= Qt::CopyAction;
+ if (pdwEffects & DROPEFFECT_MOVE)
+ actions |= Qt::MoveAction;
+ return actions;
+}
+
+static inline Qt::DropAction translateToQDragDropAction(DWORD pdwEffect)
+{
+ if (pdwEffect & DROPEFFECT_LINK)
+ return Qt::LinkAction;
+ if (pdwEffect & DROPEFFECT_COPY)
+ return Qt::CopyAction;
+ if (pdwEffect & DROPEFFECT_MOVE)
+ return Qt::MoveAction;
+ return Qt::IgnoreAction;
+}
+
+static inline DWORD translateToWinDragEffects(Qt::DropActions action)
+{
+ DWORD effect = DROPEFFECT_NONE;
+ if (action & Qt::LinkAction)
+ effect |= DROPEFFECT_LINK;
+ if (action & Qt::CopyAction)
+ effect |= DROPEFFECT_COPY;
+ if (action & Qt::MoveAction)
+ effect |= DROPEFFECT_MOVE;
+ return effect;
+}
+
+static inline Qt::KeyboardModifiers toQtKeyboardModifiers(DWORD keyState)
+{
+ Qt::KeyboardModifiers modifiers = Qt::NoModifier;
+
+ if (keyState & MK_SHIFT)
+ modifiers |= Qt::ShiftModifier;
+ if (keyState & MK_CONTROL)
+ modifiers |= Qt::ControlModifier;
+ if (keyState & MK_ALT)
+ modifiers |= Qt::AltModifier;
+
+ return modifiers;
+}
+
+/*!
+ \class QWindowsOleDropSource
+ \brief Implementation of IDropSource
+
+ Used for drag operations.
+
+ \sa QWindowsDrag
+ \ingroup qt-lighthouse-win
+*/
+
+class QWindowsOleDropSource : public IDropSource
+{
+public:
+ QWindowsOleDropSource();
+ virtual ~QWindowsOleDropSource();
+
+ void createCursors();
+
+ // IUnknown methods
+ STDMETHOD(QueryInterface)(REFIID riid, void ** ppvObj);
+ STDMETHOD_(ULONG,AddRef)(void);
+ STDMETHOD_(ULONG,Release)(void);
+
+ // IDropSource methods
+ STDMETHOD(QueryContinueDrag)(BOOL fEscapePressed, DWORD grfKeyState);
+ STDMETHOD(GiveFeedback)(DWORD dwEffect);
+
+private:
+ typedef QMap <Qt::DropAction, HCURSOR> ActionCursorMap;
+
+ inline void clearCursors();
+
+ Qt::MouseButtons m_currentButtons;
+ Qt::DropAction m_currentAction;
+ ActionCursorMap m_cursors;
+
+ ULONG m_refs;
+};
+
+QWindowsOleDropSource::QWindowsOleDropSource() :
+ m_currentButtons(Qt::NoButton), m_currentAction(Qt::IgnoreAction),
+ m_refs(1)
+{
+ if (QWindowsContext::verboseOLE)
+ qDebug("%s", __FUNCTION__);
+}
+
+QWindowsOleDropSource::~QWindowsOleDropSource()
+{
+ clearCursors();
+ if (QWindowsContext::verboseOLE)
+ qDebug("%s", __FUNCTION__);
+}
+
+void QWindowsOleDropSource::createCursors()
+{
+ QDragManager *manager = QDragManager::self();
+ if (!manager || !manager->object)
+ return;
+ const QPixmap pixmap = manager->object->pixmap();
+ const bool hasPixmap = !pixmap.isNull();
+ if (!hasPixmap && manager->dragPrivate()->customCursors.isEmpty())
+ return;
+
+ QList<Qt::DropAction> actions;
+ actions << Qt::MoveAction << Qt::CopyAction << Qt::LinkAction;
+ if (hasPixmap)
+ actions << Qt::IgnoreAction;
+ const QPoint hotSpot = manager->object->hotSpot();
+ for (int cnum = 0; cnum < actions.size(); ++cnum) {
+ const QPixmap cpm = manager->dragCursor(actions.at(cnum));
+ int w = cpm.width();
+ int h = cpm.height();
+
+ if (hasPixmap) {
+ const int x1 = qMin(-hotSpot.x(), 0);
+ const int x2 = qMax(pixmap.width() - hotSpot.x(), cpm.width());
+ const int y1 = qMin(-hotSpot.y(), 0);
+ const int y2 = qMax(pixmap.height() - hotSpot.y(), cpm.height());
+
+ w = x2 - x1 + 1;
+ h = y2 - y1 + 1;
+ }
+
+ const QRect srcRect = pixmap.rect();
+ const QPoint pmDest = QPoint(qMax(0, -hotSpot.x()), qMax(0, -hotSpot.y()));
+ const QPoint newHotSpot = hotSpot;
+ QPixmap newCursor(w, h);
+ if (hasPixmap) {
+ newCursor.fill(QColor(0, 0, 0, 0));
+ QPainter p(&newCursor);
+ p.drawPixmap(pmDest, pixmap, srcRect);
+ p.drawPixmap(qMax(0,newHotSpot.x()),qMax(0,newHotSpot.y()),cpm);
+ } else {
+ newCursor = cpm;
+ }
+
+ const int hotX = hasPixmap ? qMax(0,newHotSpot.x()) : 0;
+ const int hotY = hasPixmap ? qMax(0,newHotSpot.y()) : 0;
+
+ if (const HCURSOR sysCursor = QWindowsCursor::createPixmapCursor(newCursor, hotX, hotY))
+ m_cursors.insert(actions.at(cnum), sysCursor);
+ }
+ if (QWindowsContext::verboseOLE)
+ qDebug("%s %d cursors", __FUNCTION__, m_cursors.size());
+}
+
+void QWindowsOleDropSource::clearCursors()
+{
+ if (!m_cursors.isEmpty()) {
+ const ActionCursorMap::const_iterator cend = m_cursors.constEnd();
+ for (ActionCursorMap::const_iterator it = m_cursors.constBegin(); it != cend; ++it)
+ DestroyCursor(it.value());
+ m_cursors.clear();
+ }
+}
+
+//---------------------------------------------------------------------
+// IUnknown Methods
+//---------------------------------------------------------------------
+
+STDMETHODIMP
+QWindowsOleDropSource::QueryInterface(REFIID iid, void FAR* FAR* ppv)
+{
+ if (iid == IID_IUnknown || iid == IID_IDropSource) {
+ *ppv = this;
+ ++m_refs;
+ return NOERROR;
+ }
+ *ppv = NULL;
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+STDMETHODIMP_(ULONG)
+QWindowsOleDropSource::AddRef(void)
+{
+ return ++m_refs;
+}
+
+STDMETHODIMP_(ULONG)
+QWindowsOleDropSource::Release(void)
+{
+ if (--m_refs == 0) {
+ delete this;
+ return 0;
+ }
+ return m_refs;
+}
+
+/*!
+ \brief Check for cancel.
+*/
+
+QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
+QWindowsOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
+{
+ HRESULT hr = S_OK;
+ do {
+ if (fEscapePressed || QWindowsDrag::instance()->dragBeingCancelled()) {
+ hr = ResultFromScode(DRAGDROP_S_CANCEL);
+ break;
+ }
+
+ // grfKeyState is broken on CE & some Windows XP versions,
+ // therefore we need to check the state manually
+ if ((GetAsyncKeyState(VK_LBUTTON) == 0)
+ && (GetAsyncKeyState(VK_MBUTTON) == 0)
+ && (GetAsyncKeyState(VK_RBUTTON) == 0)) {
+ hr = ResultFromScode(DRAGDROP_S_DROP);
+ break;
+ }
+
+ const Qt::MouseButtons buttons = QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState);
+ if (m_currentButtons == Qt::NoButton) {
+ m_currentButtons = buttons;
+ } else {
+ // Button changed: Complete Drop operation.
+ if (!(m_currentButtons & buttons)) {
+ hr = ResultFromScode(DRAGDROP_S_DROP);
+ break;
+ }
+ }
+
+ QGuiApplication::processEvents();
+
+ } while (false);
+
+ QDragManager::self()->willDrop = hr == DRAGDROP_S_DROP;
+
+ if (QWindowsContext::verboseOLE
+ && (QWindowsContext::verboseOLE > 1 || hr != S_OK))
+ qDebug("%s fEscapePressed=%d, grfKeyState=%lu buttons=%d willDrop = %d returns 0x%x",
+ __FUNCTION__, fEscapePressed,grfKeyState, int(m_currentButtons),
+ QDragManager::self()->willDrop, int(hr));
+ return hr;
+}
+
+/*!
+ \brief Give feedback: Change cursor accoding to action.
+*/
+
+QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
+QWindowsOleDropSource::GiveFeedback(DWORD dwEffect)
+{
+ const Qt::DropAction action = translateToQDragDropAction(dwEffect);
+
+ if (QWindowsContext::verboseOLE > 2)
+ qDebug("%s dwEffect=%lu, action=%d", __FUNCTION__, dwEffect, action);
+
+ if (m_currentAction != action) {
+ m_currentAction = action;
+ QDragManager::self()->emitActionChanged(m_currentAction);
+ }
+
+ const ActionCursorMap::const_iterator it = m_cursors.constFind(m_currentAction);
+ if (it != m_cursors.constEnd()) {
+ SetCursor(it.value());
+ return ResultFromScode(S_OK);
+ }
+
+ return ResultFromScode(DRAGDROP_S_USEDEFAULTCURSORS);
+}
+
+/*!
+ \class QWindowsOleDropTarget
+ \brief Implementation of IDropTarget
+
+ To be registered for each window. Currently, drop sites
+ are enabled for top levels. The child window handling
+ (sending DragEnter/Leave, etc) is handled in here.
+
+ \sa QWindowsDrag
+ \ingroup qt-lighthouse-win
+*/
+
+QWindowsOleDropTarget::QWindowsOleDropTarget(QWindow *w) :
+ m_refs(1), m_window(w), m_currentWindow(0), m_chosenEffect(0), m_lastKeyState(0)
+{
+ if (QWindowsContext::verboseOLE)
+ qDebug() << __FUNCTION__ << this << w;
+}
+
+QWindowsOleDropTarget::~QWindowsOleDropTarget()
+{
+ if (QWindowsContext::verboseOLE)
+ qDebug("%s %p", __FUNCTION__, this);
+}
+
+STDMETHODIMP
+QWindowsOleDropTarget::QueryInterface(REFIID iid, void FAR* FAR* ppv)
+{
+ if (iid == IID_IUnknown || iid == IID_IDropTarget) {
+ *ppv = this;
+ AddRef();
+ return NOERROR;
+ }
+ *ppv = NULL;
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+STDMETHODIMP_(ULONG)
+QWindowsOleDropTarget::AddRef(void)
+{
+ return ++m_refs;
+}
+
+STDMETHODIMP_(ULONG)
+QWindowsOleDropTarget::Release(void)
+{
+ if (--m_refs == 0) {
+ delete this;
+ return 0;
+ }
+ return m_refs;
+}
+
+QWindow *QWindowsOleDropTarget::findDragOverWindow(const POINTL &pt) const
+{
+ if (QWindowsWindow *child =
+ QWindowsWindow::baseWindowOf(m_window)->childAtScreenPoint(QPoint(pt.x, pt.y)))
+ return child->window();
+ return m_window;
+}
+
+QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
+QWindowsOleDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState,
+ POINTL pt, LPDWORD pdwEffect)
+{
+ if (QWindowsContext::verboseOLE)
+ qDebug("%s widget=%p key=%lu, pt=%ld,%ld", __FUNCTION__, m_window, grfKeyState, pt.x, pt.y);
+
+ QWindowsDrag::instance()->setDropDataObject(pDataObj);
+ pDataObj->AddRef();
+ m_currentWindow = m_window;
+ sendDragEnterEvent(m_window, grfKeyState, pt, pdwEffect);
+ *pdwEffect = m_chosenEffect;
+ return NOERROR;
+}
+
+void QWindowsOleDropTarget::sendDragEnterEvent(QWindow *dragEnterWidget,
+ DWORD grfKeyState,
+ POINTL pt, LPDWORD pdwEffect)
+{
+ Q_ASSERT(dragEnterWidget);
+
+ m_lastPoint = QWindowsGeometryHint::mapFromGlobal(dragEnterWidget, QPoint(pt.x,pt.y));
+ m_lastKeyState = grfKeyState;
+
+ m_chosenEffect = DROPEFFECT_NONE;
+
+ QDragManager *manager = QDragManager::self();
+ QMimeData *md = manager->dropData();
+ const Qt::MouseButtons mouseButtons
+ = QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState);
+ const Qt::DropActions actions = translateToQDragDropActions(*pdwEffect);
+ const Qt::KeyboardModifiers keyMods = toQtKeyboardModifiers(grfKeyState);
+ QDragEnterEvent enterEvent(m_lastPoint, actions, md, mouseButtons, keyMods);
+ QGuiApplication::sendEvent(m_currentWindow, &enterEvent);
+ m_answerRect = enterEvent.answerRect();
+ if (QWindowsContext::verboseOLE)
+ qDebug() << __FUNCTION__ << " sent drag enter to " << m_window
+ << *md << " actions=" << actions
+ << " mods=" << keyMods << " accepted: "
+ << enterEvent.isAccepted();
+
+ if (enterEvent.isAccepted())
+ m_chosenEffect = translateToWinDragEffects(enterEvent.dropAction());
+ // Documentation states that a drag move event is sent immediately after
+ // a drag enter event. This will honor widgets overriding dragMoveEvent only:
+ if (enterEvent.isAccepted()) {
+ QDragMoveEvent moveEvent(m_lastPoint, actions, md, mouseButtons, keyMods);
+ m_answerRect = enterEvent.answerRect();
+ moveEvent.setDropAction(enterEvent.dropAction());
+ moveEvent.accept(); // accept by default, since enter event was accepted.
+
+ QGuiApplication::sendEvent(dragEnterWidget, &moveEvent);
+ if (moveEvent.isAccepted()) {
+ m_answerRect = moveEvent.answerRect();
+ m_chosenEffect = translateToWinDragEffects(moveEvent.dropAction());
+ } else {
+ m_chosenEffect = DROPEFFECT_NONE;
+ }
+ }
+}
+
+QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
+QWindowsOleDropTarget::DragOver(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
+{
+ QWindow *dragOverWindow = findDragOverWindow(pt);
+
+ const QPoint tmpPoint = QWindowsGeometryHint::mapFromGlobal(dragOverWindow, QPoint(pt.x,pt.y));
+ // see if we should compress this event
+ if ((tmpPoint == m_lastPoint || m_answerRect.contains(tmpPoint))
+ && m_lastKeyState == grfKeyState) {
+ *pdwEffect = m_chosenEffect;
+ return NOERROR;
+ }
+
+ if (QWindowsContext::verboseOLE > 1)
+ qDebug().nospace() << '>' << __FUNCTION__ << ' ' << m_window << " current "
+ << dragOverWindow << " key=" << grfKeyState
+ << " pt=" <<pt.x << ',' << pt.y;
+
+ if (dragOverWindow != m_currentWindow) {
+ QPointer<QWindow> dragOverWindowGuard(dragOverWindow);
+ // Send drag leave event to the previous drag widget.
+ // Drag-Over widget might be deleted in DragLeave,
+ // (tasktracker 218353).
+ QDragLeaveEvent dragLeave;
+ if (m_currentWindow)
+ QGuiApplication::sendEvent(m_currentWindow, &dragLeave);
+ if (!dragOverWindowGuard) {
+ dragOverWindow = findDragOverWindow(pt);
+ }
+ // Send drag enter event to the current drag widget.
+ m_currentWindow = dragOverWindow;
+ sendDragEnterEvent(dragOverWindow, grfKeyState, pt, pdwEffect);
+ }
+
+ QDragManager *manager = QDragManager::self();
+ QMimeData *md = manager->dropData();
+
+ const Qt::DropActions actions = translateToQDragDropActions(*pdwEffect);
+
+ QDragMoveEvent oldEvent(m_lastPoint, actions, md,
+ QWindowsMouseHandler::keyStateToMouseButtons(m_lastKeyState),
+ toQtKeyboardModifiers(m_lastKeyState));
+
+ m_lastPoint = tmpPoint;
+ m_lastKeyState = grfKeyState;
+
+ QDragMoveEvent e(tmpPoint, actions, md,
+ QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState),
+ toQtKeyboardModifiers(grfKeyState));
+ if (m_chosenEffect != DROPEFFECT_NONE) {
+ if (oldEvent.dropAction() == e.dropAction() &&
+ oldEvent.keyboardModifiers() == e.keyboardModifiers())
+ e.setDropAction(translateToQDragDropAction(m_chosenEffect));
+ e.accept();
+ }
+ QGuiApplication::sendEvent(dragOverWindow, &e);
+
+ m_answerRect = e.answerRect();
+ if (e.isAccepted())
+ m_chosenEffect = translateToWinDragEffects(e.dropAction());
+ else
+ m_chosenEffect = DROPEFFECT_NONE;
+ *pdwEffect = m_chosenEffect;
+
+ if (QWindowsContext::verboseOLE > 1)
+ qDebug("<%s effect=0x%lx", __FUNCTION__, m_chosenEffect);
+ return NOERROR;
+}
+
+QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
+QWindowsOleDropTarget::DragLeave()
+{
+ if (QWindowsContext::verboseOLE)
+ qDebug().nospace() <<__FUNCTION__ << ' ' << m_window;
+
+ m_currentWindow = 0;
+ QDragLeaveEvent e;
+ QGuiApplication::sendEvent(m_window, &e);
+ QWindowsDrag::instance()->releaseDropDataObject();
+
+ return NOERROR;
+}
+
+#define KEY_STATE_BUTTON_MASK (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)
+
+QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
+QWindowsOleDropTarget::Drop(LPDATAOBJECT /*pDataObj*/, DWORD grfKeyState,
+ POINTL pt, LPDWORD pdwEffect)
+{
+ QWindow *dropWindow = findDragOverWindow(pt);
+
+ if (QWindowsContext::verboseOLE)
+ qDebug().nospace() << __FUNCTION__ << ' ' << m_window
+ << " on " << dropWindow
+ << " keys=" << grfKeyState << " pt="
+ << pt.x << ',' << pt.y;
+
+ m_lastPoint = QWindowsGeometryHint::mapFromGlobal(dropWindow, QPoint(pt.x,pt.y));
+ // grfKeyState does not all ways contain button state in the drop so if
+ // it doesn't then use the last known button state;
+ if ((grfKeyState & KEY_STATE_BUTTON_MASK) == 0)
+ grfKeyState |= m_lastKeyState & KEY_STATE_BUTTON_MASK;
+ m_lastKeyState = grfKeyState;
+
+ QWindowsDrag *windowsDrag = QWindowsDrag::instance();
+ QDragManager *manager = QDragManager::self();
+ QMimeData *md = manager->dropData();
+ QDropEvent e(m_lastPoint, translateToQDragDropActions(*pdwEffect), md,
+ QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState),
+ toQtKeyboardModifiers(grfKeyState));
+ if (m_chosenEffect != DROPEFFECT_NONE)
+ e.setDropAction(translateToQDragDropAction(m_chosenEffect));
+
+ QGuiApplication::sendEvent(dropWindow, &e);
+ if (m_chosenEffect != DROPEFFECT_NONE)
+ e.accept();
+
+ if (e.isAccepted()) {
+ if (e.dropAction() == Qt::MoveAction || e.dropAction() == Qt::TargetMoveAction) {
+ if (e.dropAction() == Qt::MoveAction)
+ m_chosenEffect = DROPEFFECT_MOVE;
+ else
+ m_chosenEffect = DROPEFFECT_COPY;
+ HGLOBAL hData = GlobalAlloc(0, sizeof(DWORD));
+ if (hData) {
+ DWORD *moveEffect = (DWORD *)GlobalLock(hData);;
+ *moveEffect = DROPEFFECT_MOVE;
+ GlobalUnlock(hData);
+ STGMEDIUM medium;
+ memset(&medium, 0, sizeof(STGMEDIUM));
+ medium.tymed = TYMED_HGLOBAL;
+ medium.hGlobal = hData;
+ FORMATETC format;
+ format.cfFormat = RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT);
+ format.tymed = TYMED_HGLOBAL;
+ format.ptd = 0;
+ format.dwAspect = 1;
+ format.lindex = -1;
+ windowsDrag->dropDataObject()->SetData(&format, &medium, true);
+ }
+ } else {
+ m_chosenEffect = translateToWinDragEffects(e.dropAction());
+ }
+ } else {
+ m_chosenEffect = DROPEFFECT_NONE;
+ }
+ *pdwEffect = m_chosenEffect;
+
+ windowsDrag->releaseDropDataObject();
+ return NOERROR;
+}
+
+/*!
+ \class QWindowsDrag
+ \brief Windows drag implementation.
+
+ \ingroup qt-lighthouse-win
+*/
+
+QWindowsDrag::QWindowsDrag() : m_dropDataObject(0), m_dragBeingCancelled(false)
+{
+}
+
+QWindowsDrag::~QWindowsDrag()
+{
+}
+
+void QWindowsDrag::startDrag()
+{
+ // TODO: Accessibility handling?
+ QDragManager *dragManager = QDragManager::self();
+ QMimeData *dropData = dragManager->dropData();
+ m_dragBeingCancelled = false;
+
+ DWORD resultEffect;
+ QWindowsOleDropSource *windowDropSource = new QWindowsOleDropSource();
+ windowDropSource->createCursors();
+ QWindowsOleDataObject *dropDataObject = new QWindowsOleDataObject(dropData);
+ const Qt::DropActions possibleActions = dragManager->possible_actions;
+ const DWORD allowedEffects = translateToWinDragEffects(possibleActions);
+ if (QWindowsContext::verboseOLE)
+ qDebug(">%s possible Actions=%x, effects=0x%lx", __FUNCTION__,
+ int(possibleActions), allowedEffects);
+ const HRESULT r = DoDragDrop(dropDataObject, windowDropSource, allowedEffects, &resultEffect);
+ const DWORD reportedPerformedEffect = dropDataObject->reportedPerformedEffect();
+ Qt::DropAction ret = Qt::IgnoreAction;
+ if (r == DRAGDROP_S_DROP) {
+ if (reportedPerformedEffect == DROPEFFECT_MOVE && resultEffect != DROPEFFECT_MOVE) {
+ ret = Qt::TargetMoveAction;
+ resultEffect = DROPEFFECT_MOVE;
+ } else {
+ ret = translateToQDragDropAction(resultEffect);
+ }
+ // Force it to be a copy if an unsupported operation occurred.
+ // This indicates a bug in the drop target.
+ if (resultEffect != DROPEFFECT_NONE && !(resultEffect & allowedEffects))
+ ret = Qt::CopyAction;
+ } else {
+ dragManager->setCurrentTarget(0);
+ }
+
+ // clean up
+ dropDataObject->releaseQt();
+ dropDataObject->Release(); // Will delete obj if refcount becomes 0
+ windowDropSource->Release(); // Will delete src if refcount becomes 0
+ if (QWindowsContext::verboseOLE)
+ qDebug("<%s allowedEffects=0x%lx, reportedPerformedEffect=0x%lx, resultEffect=0x%lx, hr=0x%x, dropAction=%d",
+ __FUNCTION__, allowedEffects, reportedPerformedEffect, resultEffect, int(r), ret);
+}
+
+void QWindowsDrag::move(const QMouseEvent *me)
+{
+ const QPoint pos = me->pos();
+ if (QWindowsContext::verboseOLE)
+ qDebug("%s %d %d", __FUNCTION__, pos.x(), pos.y());
+}
+
+void QWindowsDrag::drop(const QMouseEvent *me)
+{
+ const QPoint pos = me->pos();
+ if (QWindowsContext::verboseOLE)
+ qDebug("%s %d %d", __FUNCTION__, pos.x(), pos.y());
+}
+
+void QWindowsDrag::cancel()
+{
+ // TODO: Accessibility handling?
+ if (QWindowsContext::verboseOLE)
+ qDebug("%s", __FUNCTION__);
+ m_dragBeingCancelled = true;
+}
+
+QWindowsDrag *QWindowsDrag::instance()
+{
+ return static_cast<QWindowsDrag *>(QWindowsIntegration::instance()->drag());
+}
+
+void QWindowsDrag::releaseDropDataObject()
+{
+ if (QWindowsContext::verboseOLE)
+ qDebug("%s %p", __FUNCTION__, m_dropDataObject);
+ if (m_dropDataObject) {
+ m_dropDataObject->Release();
+ m_dropDataObject = 0;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsdrag.h b/src/plugins/platforms/windows/qwindowsdrag.h
new file mode 100644
index 0000000000..6e6ebe0424
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsdrag.h
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSDRAG_H
+#define QWINDOWSDRAG_H
+
+#include "qwindowsinternalmimedata.h"
+
+#include <QtGui/QPlatformDrag>
+
+QT_BEGIN_NAMESPACE
+
+class QWindowsDropMimeData : public QWindowsInternalMimeData {
+public:
+ QWindowsDropMimeData() {}
+ virtual IDataObject *retrieveDataObject() const;
+};
+
+class QWindowsOleDropTarget : public IDropTarget
+{
+public:
+ explicit QWindowsOleDropTarget(QWindow *w);
+ virtual ~QWindowsOleDropTarget();
+
+ // IUnknown methods
+ STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppvObj);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+
+ // IDropTarget methods
+ STDMETHOD(DragEnter)(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect);
+ STDMETHOD(DragOver)(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect);
+ STDMETHOD(DragLeave)();
+ STDMETHOD(Drop)(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect);
+
+private:
+ inline QWindow *findDragOverWindow(const POINTL &pt) const;
+ void sendDragEnterEvent(QWindow *to, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect);
+
+ ULONG m_refs;
+ QWindow *const m_window;
+ QWindow *m_currentWindow;
+ QRect m_answerRect;
+ QPoint m_lastPoint;
+ DWORD m_chosenEffect;
+ DWORD m_lastKeyState;
+};
+
+class QWindowsDrag : public QPlatformDrag
+{
+public:
+ QWindowsDrag();
+ virtual ~QWindowsDrag();
+
+ virtual QMimeData *platformDropData() { return &m_dropData; }
+
+ virtual void startDrag();
+ virtual void move(const QMouseEvent *me);
+ virtual void drop(const QMouseEvent *me);
+ virtual void cancel();
+
+ static QWindowsDrag *instance();
+
+ IDataObject *dropDataObject() const { return m_dropDataObject; }
+ void setDropDataObject(IDataObject *dataObject) { m_dropDataObject = dataObject; }
+ void releaseDropDataObject();
+
+ bool dragBeingCancelled() const { return m_dragBeingCancelled; }
+
+private:
+ QWindowsDropMimeData m_dropData;
+ IDataObject *m_dropDataObject;
+ bool m_dragBeingCancelled;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSDRAG_H
diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp
new file mode 100644
index 0000000000..ea35ab5f9f
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp
@@ -0,0 +1,950 @@
+/****************************************************************************
+**
+** 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 "qwindowsfontdatabase.h"
+#include "qwindowscontext.h"
+#include "qwindowsfontengine.h"
+#include "qwindowsfontenginedirectwrite.h"
+#include "qtwindows_additional.h"
+
+#include <QtGui/QFont>
+#include <QtGui/QGuiApplication>
+
+#include <QtCore/qmath.h>
+#include <QtCore/QDebug>
+
+#if !defined(QT_NO_DIRECTWRITE)
+# include <dwrite.h>
+# include <d2d1.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \struct QWindowsFontEngineData
+ \brief Static constant data shared by the font engines.
+ \ingroup qt-lighthouse-win
+*/
+
+QWindowsFontEngineData::QWindowsFontEngineData()
+#if !defined(QT_NO_DIRECTWRITE)
+ : directWriteFactory(0)
+ , directWriteGdiInterop(0)
+#endif
+{
+ // from qapplication_win.cpp
+ UINT result = 0;
+ if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &result, 0))
+ clearTypeEnabled = (result == FE_FONTSMOOTHINGCLEARTYPE);
+
+ int winSmooth;
+ if (SystemParametersInfo(0x200C /* SPI_GETFONTSMOOTHINGCONTRAST */, 0, &winSmooth, 0)) {
+ fontSmoothingGamma = winSmooth / qreal(1000.0);
+ } else {
+ fontSmoothingGamma = 1.0;
+ }
+
+ // Safeguard ourselves against corrupt registry values...
+ if (fontSmoothingGamma > 5 || fontSmoothingGamma < 1)
+ fontSmoothingGamma = qreal(1.4);
+
+ const qreal gray_gamma = 2.31;
+ for (int i=0; i<256; ++i)
+ pow_gamma[i] = uint(qRound(qPow(i / qreal(255.), gray_gamma) * 2047));
+
+ HDC displayDC = GetDC(0);
+ hdc = CreateCompatibleDC(displayDC);
+ ReleaseDC(0, displayDC);
+}
+
+QWindowsFontEngineData::~QWindowsFontEngineData()
+{
+ if (hdc)
+ ReleaseDC(0, hdc);
+#if !defined(QT_NO_DIRECTWRITE)
+ if (directWriteGdiInterop)
+ directWriteGdiInterop->Release();
+ if (directWriteFactory)
+ directWriteFactory->Release();
+#endif
+}
+
+#if !defined(QT_NO_DIRECTWRITE)
+static inline bool initDirectWrite(QWindowsFontEngineData *d)
+{
+ if (!d->directWriteFactory) {
+ const HRESULT hr = DWriteCreateFactory(
+ DWRITE_FACTORY_TYPE_SHARED,
+ __uuidof(IDWriteFactory),
+ reinterpret_cast<IUnknown **>(&d->directWriteFactory)
+ );
+ if (FAILED(hr)) {
+ qErrnoWarning("%s: DWriteCreateFactory failed", __FUNCTION__);
+ return false;
+ }
+ }
+ if (!d->directWriteGdiInterop) {
+ const HRESULT hr = d->directWriteFactory->GetGdiInterop(&d->directWriteGdiInterop);
+ if (FAILED(hr)) {
+ qErrnoWarning("%s: GetGdiInterop failed", __FUNCTION__);
+ return false;
+ }
+ }
+ return true;
+}
+
+#endif // !defined(QT_NO_DIRECTWRITE)
+
+/*!
+ \class QWindowsFontDatabase
+ \brief Font database for Windows
+
+ \note The Qt 4.8 WIndows font database employed a mechanism of
+ delayed population of the database again passing a font name
+ to EnumFontFamiliesEx(), working around the fact that
+ EnumFontFamiliesEx() does not list all fonts by default.
+ This should be introduced to Lighthouse as well?
+
+ \ingroup qt-lighthouse-win
+*/
+
+QDebug operator<<(QDebug d, const QFontDef &def)
+{
+ d.nospace() << "Family=" << def.family << " Stylename=" << def.styleName
+ << " pointsize=" << def.pointSize << " pixelsize=" << def.pixelSize
+ << " styleHint=" << def.styleHint << " weight=" << def.weight
+ << " stretch=" << def.stretch << " hintingPreference="
+ << def.hintingPreference << ' ';
+ return d;
+}
+
+/* From QFontDatabase.cpp, qt_determine_writing_systems_from_truetype_bits().
+ * Fixme: Make public? */
+
+// see the Unicode subset bitfields in the MSDN docs
+static int requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = {
+ // Any,
+ { 127, 127 },
+ // Latin,
+ { 0, 127 },
+ // Greek,
+ { 7, 127 },
+ // Cyrillic,
+ { 9, 127 },
+ // Armenian,
+ { 10, 127 },
+ // Hebrew,
+ { 11, 127 },
+ // Arabic,
+ { 13, 127 },
+ // Syriac,
+ { 71, 127 },
+ //Thaana,
+ { 72, 127 },
+ //Devanagari,
+ { 15, 127 },
+ //Bengali,
+ { 16, 127 },
+ //Gurmukhi,
+ { 17, 127 },
+ //Gujarati,
+ { 18, 127 },
+ //Oriya,
+ { 19, 127 },
+ //Tamil,
+ { 20, 127 },
+ //Telugu,
+ { 21, 127 },
+ //Kannada,
+ { 22, 127 },
+ //Malayalam,
+ { 23, 127 },
+ //Sinhala,
+ { 73, 127 },
+ //Thai,
+ { 24, 127 },
+ //Lao,
+ { 25, 127 },
+ //Tibetan,
+ { 70, 127 },
+ //Myanmar,
+ { 74, 127 },
+ // Georgian,
+ { 26, 127 },
+ // Khmer,
+ { 80, 127 },
+ // SimplifiedChinese,
+ { 126, 127 },
+ // TraditionalChinese,
+ { 126, 127 },
+ // Japanese,
+ { 126, 127 },
+ // Korean,
+ { 56, 127 },
+ // Vietnamese,
+ { 0, 127 }, // same as latin1
+ // Other,
+ { 126, 127 },
+ // Ogham,
+ { 78, 127 },
+ // Runic,
+ { 79, 127 },
+ // Nko,
+ { 14, 127 },
+};
+
+enum
+{
+ SimplifiedChineseCsbBit = 18,
+ TraditionalChineseCsbBit = 20,
+ JapaneseCsbBit = 17,
+ KoreanCsbBit = 21
+};
+
+static inline void writingSystemsFromTrueTypeBits(quint32 unicodeRange[4],
+ quint32 codePageRange[2],
+ QSupportedWritingSystems *ws)
+{
+ bool hasScript = false;
+ for(int i = 0; i < QFontDatabase::WritingSystemsCount; i++) {
+ int bit = requiredUnicodeBits[i][0];
+ int index = bit/32;
+ int flag = 1 << (bit&31);
+ if (bit != 126 && unicodeRange[index] & flag) {
+ bit = requiredUnicodeBits[i][1];
+ index = bit/32;
+
+ flag = 1 << (bit&31);
+ if (bit == 127 || unicodeRange[index] & flag) {
+ ws->setSupported(QFontDatabase::WritingSystem(i), true);
+ hasScript = true;
+ }
+ }
+ }
+ if(codePageRange[0] & (1 << SimplifiedChineseCsbBit)) {
+ ws->setSupported(QFontDatabase::SimplifiedChinese, true);
+ hasScript = true;
+ }
+ if(codePageRange[0] & (1 << TraditionalChineseCsbBit)) {
+ ws->setSupported(QFontDatabase::TraditionalChinese, true);
+ hasScript = true;
+ }
+ if(codePageRange[0] & (1 << JapaneseCsbBit)) {
+ ws->setSupported(QFontDatabase::Japanese, true);
+ hasScript = true;
+ //qDebug("font %s supports Japanese", familyName.latin1());
+ }
+ if(codePageRange[0] & (1 << KoreanCsbBit)) {
+ ws->setSupported(QFontDatabase::Korean, true);
+ hasScript = true;
+ }
+ if (!hasScript)
+ ws->setSupported(QFontDatabase::Symbol, true);
+}
+
+// convert 0 ~ 1000 integer to QFont::Weight
+static inline QFont::Weight weightFromInteger(long weight)
+{
+ if (weight < 400)
+ return QFont::Light;
+ if (weight < 600)
+ return QFont::Normal;
+ if (weight < 700)
+ return QFont::DemiBold;
+ if (weight < 800)
+ return QFont::Bold;
+ return QFont::Black;
+}
+
+static inline QFontDatabase::WritingSystem writingSystemFromScript(const QString &scriptName)
+{
+ if (scriptName == QStringLiteral("Western")
+ || scriptName == QStringLiteral("Baltic")
+ || scriptName == QStringLiteral("Central European")
+ || scriptName == QStringLiteral("Turkish")
+ || scriptName == QStringLiteral("Vietnamese")
+ || scriptName == QStringLiteral("OEM/Dos"))
+ return QFontDatabase::Latin;
+ if (scriptName == QStringLiteral("Thai"))
+ return QFontDatabase::Thai;
+ if (scriptName == QStringLiteral("Symbol")
+ || scriptName == QStringLiteral("Other"))
+ return QFontDatabase::Symbol;
+ if (scriptName == QStringLiteral("CHINESE_GB2312"))
+ return QFontDatabase::SimplifiedChinese;
+ if (scriptName == QStringLiteral("CHINESE_BIG5"))
+ return QFontDatabase::TraditionalChinese;
+ if (scriptName == QStringLiteral("Cyrillic"))
+ return QFontDatabase::Cyrillic;
+ if (scriptName == QStringLiteral("Hangul"))
+ return QFontDatabase::Korean;
+ if (scriptName == QStringLiteral("Hebrew"))
+ return QFontDatabase::Hebrew;
+ if (scriptName == QStringLiteral("Greek"))
+ return QFontDatabase::Greek;
+ if (scriptName == QStringLiteral("Japanese"))
+ return QFontDatabase::Japanese;
+ if (scriptName == QStringLiteral("Arabic"))
+ return QFontDatabase::Arabic;
+ return QFontDatabase::Any;
+}
+
+static bool addFontToDatabase(QString familyName, const QString &scriptName,
+ const TEXTMETRIC *textmetric,
+ const FONTSIGNATURE *signature,
+ int type)
+{
+ // the "@family" fonts are just the same as "family". Ignore them.
+ if (familyName.at(0) == QLatin1Char('@') || familyName.startsWith(QStringLiteral("WST_")))
+ return false;
+
+ static const int SMOOTH_SCALABLE = 0xffff;
+ const QString foundryName; // No such concept.
+ const NEWTEXTMETRIC *tm = (NEWTEXTMETRIC *)textmetric;
+ const bool fixed = !(tm->tmPitchAndFamily & TMPF_FIXED_PITCH);
+ const bool ttf = (tm->tmPitchAndFamily & TMPF_TRUETYPE);
+ const bool scalable = tm->tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE);
+ const int size = scalable ? SMOOTH_SCALABLE : tm->tmHeight;
+ const QFont::Style style = tm->tmItalic ? QFont::StyleItalic : QFont::StyleNormal;
+ const bool antialias = false;
+ const QFont::Weight weight = weightFromInteger(tm->tmWeight);
+ const QFont::Stretch stretch = QFont::Unstretched;
+
+ Q_UNUSED(fixed)
+
+ if (QWindowsContext::verboseFonts > 2) {
+ QDebug nospace = qDebug().nospace();
+ nospace << __FUNCTION__ << familyName << scriptName
+ << "TTF=" << ttf;
+ if (type & DEVICE_FONTTYPE)
+ nospace << " DEVICE";
+ if (type & RASTER_FONTTYPE)
+ nospace << " RASTER";
+ if (type & TRUETYPE_FONTTYPE)
+ nospace << " TRUETYPE";
+ nospace << " scalable=" << scalable << " Size=" << size
+ << " Style=" << style << " Weight=" << weight
+ << " stretch=" << stretch;
+ }
+
+/* Fixme: omitted for the moment
+ if(ttf && localizedName(familyName) && family->english_name.isEmpty())
+ family->english_name = getEnglishName(familyName);
+*/
+ QSupportedWritingSystems writingSystems;
+ if (type & TRUETYPE_FONTTYPE) {
+ quint32 unicodeRange[4] = {
+ signature->fsUsb[0], signature->fsUsb[1],
+ signature->fsUsb[2], signature->fsUsb[3]
+ };
+ quint32 codePageRange[2] = {
+ signature->fsCsb[0], signature->fsCsb[1]
+ };
+ writingSystemsFromTrueTypeBits(unicodeRange, codePageRange, &writingSystems);
+ // ### Hack to work around problem with Thai text on Windows 7. Segoe UI contains
+ // the symbol for Baht, and Windows thus reports that it supports the Thai script.
+ // Since it's the default UI font on this platform, most widgets will be unable to
+ // display Thai text by default. As a temporary work around, we special case Segoe UI
+ // and remove the Thai script from its list of supported writing systems.
+ if (writingSystems.supported(QFontDatabase::Thai) &&
+ familyName == QStringLiteral("Segoe UI"))
+ writingSystems.setSupported(QFontDatabase::Thai, false);
+ } else {
+ const QFontDatabase::WritingSystem ws = writingSystemFromScript(scriptName);
+ if (ws != QFontDatabase::Any)
+ writingSystems.setSupported(ws);
+ }
+
+ QPlatformFontDatabase::registerFont(familyName, foundryName, weight,
+ style, stretch, antialias, scalable, size, writingSystems, 0);
+ // add fonts windows can generate for us:
+ if (weight <= QFont::DemiBold)
+ QPlatformFontDatabase::registerFont(familyName, foundryName, QFont::Bold,
+ style, stretch, antialias, scalable, size, writingSystems, 0);
+ if (style != QFont::StyleItalic)
+ QPlatformFontDatabase::registerFont(familyName, foundryName, weight,
+ QFont::StyleItalic, stretch, antialias, scalable, size, writingSystems, 0);
+ if (weight <= QFont::DemiBold && style != QFont::StyleItalic)
+ QPlatformFontDatabase::registerFont(familyName, foundryName, QFont::Bold,
+ QFont::StyleItalic, stretch, antialias, scalable, size, writingSystems, 0);
+ return true;
+}
+
+static int CALLBACK storeFont(ENUMLOGFONTEX* f, NEWTEXTMETRICEX *textmetric,
+ int type, LPARAM namesSetIn)
+{
+ typedef QSet<QString> StringSet;
+ const QString familyName = QString::fromWCharArray(f->elfLogFont.lfFaceName);
+ const QString script = QString::fromWCharArray(f->elfScript);
+
+ const FONTSIGNATURE signature = textmetric->ntmFontSig;
+
+ // NEWTEXTMETRICEX is a NEWTEXTMETRIC, which according to the documentation is
+ // identical to a TEXTMETRIC except for the last four members, which we don't use
+ // anyway
+ if (addFontToDatabase(familyName, script, (TEXTMETRIC *)textmetric, &signature, type))
+ reinterpret_cast<StringSet *>(namesSetIn)->insert(familyName);
+
+ // keep on enumerating
+ return 1;
+}
+
+void QWindowsFontDatabase::populateFontDatabase()
+{
+ if (m_families.isEmpty()) {
+ QPlatformFontDatabase::populateFontDatabase();
+ populate(); // Called multiple times.
+ // Work around EnumFontFamiliesEx() not listing the system font, see below.
+ const QString sysFontFamily = QGuiApplication::font().family();
+ if (!m_families.contains(sysFontFamily))
+ populate(sysFontFamily);
+ }
+}
+
+/*!
+ \brief Populate font database using EnumFontFamiliesEx().
+
+ Normally, leaving the name empty should enumerate
+ all fonts, however, system fonts like "MS Shell Dlg 2"
+ are only found when specifying the name explicitly.
+*/
+
+void QWindowsFontDatabase::populate(const QString &family)
+ {
+
+ if (QWindowsContext::verboseFonts)
+ qDebug() << __FUNCTION__ << m_families.size() << family;
+
+ HDC dummy = GetDC(0);
+ LOGFONT lf;
+ lf.lfCharSet = DEFAULT_CHARSET;
+ if (family.size() >= LF_FACESIZE) {
+ qWarning("%s: Unable to enumerate family '%s'.",
+ __FUNCTION__, qPrintable(family));
+ return;
+ }
+ wmemcpy(lf.lfFaceName, reinterpret_cast<const wchar_t*>(family.utf16()),
+ family.size() + 1);
+ lf.lfPitchAndFamily = 0;
+ EnumFontFamiliesEx(dummy, &lf, (FONTENUMPROC)storeFont,
+ (LPARAM)&m_families, 0);
+ ReleaseDC(0, dummy);
+}
+
+QWindowsFontDatabase::QWindowsFontDatabase() :
+ m_fontEngineData(new QWindowsFontEngineData)
+{
+ if (QWindowsContext::verboseFonts)
+ qDebug() << __FUNCTION__ << "Clear type: "
+ << m_fontEngineData->clearTypeEnabled << "gamma: "
+ << m_fontEngineData->fontSmoothingGamma;
+}
+
+QWindowsFontDatabase::~QWindowsFontDatabase()
+{
+}
+
+QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef,
+ QUnicodeTables::Script script,
+ void *handle)
+{
+ QFontEngine *fe = QWindowsFontDatabase::createEngine(script, fontDef,
+ 0, QWindowsContext::instance()->defaultDPI(), false,
+ QStringList(), m_fontEngineData);
+ if (QWindowsContext::verboseFonts)
+ qDebug() << __FUNCTION__ << "FONTDEF" << fontDef << script << fe << handle;
+ return fe;
+}
+
+QFontEngine *QWindowsFontDatabase::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
+{
+ QFontEngine *fe = QPlatformFontDatabase::fontEngine(fontData, pixelSize, hintingPreference);
+ if (QWindowsContext::verboseFonts)
+ qDebug() << __FUNCTION__ << "FONTDATA" << fontData << pixelSize << hintingPreference << fe;
+ return fe;
+}
+
+QStringList QWindowsFontDatabase::fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const
+{
+ QStringList result = QPlatformFontDatabase::fallbacksForFamily(family, style, styleHint, script);
+ if (!result.isEmpty())
+ return result;
+ if (QWindowsContext::verboseFonts)
+ qDebug() << __FUNCTION__ << family << style << styleHint
+ << script << result << m_families.size();
+ return result;
+}
+
+QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName)
+{
+ const QStringList result = QPlatformFontDatabase::addApplicationFont(fontData, fileName);
+ Q_UNIMPLEMENTED();
+ return result;
+}
+
+void QWindowsFontDatabase::releaseHandle(void *handle)
+{
+ if (handle && QWindowsContext::verboseFonts)
+ qDebug() << __FUNCTION__ << handle;
+}
+
+QString QWindowsFontDatabase::fontDir() const
+{
+ const QString result = QPlatformFontDatabase::fontDir();
+ if (QWindowsContext::verboseFonts)
+ qDebug() << __FUNCTION__ << result;
+ return result;
+}
+
+HFONT QWindowsFontDatabase::systemFont()
+{
+ static const HFONT stock_sysfont = (HFONT)GetStockObject(SYSTEM_FONT);
+ return stock_sysfont;
+}
+
+// Creation functions
+
+static inline bool scriptRequiresOpenType(int script)
+{
+ return ((script >= QUnicodeTables::Syriac && script <= QUnicodeTables::Sinhala)
+ || script == QUnicodeTables::Khmer || script == QUnicodeTables::Nko);
+}
+
+static const char *other_tryFonts[] = {
+ "Arial",
+ "MS UI Gothic",
+ "Gulim",
+ "SimSun",
+ "PMingLiU",
+ "Arial Unicode MS",
+ 0
+};
+
+static const char *jp_tryFonts [] = {
+ "MS UI Gothic",
+ "Arial",
+ "Gulim",
+ "SimSun",
+ "PMingLiU",
+ "Arial Unicode MS",
+ 0
+};
+
+static const char *ch_CN_tryFonts [] = {
+ "SimSun",
+ "Arial",
+ "PMingLiU",
+ "Gulim",
+ "MS UI Gothic",
+ "Arial Unicode MS",
+ 0
+};
+
+static const char *ch_TW_tryFonts [] = {
+ "PMingLiU",
+ "Arial",
+ "SimSun",
+ "Gulim",
+ "MS UI Gothic",
+ "Arial Unicode MS",
+ 0
+};
+
+static const char *kr_tryFonts[] = {
+ "Gulim",
+ "Arial",
+ "PMingLiU",
+ "SimSun",
+ "MS UI Gothic",
+ "Arial Unicode MS",
+ 0
+};
+
+static const char **tryFonts = 0;
+
+QFontEngine *QWindowsFontDatabase::createEngine(int script, const QFontDef &request,
+ HDC fontHdc, int dpi, bool rawMode,
+ const QStringList &family_list,
+ const QSharedPointer<QWindowsFontEngineData> &data)
+{
+ LOGFONT lf;
+ memset(&lf, 0, sizeof(LOGFONT));
+
+ const bool useDevice = (request.styleStrategy & QFont::PreferDevice) && fontHdc;
+
+ const HDC hdc = useDevice ? fontHdc : data->hdc;
+
+ bool stockFont = false;
+ bool preferClearTypeAA = false;
+
+ HFONT hfont = 0;
+
+#if !defined(QT_NO_DIRECTWRITE)
+ bool useDirectWrite = (request.hintingPreference == QFont::PreferNoHinting)
+ || (request.hintingPreference == QFont::PreferVerticalHinting);
+ IDWriteFont *directWriteFont = 0;
+#else
+ bool useDirectWrite = false;
+#endif
+
+ if (rawMode) { // will choose a stock font
+ int f = SYSTEM_FONT;
+ const QString fam = request.family.toLower();
+ if (fam == QStringLiteral("default") || fam == QStringLiteral("system"))
+ f = SYSTEM_FONT;
+ else if (fam == QStringLiteral("system_fixed"))
+ f = SYSTEM_FIXED_FONT;
+ else if (fam == QStringLiteral("ansi_fixed"))
+ f = ANSI_FIXED_FONT;
+ else if (fam == QStringLiteral("ansi_var"))
+ f = ANSI_VAR_FONT;
+ else if (fam == QStringLiteral("device_default"))
+ f = DEVICE_DEFAULT_FONT;
+ else if (fam == QStringLiteral("oem_fixed"))
+ f = OEM_FIXED_FONT;
+ else if (fam.at(0) == QLatin1Char('#'))
+ f = fam.right(fam.length()-1).toInt();
+ hfont = (HFONT)GetStockObject(f);
+ if (!hfont) {
+ qErrnoWarning("%s: GetStockObject failed", __FUNCTION__);
+ hfont = QWindowsFontDatabase::systemFont();
+ }
+ stockFont = true;
+ } else {
+ int hint = FF_DONTCARE;
+ switch (request.styleHint) {
+ case QFont::Helvetica:
+ hint = FF_SWISS;
+ break;
+ case QFont::Times:
+ hint = FF_ROMAN;
+ break;
+ case QFont::Courier:
+ hint = FF_MODERN;
+ break;
+ case QFont::OldEnglish:
+ hint = FF_DECORATIVE;
+ break;
+ case QFont::System:
+ hint = FF_MODERN;
+ break;
+ default:
+ break;
+ }
+
+ lf.lfHeight = -qRound(request.pixelSize);
+ lf.lfWidth = 0;
+ lf.lfEscapement = 0;
+ lf.lfOrientation = 0;
+ if (request.weight == 50)
+ lf.lfWeight = FW_DONTCARE;
+ else
+ lf.lfWeight = (request.weight*900)/99;
+ lf.lfItalic = request.style != QFont::StyleNormal;
+ lf.lfCharSet = DEFAULT_CHARSET;
+
+ int strat = OUT_DEFAULT_PRECIS;
+ if (request.styleStrategy & QFont::PreferBitmap) {
+ strat = OUT_RASTER_PRECIS;
+ } else if (request.styleStrategy & QFont::PreferDevice) {
+ strat = OUT_DEVICE_PRECIS;
+ } else if (request.styleStrategy & QFont::PreferOutline) {
+ strat = OUT_OUTLINE_PRECIS;
+ } else if (request.styleStrategy & QFont::ForceOutline) {
+ strat = OUT_TT_ONLY_PRECIS;
+ }
+
+ lf.lfOutPrecision = strat;
+
+ int qual = DEFAULT_QUALITY;
+
+ if (request.styleStrategy & QFont::PreferMatch)
+ qual = DRAFT_QUALITY;
+ else if (request.styleStrategy & QFont::PreferQuality)
+ qual = PROOF_QUALITY;
+
+ if (request.styleStrategy & QFont::PreferAntialias) {
+ if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP) {
+ qual = CLEARTYPE_QUALITY;
+ preferClearTypeAA = true;
+ } else {
+ qual = ANTIALIASED_QUALITY;
+ }
+ } else if (request.styleStrategy & QFont::NoAntialias) {
+ qual = NONANTIALIASED_QUALITY;
+ }
+
+ lf.lfQuality = qual;
+
+ lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lf.lfPitchAndFamily = DEFAULT_PITCH | hint;
+
+ QString fam = request.family;
+
+ if(fam.isEmpty())
+ fam = QStringLiteral("MS Sans Serif");
+
+ if ((fam == QStringLiteral("MS Sans Serif"))
+ && (request.style == QFont::StyleItalic || (-lf.lfHeight > 18 && -lf.lfHeight != 24))) {
+ fam = QStringLiteral("Arial"); // MS Sans Serif has bearing problems in italic, and does not scale
+ }
+ if (fam == QStringLiteral("Courier") && !(request.styleStrategy & QFont::PreferBitmap))
+ fam = QStringLiteral("Courier New");
+
+ memcpy(lf.lfFaceName, fam.utf16(), sizeof(wchar_t) * qMin(fam.length() + 1, 32)); // 32 = Windows hard-coded
+
+ hfont = CreateFontIndirect(&lf);
+ if (!hfont)
+ qErrnoWarning("%s: CreateFontIndirect failed", __FUNCTION__);
+
+ stockFont = (hfont == 0);
+ bool ttf = false;
+ int avWidth = 0;
+ BOOL res;
+ HGDIOBJ oldObj = SelectObject(hdc, hfont);
+
+ TEXTMETRIC tm;
+ res = GetTextMetrics(hdc, &tm);
+ avWidth = tm.tmAveCharWidth;
+ ttf = tm.tmPitchAndFamily & TMPF_TRUETYPE;
+ SelectObject(hdc, oldObj);
+
+ if (!ttf || !useDirectWrite) {
+ useDirectWrite = false;
+
+ if (hfont && (!ttf || request.stretch != 100)) {
+ DeleteObject(hfont);
+ if (!res)
+ qErrnoWarning("QFontEngine::loadEngine: GetTextMetrics failed");
+ lf.lfWidth = avWidth * request.stretch/100;
+ hfont = CreateFontIndirect(&lf);
+ if (!hfont)
+ qErrnoWarning("%s: CreateFontIndirect with stretch failed", __FUNCTION__);
+ }
+
+ if (hfont == 0) {
+ hfont = (HFONT)GetStockObject(ANSI_VAR_FONT);
+ stockFont = true;
+ }
+ }
+
+#if !defined(QT_NO_DIRECTWRITE)
+ else {
+ // Default to false for DirectWrite (and re-enable once/if everything
+ // turns out okay)
+ useDirectWrite = false;
+ if (initDirectWrite(data.data())) {
+ const QString nameSubstitute = QWindowsFontEngineDirectWrite::fontNameSubstitute(QString::fromWCharArray(lf.lfFaceName));
+ memcpy(lf.lfFaceName, nameSubstitute.utf16(),
+ sizeof(wchar_t) * qMin(nameSubstitute.length() + 1, LF_FACESIZE));
+
+ HRESULT hr = data->directWriteGdiInterop->CreateFontFromLOGFONT(
+ &lf,
+ &directWriteFont);
+ if (FAILED(hr)) {
+ qErrnoWarning("%s: CreateFontFromLOGFONT failed", __FUNCTION__);
+ } else {
+ DeleteObject(hfont);
+ useDirectWrite = true;
+ }
+ }
+ }
+#endif
+ }
+
+ QFontEngine *fe = 0;
+ if (!useDirectWrite) {
+ QWindowsFontEngine *few = new QWindowsFontEngine(request.family, hfont, stockFont, lf, data);
+ few->setObjectName(QStringLiteral("QWindowsFontEngine_") + request.family);
+ if (preferClearTypeAA)
+ few->glyphFormat = QFontEngineGlyphCache::Raster_RGBMask;
+
+ // Also check for OpenType tables when using complex scripts
+ // ### TODO: This only works for scripts that require OpenType. More generally
+ // for scripts that do not require OpenType we should just look at the list of
+ // supported writing systems in the font's OS/2 table.
+ if (scriptRequiresOpenType(script)) {
+ HB_Face hbFace = few->harfbuzzFace();
+ if (!hbFace || !hbFace->supported_scripts[script]) {
+ qWarning(" OpenType support missing for script\n");
+ delete few;
+ return 0;
+ }
+ }
+
+ few->initFontInfo(request, fontHdc, dpi);
+ fe = few;
+ }
+
+#if !defined(QT_NO_DIRECTWRITE)
+ else {
+ IDWriteFontFace *directWriteFontFace = NULL;
+ HRESULT hr = directWriteFont->CreateFontFace(&directWriteFontFace);
+ if (SUCCEEDED(hr)) {
+ QWindowsFontEngineDirectWrite *fedw = new QWindowsFontEngineDirectWrite(directWriteFontFace,
+ request.pixelSize,
+ data);
+ fedw->initFontInfo(request, dpi, directWriteFont);
+ fedw->setObjectName(QStringLiteral("QWindowsFontEngineDirectWrite_") + request.family);
+ fe = fedw;
+ } else {
+ qErrnoWarning("%s: CreateFontFace failed", __FUNCTION__);
+ }
+ }
+
+ if (directWriteFont != 0)
+ directWriteFont->Release();
+#endif
+
+ if(script == QUnicodeTables::Common
+ && !(request.styleStrategy & QFont::NoFontMerging)) {
+ QFontDatabase db;
+ if (!db.writingSystems(request.family).contains(QFontDatabase::Symbol)) {
+ if(!tryFonts) {
+ LANGID lid = GetUserDefaultLangID();
+ switch( lid&0xff ) {
+ case LANG_CHINESE: // Chinese (Taiwan)
+ if ( lid == 0x0804 ) // Taiwan
+ tryFonts = ch_TW_tryFonts;
+ else
+ tryFonts = ch_CN_tryFonts;
+ break;
+ case LANG_JAPANESE:
+ tryFonts = jp_tryFonts;
+ break;
+ case LANG_KOREAN:
+ tryFonts = kr_tryFonts;
+ break;
+ default:
+ tryFonts = other_tryFonts;
+ break;
+ }
+ }
+ QStringList fm = QFontDatabase().families();
+ QStringList list = family_list;
+ const char **tf = tryFonts;
+ while(tf && *tf) {
+ if(fm.contains(QLatin1String(*tf)))
+ list << QLatin1String(*tf);
+ ++tf;
+ }
+ QFontEngine *mfe = new QWindowsMultiFontEngine(fe, list);
+ mfe->setObjectName(QStringLiteral("QWindowsMultiFontEngine_") + request.family);
+ mfe->fontDef = fe->fontDef;
+ fe = mfe;
+ }
+ }
+ return fe;
+}
+
+static inline int verticalDPI()
+{
+ return GetDeviceCaps(QWindowsContext::instance()->displayContext(), LOGPIXELSY);
+}
+
+QFont QWindowsFontDatabase::defaultFont() const
+{
+ LOGFONT lf;
+ GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(lf), &lf);
+ QFont systemFont = QWindowsFontDatabase::LOGFONT_to_QFont(lf);
+ // "MS Shell Dlg 2" is the correct system font >= Win2k
+ if (systemFont.family() == QStringLiteral("MS Shell Dlg"))
+ systemFont.setFamily(QStringLiteral("MS Shell Dlg 2"));
+ if (QWindowsContext::verboseFonts)
+ qDebug() << __FUNCTION__ << systemFont;
+ return systemFont;
+}
+
+QHash<QByteArray, QFont> QWindowsFontDatabase::defaultFonts() const
+{
+ QHash<QByteArray, QFont> result;
+ NONCLIENTMETRICS ncm;
+ ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICS, lfMessageFont) + sizeof(LOGFONT);
+ SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize , &ncm, 0);
+
+ const int verticalRes = verticalDPI();
+
+ const QFont menuFont = LOGFONT_to_QFont(ncm.lfMenuFont, verticalRes);
+ const QFont messageFont = LOGFONT_to_QFont(ncm.lfMessageFont, verticalRes);
+ const QFont statusFont = LOGFONT_to_QFont(ncm.lfStatusFont, verticalRes);
+ const QFont titleFont = LOGFONT_to_QFont(ncm.lfCaptionFont, verticalRes);
+
+ LOGFONT lfIconTitleFont;
+ SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0);
+ const QFont iconTitleFont = LOGFONT_to_QFont(lfIconTitleFont, verticalRes);
+
+ result.insert(QByteArray("QMenu"), menuFont);
+ result.insert(QByteArray("QMenuBar"), menuFont);
+ result.insert(QByteArray("QMessageBox"), messageFont);
+ result.insert(QByteArray("QTipLabel"), statusFont);
+ result.insert(QByteArray("QStatusBar"), statusFont);
+ result.insert(QByteArray("Q3TitleBar"), titleFont);
+ result.insert(QByteArray("QWorkspaceTitleBar"), titleFont);
+ result.insert(QByteArray("QAbstractItemView"), iconTitleFont);
+ result.insert(QByteArray("QDockWidgetTitle"), iconTitleFont);
+ if (QWindowsContext::verboseFonts) {
+ typedef QHash<QByteArray, QFont>::const_iterator CIT;
+ QDebug nsp = qDebug().nospace();
+ nsp << __FUNCTION__ << " DPI=" << verticalRes << "\n";
+ const CIT cend = result.constEnd();
+ for (CIT it = result.constBegin(); it != cend; ++it)
+ nsp << it.key() << ' ' << it.value() << '\n';
+ }
+ return result;
+}
+
+QFont QWindowsFontDatabase::LOGFONT_to_QFont(const LOGFONT& logFont, int verticalDPI_In)
+{
+ if (verticalDPI_In <= 0)
+ verticalDPI_In = verticalDPI();
+ QFont qFont(QString::fromWCharArray(logFont.lfFaceName));
+ qFont.setItalic(logFont.lfItalic);
+ if (logFont.lfWeight != FW_DONTCARE)
+ qFont.setWeight(weightFromInteger(logFont.lfWeight));
+ const qreal logFontHeight = qAbs(logFont.lfHeight);
+ qFont.setPointSizeF(logFontHeight * 72.0 / qreal(verticalDPI_In));
+ qFont.setUnderline(false);
+ qFont.setOverline(false);
+ qFont.setStrikeOut(false);
+ return qFont;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.h b/src/plugins/platforms/windows/qwindowsfontdatabase.h
new file mode 100644
index 0000000000..a80482f6e2
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsfontdatabase.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSFONTDATABASE_H
+#define QWINDOWSFONTDATABASE_H
+
+#include <QtGui/QPlatformFontDatabase>
+#include <QtCore/QSharedPointer>
+#include "qtwindows_additional.h"
+
+QT_BEGIN_NAMESPACE
+
+#if !defined(QT_NO_DIRECTWRITE)
+ struct IDWriteFactory;
+ struct IDWriteGdiInterop;
+#endif
+
+class QWindowsFontEngineData
+{
+ Q_DISABLE_COPY(QWindowsFontEngineData)
+public:
+ QWindowsFontEngineData();
+ ~QWindowsFontEngineData();
+
+ uint pow_gamma[256];
+
+ bool clearTypeEnabled;
+ qreal fontSmoothingGamma;
+ HDC hdc;
+#if !defined(QT_NO_DIRECTWRITE)
+ IDWriteFactory *directWriteFactory;
+ IDWriteGdiInterop *directWriteGdiInterop;
+#endif
+};
+
+class QWindowsFontDatabase : public QPlatformFontDatabase
+{
+public:
+ QWindowsFontDatabase();
+ ~QWindowsFontDatabase();
+
+ virtual void populateFontDatabase();
+ virtual QFontEngine *fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *handle);
+ virtual QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference);
+ virtual QStringList fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const;
+ virtual QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName);
+ virtual void releaseHandle(void *handle);
+ virtual QString fontDir() const;
+
+ virtual QFont defaultFont() const;
+ virtual QHash<QByteArray, QFont> defaultFonts() const;
+
+ static QFontEngine *createEngine(int script, const QFontDef &request,
+ HDC fontHdc, int dpi, bool rawMode,
+ const QStringList &family_list,
+ const QSharedPointer<QWindowsFontEngineData> &data);
+
+ static HFONT systemFont();
+ static QFont LOGFONT_to_QFont(const LOGFONT& lf, int verticalDPI = 0);
+
+private:
+ void populate(const QString &family = QString());
+ QSharedPointer<QWindowsFontEngineData> m_fontEngineData;
+ QSet<QString> m_families;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSFONTDATABASE_H
diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp
new file mode 100644
index 0000000000..80d9ed4686
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp
@@ -0,0 +1,1223 @@
+/****************************************************************************
+**
+** 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 QtGui module 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$
+**
+****************************************************************************/
+
+#if _WIN32_WINNT < 0x0500
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+
+#include "qwindowsfontengine.h"
+#include "qwindowsnativeimage.h"
+#include "qwindowscontext.h"
+#include "qwindowsfontdatabase.h"
+#include "qtwindows_additional.h"
+
+#include <QtGui/private/qtextengine_p.h> // glyph_metrics_t
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/QPaintDevice>
+#include <QtGui/QBitmap>
+#include <QtGui/QPainter>
+#include <QtGui/private/qpainter_p.h>
+#include <QtGui/QPaintEngine>
+#include <QtGui/private/qpaintengine_raster_p.h>
+
+#include <QtCore/QtEndian>
+#include <QtCore/qmath.h>
+#include <QtCore/QThreadStorage>
+#include <QtCore/private/qsystemlibrary_p.h>
+
+#include <QtCore/private/qunicodetables_p.h>
+#include <QtCore/QDebug>
+
+#include <limits.h>
+
+QT_BEGIN_NAMESPACE
+
+//### mingw needed define
+#ifndef TT_PRIM_CSPLINE
+#define TT_PRIM_CSPLINE 3
+#endif
+
+#ifdef MAKE_TAG
+#undef MAKE_TAG
+#endif
+// GetFontData expects the tags in little endian ;(
+#define MAKE_TAG(ch1, ch2, ch3, ch4) (\
+ (((quint32)(ch4)) << 24) | \
+ (((quint32)(ch3)) << 16) | \
+ (((quint32)(ch2)) << 8) | \
+ ((quint32)(ch1)) \
+ )
+
+// common DC for all fonts
+
+QT_BEGIN_NAMESPACE
+
+typedef BOOL (WINAPI *PtrGetCharWidthI)(HDC, UINT, UINT, LPWORD, LPINT);
+static PtrGetCharWidthI ptrGetCharWidthI = 0;
+static bool resolvedGetCharWidthI = false;
+
+static void resolveGetCharWidthI()
+{
+ if (resolvedGetCharWidthI)
+ return;
+ resolvedGetCharWidthI = true;
+ ptrGetCharWidthI = (PtrGetCharWidthI)QSystemLibrary::resolve(QStringLiteral("gdi32"), "GetCharWidthI");
+}
+
+// defined in qtextengine_win.cpp
+typedef void *SCRIPT_CACHE;
+typedef HRESULT (WINAPI *fScriptFreeCache)(SCRIPT_CACHE *);
+extern fScriptFreeCache ScriptFreeCache;
+
+static inline quint32 getUInt(unsigned char *p)
+{
+ quint32 val;
+ val = *p++ << 24;
+ val |= *p++ << 16;
+ val |= *p++ << 8;
+ val |= *p;
+
+ return val;
+}
+
+static inline quint16 getUShort(unsigned char *p)
+{
+ quint16 val;
+ val = *p++ << 8;
+ val |= *p;
+
+ return val;
+}
+
+// general font engine
+
+QFixed QWindowsFontEngine::lineThickness() const
+{
+ if(lineWidth > 0)
+ return lineWidth;
+
+ return QFontEngine::lineThickness();
+}
+
+static OUTLINETEXTMETRIC *getOutlineTextMetric(HDC hdc)
+{
+ int size;
+ size = GetOutlineTextMetrics(hdc, 0, 0);
+ OUTLINETEXTMETRIC *otm = (OUTLINETEXTMETRIC *)malloc(size);
+ GetOutlineTextMetrics(hdc, size, otm);
+ return otm;
+}
+
+void QWindowsFontEngine::getCMap()
+{
+ ttf = (bool)(tm.tmPitchAndFamily & TMPF_TRUETYPE);
+ HDC hdc = m_fontEngineData->hdc;
+ SelectObject(hdc, hfont);
+ bool symb = false;
+ if (ttf) {
+ cmapTable = getSfntTable(qbswap<quint32>(MAKE_TAG('c', 'm', 'a', 'p')));
+ int size = 0;
+ cmap = QFontEngine::getCMap(reinterpret_cast<const uchar *>(cmapTable.constData()),
+ cmapTable.size(), &symb, &size);
+ }
+ if (!cmap) {
+ ttf = false;
+ symb = false;
+ }
+ symbol = symb;
+ designToDevice = 1;
+ _faceId.index = 0;
+ if(cmap) {
+ OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc);
+ designToDevice = QFixed((int)otm->otmEMSquare)/int(otm->otmTextMetrics.tmHeight);
+ unitsPerEm = otm->otmEMSquare;
+ x_height = (int)otm->otmsXHeight;
+ loadKerningPairs(designToDevice);
+ _faceId.filename = QString::fromWCharArray((wchar_t *)((char *)otm + (quintptr)otm->otmpFullName)).toLatin1();
+ lineWidth = otm->otmsUnderscoreSize;
+ fsType = otm->otmfsType;
+ free(otm);
+ } else {
+ unitsPerEm = tm.tmHeight;
+ }
+}
+
+
+inline unsigned int getChar(const QChar *str, int &i, const int len)
+{
+ unsigned int uc = str[i].unicode();
+ if (uc >= 0xd800 && uc < 0xdc00 && i < len-1) {
+ uint low = str[i+1].unicode();
+ if (low >= 0xdc00 && low < 0xe000) {
+ uc = (uc - 0xd800)*0x400 + (low - 0xdc00) + 0x10000;
+ ++i;
+ }
+ }
+ return uc;
+}
+
+int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLayout *glyphs, bool mirrored) const
+{
+ int i = 0;
+ int glyph_pos = 0;
+ if (mirrored) {
+ if (symbol) {
+ for (; i < numChars; ++i, ++glyph_pos) {
+ unsigned int uc = getChar(str, i, numChars);
+ glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
+ if (!glyphs->glyphs[glyph_pos] && uc < 0x100)
+ glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
+ }
+ } else if (ttf) {
+ for (; i < numChars; ++i, ++glyph_pos) {
+ unsigned int uc = getChar(str, i, numChars);
+ glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, QChar::mirroredChar(uc));
+ }
+ } else {
+ wchar_t first = tm.tmFirstChar;
+ wchar_t last = tm.tmLastChar;
+
+ for (; i < numChars; ++i, ++glyph_pos) {
+ uint ucs = QChar::mirroredChar(getChar(str, i, numChars));
+ if (ucs >= first && ucs <= last)
+ glyphs->glyphs[glyph_pos] = ucs;
+ else
+ glyphs->glyphs[glyph_pos] = 0;
+ }
+ }
+ } else {
+ if (symbol) {
+ for (; i < numChars; ++i, ++glyph_pos) {
+ unsigned int uc = getChar(str, i, numChars);
+ glyphs->glyphs[i] = getTrueTypeGlyphIndex(cmap, uc);
+ if(!glyphs->glyphs[glyph_pos] && uc < 0x100)
+ glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
+ }
+ } else if (ttf) {
+ for (; i < numChars; ++i, ++glyph_pos) {
+ unsigned int uc = getChar(str, i, numChars);
+ glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
+ }
+ } else {
+ wchar_t first = tm.tmFirstChar;
+ wchar_t last = tm.tmLastChar;
+
+ for (; i < numChars; ++i, ++glyph_pos) {
+ uint uc = getChar(str, i, numChars);
+ if (uc >= first && uc <= last)
+ glyphs->glyphs[glyph_pos] = uc;
+ else
+ glyphs->glyphs[glyph_pos] = 0;
+ }
+ }
+ }
+ glyphs->numGlyphs = glyph_pos;
+ return glyph_pos;
+}
+
+/*!
+ \class QWindowsFontEngine
+ \brief Standard Windows font engine.
+ \ingroup qt-lighthouse-win
+
+ Will probably be superseded by a common Free Type font engine in Qt 5.X.
+*/
+
+QWindowsFontEngine::QWindowsFontEngine(const QString &name,
+ HFONT _hfont, bool stockFontIn, LOGFONT lf,
+ QSharedPointer<QWindowsFontEngineData> fontEngineData) :
+ m_fontEngineData(fontEngineData),
+ _name(name),
+ hfont(_hfont),
+ m_logfont(lf),
+ stockFont(stockFontIn),
+ ttf(0),
+ hasOutline(0),
+ lw(0),
+ cmap(0),
+ lbearing(SHRT_MIN),
+ rbearing(SHRT_MIN),
+ x_height(-1),
+ synthesized_flags(-1),
+ lineWidth(-1),
+ widthCache(0),
+ widthCacheSize(0),
+ designAdvances(0),
+ designAdvancesSize(0)
+{
+ if (QWindowsContext::verboseFonts)
+ qDebug("%s: font='%s', size=%ld", __FUNCTION__, qPrintable(name), lf.lfHeight);
+ HDC hdc = m_fontEngineData->hdc;
+ SelectObject(hdc, hfont);
+ fontDef.pixelSize = -lf.lfHeight;
+ const BOOL res = GetTextMetrics(hdc, &tm);
+ fontDef.fixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
+ if (!res) {
+ qErrnoWarning("%s: GetTextMetrics failed", __FUNCTION__);
+ ZeroMemory(&tm, sizeof(TEXTMETRIC));
+ }
+
+ cache_cost = tm.tmHeight * tm.tmAveCharWidth * 2000;
+ getCMap();
+
+ if (!resolvedGetCharWidthI)
+ resolveGetCharWidthI();
+}
+
+QWindowsFontEngine::~QWindowsFontEngine()
+{
+ if (designAdvances)
+ free(designAdvances);
+
+ if (widthCache)
+ free(widthCache);
+
+ // make sure we aren't by accident still selected
+ SelectObject(m_fontEngineData->hdc, (HFONT)GetStockObject(SYSTEM_FONT));
+
+ if (!stockFont) {
+ if (!DeleteObject(hfont))
+ qErrnoWarning("%s: QFontEngineWin: failed to delete non-stock font... failed", __FUNCTION__);
+ }
+ if (QWindowsContext::verboseFonts)
+ if (QWindowsContext::verboseFonts)
+ qDebug("%s: font='%s", __FUNCTION__, qPrintable(_name));
+}
+
+HGDIOBJ QWindowsFontEngine::selectDesignFont() const
+{
+ LOGFONT f = m_logfont;
+ f.lfHeight = unitsPerEm;
+ HFONT designFont = CreateFontIndirect(&f);
+ return SelectObject(m_fontEngineData->hdc, designFont);
+}
+
+bool QWindowsFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
+{
+ if (*nglyphs < len) {
+ *nglyphs = len;
+ return false;
+ }
+
+ *nglyphs = getGlyphIndexes(str, len, glyphs, flags & QTextEngine::RightToLeft);
+
+ if (flags & QTextEngine::GlyphIndicesOnly)
+ return true;
+
+ recalcAdvances(glyphs, flags);
+ return true;
+}
+
+inline void calculateTTFGlyphWidth(HDC hdc, UINT glyph, int &width)
+{
+ if (ptrGetCharWidthI)
+ ptrGetCharWidthI(hdc, glyph, 1, 0, &width);
+}
+
+void QWindowsFontEngine::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
+{
+ HGDIOBJ oldFont = 0;
+ HDC hdc = m_fontEngineData->hdc;
+ if (ttf && (flags & QTextEngine::DesignMetrics)) {
+ for(int i = 0; i < glyphs->numGlyphs; i++) {
+ unsigned int glyph = glyphs->glyphs[i];
+ if(int(glyph) >= designAdvancesSize) {
+ int newSize = (glyph + 256) >> 8 << 8;
+ designAdvances = q_check_ptr((QFixed *)realloc(designAdvances,
+ newSize*sizeof(QFixed)));
+ for(int i = designAdvancesSize; i < newSize; ++i)
+ designAdvances[i] = -1000000;
+ designAdvancesSize = newSize;
+ }
+ if (designAdvances[glyph] < -999999) {
+ if (!oldFont)
+ oldFont = selectDesignFont();
+
+ int width = 0;
+ calculateTTFGlyphWidth(hdc, glyph, width);
+ designAdvances[glyph] = QFixed(width) / designToDevice;
+ }
+ glyphs->advances_x[i] = designAdvances[glyph];
+ glyphs->advances_y[i] = 0;
+ }
+ if(oldFont)
+ DeleteObject(SelectObject(hdc, oldFont));
+ } else {
+ for(int i = 0; i < glyphs->numGlyphs; i++) {
+ unsigned int glyph = glyphs->glyphs[i];
+
+ glyphs->advances_y[i] = 0;
+
+ if (glyph >= widthCacheSize) {
+ int newSize = (glyph + 256) >> 8 << 8;
+ widthCache = q_check_ptr((unsigned char *)realloc(widthCache,
+ newSize*sizeof(QFixed)));
+ memset(widthCache + widthCacheSize, 0, newSize - widthCacheSize);
+ widthCacheSize = newSize;
+ }
+ glyphs->advances_x[i] = widthCache[glyph];
+ // font-width cache failed
+ if (glyphs->advances_x[i] == 0) {
+ int width = 0;
+ if (!oldFont)
+ oldFont = SelectObject(hdc, hfont);
+
+ if (!ttf) {
+ QChar ch[2] = { ushort(glyph), 0 };
+ int chrLen = 1;
+ if (glyph > 0xffff) {
+ ch[0] = QChar::highSurrogate(glyph);
+ ch[1] = QChar::lowSurrogate(glyph);
+ ++chrLen;
+ }
+ SIZE size = {0, 0};
+ GetTextExtentPoint32(hdc, (wchar_t *)ch, chrLen, &size);
+ width = size.cx;
+ } else {
+ calculateTTFGlyphWidth(hdc, glyph, width);
+ }
+ glyphs->advances_x[i] = width;
+ // if glyph's within cache range, store it for later
+ if (width > 0 && width < 0x100)
+ widthCache[glyph] = width;
+ }
+ }
+
+ if (oldFont)
+ SelectObject(hdc, oldFont);
+ }
+}
+
+glyph_metrics_t QWindowsFontEngine::boundingBox(const QGlyphLayout &glyphs)
+{
+ if (glyphs.numGlyphs == 0)
+ return glyph_metrics_t();
+
+ QFixed w = 0;
+ for (int i = 0; i < glyphs.numGlyphs; ++i)
+ w += glyphs.effectiveAdvance(i);
+
+ return glyph_metrics_t(0, -tm.tmAscent, w - lastRightBearing(glyphs), tm.tmHeight, w, 0);
+}
+
+bool QWindowsFontEngine::getOutlineMetrics(glyph_t glyph, const QTransform &t, glyph_metrics_t *metrics) const
+{
+ Q_ASSERT(metrics != 0);
+
+ HDC hdc = m_fontEngineData->hdc;
+
+ GLYPHMETRICS gm;
+ DWORD res = 0;
+ MAT2 mat;
+ mat.eM11.value = mat.eM22.value = 1;
+ mat.eM11.fract = mat.eM22.fract = 0;
+ mat.eM21.value = mat.eM12.value = 0;
+ mat.eM21.fract = mat.eM12.fract = 0;
+
+ if (t.type() > QTransform::TxTranslate) {
+ // We need to set the transform using the HDC's world
+ // matrix rather than using the MAT2 above, because the
+ // results provided when transforming via MAT2 does not
+ // match the glyphs that are drawn using a WorldTransform
+ XFORM xform;
+ xform.eM11 = t.m11();
+ xform.eM12 = t.m12();
+ xform.eM21 = t.m21();
+ xform.eM22 = t.m22();
+ xform.eDx = 0;
+ xform.eDy = 0;
+ SetGraphicsMode(hdc, GM_ADVANCED);
+ SetWorldTransform(hdc, &xform);
+ }
+
+ uint format = GGO_METRICS;
+ if (ttf)
+ format |= GGO_GLYPH_INDEX;
+ res = GetGlyphOutline(hdc, glyph, format, &gm, 0, 0, &mat);
+
+ if (t.type() > QTransform::TxTranslate) {
+ XFORM xform;
+ xform.eM11 = xform.eM22 = 1;
+ xform.eM12 = xform.eM21 = xform.eDx = xform.eDy = 0;
+ SetWorldTransform(hdc, &xform);
+ SetGraphicsMode(hdc, GM_COMPATIBLE);
+ }
+
+ if (res != GDI_ERROR) {
+ *metrics = glyph_metrics_t(gm.gmptGlyphOrigin.x, -gm.gmptGlyphOrigin.y,
+ (int)gm.gmBlackBoxX, (int)gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+glyph_metrics_t QWindowsFontEngine::boundingBox(glyph_t glyph, const QTransform &t)
+{
+ HDC hdc = m_fontEngineData->hdc;
+ SelectObject(hdc, hfont);
+
+ glyph_metrics_t glyphMetrics;
+ bool success = getOutlineMetrics(glyph, t, &glyphMetrics);
+
+ if (!ttf && !success) {
+ // Bitmap fonts
+ wchar_t ch = glyph;
+ ABCFLOAT abc;
+ GetCharABCWidthsFloat(hdc, ch, ch, &abc);
+ int width = qRound(abc.abcfB);
+
+ return glyph_metrics_t(QFixed::fromReal(abc.abcfA), -tm.tmAscent, width, tm.tmHeight, width, 0).transformed(t);
+ }
+
+ return glyphMetrics;
+}
+
+QFixed QWindowsFontEngine::ascent() const
+{
+ return tm.tmAscent;
+}
+
+QFixed QWindowsFontEngine::descent() const
+{
+ // ### we subtract 1 to even out the historical +1 in QFontMetrics'
+ // ### height=asc+desc+1 equation. Fix in Qt5.
+ return tm.tmDescent - 1;
+}
+
+QFixed QWindowsFontEngine::leading() const
+{
+ return tm.tmExternalLeading;
+}
+
+
+QFixed QWindowsFontEngine::xHeight() const
+{
+ if(x_height >= 0)
+ return x_height;
+ return QFontEngine::xHeight();
+}
+
+QFixed QWindowsFontEngine::averageCharWidth() const
+{
+ return tm.tmAveCharWidth;
+}
+
+qreal QWindowsFontEngine::maxCharWidth() const
+{
+ return tm.tmMaxCharWidth;
+}
+
+enum { max_font_count = 256 };
+static const ushort char_table[] = {
+ 40,
+ 67,
+ 70,
+ 75,
+ 86,
+ 88,
+ 89,
+ 91,
+ 102,
+ 114,
+ 124,
+ 127,
+ 205,
+ 645,
+ 884,
+ 922,
+ 1070,
+ 12386,
+ 0
+};
+
+static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
+
+#ifndef Q_CC_MINGW
+void QWindowsFontEngine::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing)
+{
+ HDC hdc = m_fontEngineData->hdc;
+ SelectObject(hdc, hfont);
+
+ if (ttf)
+ {
+ ABC abcWidths;
+ GetCharABCWidthsI(hdc, glyph, 1, 0, &abcWidths);
+ if (leftBearing)
+ *leftBearing = abcWidths.abcA;
+ if (rightBearing)
+ *rightBearing = abcWidths.abcC;
+ } else {
+ QFontEngine::getGlyphBearings(glyph, leftBearing, rightBearing);
+ }
+}
+#endif // Q_CC_MINGW
+
+qreal QWindowsFontEngine::minLeftBearing() const
+{
+ if (lbearing == SHRT_MIN)
+ minRightBearing(); // calculates both
+
+ return lbearing;
+}
+
+qreal QWindowsFontEngine::minRightBearing() const
+{
+ if (rbearing == SHRT_MIN) {
+ int ml = 0;
+ int mr = 0;
+ HDC hdc = m_fontEngineData->hdc;
+ SelectObject(hdc, hfont);
+ if (ttf) {
+ ABC *abc = 0;
+ int n = tm.tmLastChar - tm.tmFirstChar;
+ if (n <= max_font_count) {
+ abc = new ABC[n+1];
+ GetCharABCWidths(hdc, tm.tmFirstChar, tm.tmLastChar, abc);
+ } else {
+ abc = new ABC[char_table_entries+1];
+ for(int i = 0; i < char_table_entries; i++)
+ GetCharABCWidths(hdc, char_table[i], char_table[i], abc + i);
+ n = char_table_entries;
+ }
+ ml = abc[0].abcA;
+ mr = abc[0].abcC;
+ for (int i = 1; i < n; i++) {
+ if (abc[i].abcA + abc[i].abcB + abc[i].abcC != 0) {
+ ml = qMin(ml,abc[i].abcA);
+ mr = qMin(mr,abc[i].abcC);
+ }
+ }
+ delete [] abc;
+ } else {
+ ABCFLOAT *abc = 0;
+ int n = tm.tmLastChar - tm.tmFirstChar+1;
+ if (n <= max_font_count) {
+ abc = new ABCFLOAT[n];
+ GetCharABCWidthsFloat(hdc, tm.tmFirstChar, tm.tmLastChar, abc);
+ } else {
+ abc = new ABCFLOAT[char_table_entries];
+ for(int i = 0; i < char_table_entries; i++)
+ GetCharABCWidthsFloat(hdc, char_table[i], char_table[i], abc+i);
+ n = char_table_entries;
+ }
+ float fml = abc[0].abcfA;
+ float fmr = abc[0].abcfC;
+ for (int i=1; i<n; i++) {
+ if (abc[i].abcfA + abc[i].abcfB + abc[i].abcfC != 0) {
+ fml = qMin(fml,abc[i].abcfA);
+ fmr = qMin(fmr,abc[i].abcfC);
+ }
+ }
+ ml = int(fml - 0.9999);
+ mr = int(fmr - 0.9999);
+ delete [] abc;
+ }
+ lbearing = ml;
+ rbearing = mr;
+ }
+
+ return rbearing;
+}
+
+
+const char *QWindowsFontEngine::name() const
+{
+ return 0;
+}
+
+bool QWindowsFontEngine::canRender(const QChar *string, int len)
+{
+ if (symbol) {
+ for (int i = 0; i < len; ++i) {
+ unsigned int uc = getChar(string, i, len);
+ if (getTrueTypeGlyphIndex(cmap, uc) == 0) {
+ if (uc < 0x100) {
+ if (getTrueTypeGlyphIndex(cmap, uc + 0xf000) == 0)
+ return false;
+ } else {
+ return false;
+ }
+ }
+ }
+ } else if (ttf) {
+ for (int i = 0; i < len; ++i) {
+ unsigned int uc = getChar(string, i, len);
+ if (getTrueTypeGlyphIndex(cmap, uc) == 0)
+ return false;
+ }
+ } else {
+ while(len--) {
+ if (tm.tmFirstChar > string->unicode() || tm.tmLastChar < string->unicode())
+ return false;
+ }
+ }
+ return true;
+}
+
+QFontEngine::Type QWindowsFontEngine::type() const
+{
+ return QFontEngine::Win;
+}
+
+static inline double qt_fixed_to_double(const FIXED &p) {
+ return ((p.value << 16) + p.fract) / 65536.0;
+}
+
+static inline QPointF qt_to_qpointf(const POINTFX &pt, qreal scale) {
+ return QPointF(qt_fixed_to_double(pt.x) * scale, -qt_fixed_to_double(pt.y) * scale);
+}
+
+#ifndef GGO_UNHINTED
+#define GGO_UNHINTED 0x0100
+#endif
+
+static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc,
+ QPainterPath *path, bool ttf, glyph_metrics_t *metric = 0, qreal scale = 1)
+{
+ MAT2 mat;
+ mat.eM11.value = mat.eM22.value = 1;
+ mat.eM11.fract = mat.eM22.fract = 0;
+ mat.eM21.value = mat.eM12.value = 0;
+ mat.eM21.fract = mat.eM12.fract = 0;
+ uint glyphFormat = GGO_NATIVE;
+
+ if (ttf)
+ glyphFormat |= GGO_GLYPH_INDEX;
+
+ GLYPHMETRICS gMetric;
+ memset(&gMetric, 0, sizeof(GLYPHMETRICS));
+ int bufferSize = GDI_ERROR;
+ bufferSize = GetGlyphOutline(hdc, glyph, glyphFormat, &gMetric, 0, 0, &mat);
+ if ((DWORD)bufferSize == GDI_ERROR) {
+ return false;
+ }
+
+ void *dataBuffer = new char[bufferSize];
+ DWORD ret = GDI_ERROR;
+ ret = GetGlyphOutline(hdc, glyph, glyphFormat, &gMetric, bufferSize, dataBuffer, &mat);
+ if (ret == GDI_ERROR) {
+ delete [](char *)dataBuffer;
+ return false;
+ }
+
+ if(metric) {
+ // #### obey scale
+ *metric = glyph_metrics_t(gMetric.gmptGlyphOrigin.x, -gMetric.gmptGlyphOrigin.y,
+ (int)gMetric.gmBlackBoxX, (int)gMetric.gmBlackBoxY,
+ gMetric.gmCellIncX, gMetric.gmCellIncY);
+ }
+
+ int offset = 0;
+ int headerOffset = 0;
+ TTPOLYGONHEADER *ttph = 0;
+
+ QPointF oset = position.toPointF();
+ while (headerOffset < bufferSize) {
+ ttph = (TTPOLYGONHEADER*)((char *)dataBuffer + headerOffset);
+
+ QPointF lastPoint(qt_to_qpointf(ttph->pfxStart, scale));
+ path->moveTo(lastPoint + oset);
+ offset += sizeof(TTPOLYGONHEADER);
+ TTPOLYCURVE *curve;
+ while (offset<int(headerOffset + ttph->cb)) {
+ curve = (TTPOLYCURVE*)((char*)(dataBuffer) + offset);
+ switch (curve->wType) {
+ case TT_PRIM_LINE: {
+ for (int i=0; i<curve->cpfx; ++i) {
+ QPointF p = qt_to_qpointf(curve->apfx[i], scale) + oset;
+ path->lineTo(p);
+ }
+ break;
+ }
+ case TT_PRIM_QSPLINE: {
+ const QPainterPath::Element &elm = path->elementAt(path->elementCount()-1);
+ QPointF prev(elm.x, elm.y);
+ QPointF endPoint;
+ for (int i=0; i<curve->cpfx - 1; ++i) {
+ QPointF p1 = qt_to_qpointf(curve->apfx[i], scale) + oset;
+ QPointF p2 = qt_to_qpointf(curve->apfx[i+1], scale) + oset;
+ if (i < curve->cpfx - 2) {
+ endPoint = QPointF((p1.x() + p2.x()) / 2, (p1.y() + p2.y()) / 2);
+ } else {
+ endPoint = p2;
+ }
+
+ path->quadTo(p1, endPoint);
+ prev = endPoint;
+ }
+
+ break;
+ }
+ case TT_PRIM_CSPLINE: {
+ for (int i=0; i<curve->cpfx; ) {
+ QPointF p2 = qt_to_qpointf(curve->apfx[i++], scale) + oset;
+ QPointF p3 = qt_to_qpointf(curve->apfx[i++], scale) + oset;
+ QPointF p4 = qt_to_qpointf(curve->apfx[i++], scale) + oset;
+ path->cubicTo(p2, p3, p4);
+ }
+ break;
+ }
+ default:
+ qWarning("QFontEngineWin::addOutlineToPath, unhandled switch case");
+ }
+ offset += sizeof(TTPOLYCURVE) + (curve->cpfx-1) * sizeof(POINTFX);
+ }
+ path->closeSubpath();
+ headerOffset += ttph->cb;
+ }
+ delete [] (char*)dataBuffer;
+
+ return true;
+}
+
+void QWindowsFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs,
+ QPainterPath *path, QTextItem::RenderFlags)
+{
+ LOGFONT lf = m_logfont;
+ // The sign must be negative here to make sure we match against character height instead of
+ // hinted cell height. This ensures that we get linear matching, and we need this for
+ // paths since we later on apply a scaling transform to the glyph outline to get the
+ // font at the correct pixel size.
+ lf.lfHeight = -unitsPerEm;
+ lf.lfWidth = 0;
+ HFONT hf = CreateFontIndirect(&lf);
+ HDC hdc = m_fontEngineData->hdc;
+ HGDIOBJ oldfont = SelectObject(hdc, hf);
+
+ for(int i = 0; i < nglyphs; ++i) {
+ if (!addGlyphToPath(glyphs[i], positions[i], hdc, path, ttf, /*metric*/0,
+ qreal(fontDef.pixelSize) / unitsPerEm)) {
+ // Some windows fonts, like "Modern", are vector stroke
+ // fonts, which are reported as TMPF_VECTOR but do not
+ // support GetGlyphOutline, and thus we set this bit so
+ // that addOutLineToPath can check it and return safely...
+ hasOutline = false;
+ break;
+ }
+ }
+ DeleteObject(SelectObject(hdc, oldfont));
+}
+
+void QWindowsFontEngine::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs,
+ QPainterPath *path, QTextItem::RenderFlags flags)
+{
+ if(tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)) {
+ hasOutline = true;
+ QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
+ if (hasOutline) {
+ // has_outline is set to false if addGlyphToPath gets
+ // false from GetGlyphOutline, meaning its not an outline
+ // font.
+ return;
+ }
+ }
+ QFontEngine::addBitmapFontToPath(x, y, glyphs, path, flags);
+}
+
+QFontEngine::FaceId QWindowsFontEngine::faceId() const
+{
+ return _faceId;
+}
+
+QT_BEGIN_INCLUDE_NAMESPACE
+#include <qdebug.h>
+QT_END_INCLUDE_NAMESPACE
+
+int QWindowsFontEngine::synthesized() const
+{
+ if(synthesized_flags == -1) {
+ synthesized_flags = 0;
+ if(ttf) {
+ const DWORD HEAD = MAKE_TAG('h', 'e', 'a', 'd');
+ HDC hdc = m_fontEngineData->hdc;
+ SelectObject(hdc, hfont);
+ uchar data[4];
+ GetFontData(hdc, HEAD, 44, &data, 4);
+ USHORT macStyle = getUShort(data);
+ if (tm.tmItalic && !(macStyle & 2))
+ synthesized_flags = SynthesizedItalic;
+ if (fontDef.stretch != 100 && ttf)
+ synthesized_flags |= SynthesizedStretch;
+ if (tm.tmWeight >= 500 && !(macStyle & 1))
+ synthesized_flags |= SynthesizedBold;
+ //qDebug() << "font is" << _name <<
+ // "it=" << (macStyle & 2) << fontDef.style << "flags=" << synthesized_flags;
+ }
+ }
+ return synthesized_flags;
+}
+
+QFixed QWindowsFontEngine::emSquareSize() const
+{
+ return unitsPerEm;
+}
+
+QFontEngine::Properties QWindowsFontEngine::properties() const
+{
+ LOGFONT lf = m_logfont;
+ lf.lfHeight = unitsPerEm;
+ HFONT hf = CreateFontIndirect(&lf);
+ HDC hdc = m_fontEngineData->hdc;
+ HGDIOBJ oldfont = SelectObject(hdc, hf);
+ OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc);
+ Properties p;
+ p.emSquare = unitsPerEm;
+ p.italicAngle = otm->otmItalicAngle;
+ p.postscriptName = QString::fromWCharArray((wchar_t *)((char *)otm + (quintptr)otm->otmpFamilyName)).toLatin1();
+ p.postscriptName += QString::fromWCharArray((wchar_t *)((char *)otm + (quintptr)otm->otmpStyleName)).toLatin1();
+ p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(p.postscriptName);
+ p.boundingBox = QRectF(otm->otmrcFontBox.left, -otm->otmrcFontBox.top,
+ otm->otmrcFontBox.right - otm->otmrcFontBox.left,
+ otm->otmrcFontBox.top - otm->otmrcFontBox.bottom);
+ p.ascent = otm->otmAscent;
+ p.descent = -otm->otmDescent;
+ p.leading = (int)otm->otmLineGap;
+ p.capHeight = 0;
+ p.lineWidth = otm->otmsUnderscoreSize;
+ free(otm);
+ DeleteObject(SelectObject(hdc, oldfont));
+ return p;
+}
+
+void QWindowsFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
+{
+ LOGFONT lf = m_logfont;
+ lf.lfHeight = unitsPerEm;
+ int flags = synthesized();
+ if(flags & SynthesizedItalic)
+ lf.lfItalic = false;
+ lf.lfWidth = 0;
+ HFONT hf = CreateFontIndirect(&lf);
+ HDC hdc = m_fontEngineData->hdc;
+ HGDIOBJ oldfont = SelectObject(hdc, hf);
+ QFixedPoint p;
+ p.x = 0;
+ p.y = 0;
+ addGlyphToPath(glyph, p, hdc, path, ttf, metrics);
+ DeleteObject(SelectObject(hdc, oldfont));
+}
+
+bool QWindowsFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const
+{
+ if (!ttf)
+ return false;
+ HDC hdc = m_fontEngineData->hdc;
+ SelectObject(hdc, hfont);
+ DWORD t = qbswap<quint32>(tag);
+ *length = GetFontData(hdc, t, 0, buffer, *length);
+ return *length != GDI_ERROR;
+}
+
+#if !defined(CLEARTYPE_QUALITY)
+# define CLEARTYPE_QUALITY 5
+#endif
+
+QWindowsNativeImage *QWindowsFontEngine::drawGDIGlyph(HFONT font, glyph_t glyph, int margin,
+ const QTransform &t,
+ QImage::Format mask_format)
+{
+ Q_UNUSED(mask_format)
+ glyph_metrics_t gm = boundingBox(glyph);
+
+// printf(" -> for glyph %4x\n", glyph);
+
+ int gx = gm.x.toInt();
+ int gy = gm.y.toInt();
+ int iw = gm.width.toInt();
+ int ih = gm.height.toInt();
+
+ if (iw <= 0 || iw <= 0)
+ return 0;
+
+ bool has_transformation = t.type() > QTransform::TxTranslate;
+
+ unsigned int options = ttf ? ETO_GLYPH_INDEX : 0;
+ XFORM xform;
+
+ if (has_transformation) {
+ xform.eM11 = t.m11();
+ xform.eM12 = t.m12();
+ xform.eM21 = t.m21();
+ xform.eM22 = t.m22();
+ xform.eDx = margin;
+ xform.eDy = margin;
+
+ HDC hdc = CreateCompatibleDC(QWindowsContext::instance()->displayContext());
+
+ SetGraphicsMode(hdc, GM_ADVANCED);
+ SetWorldTransform(hdc, &xform);
+ HGDIOBJ old_font = SelectObject(hdc, font);
+
+ int ggo_options = GGO_METRICS | (ttf ? GGO_GLYPH_INDEX : 0);
+ GLYPHMETRICS tgm;
+ MAT2 mat;
+ memset(&mat, 0, sizeof(mat));
+ mat.eM11.value = mat.eM22.value = 1;
+
+ if (GetGlyphOutline(hdc, glyph, ggo_options, &tgm, 0, 0, &mat) == GDI_ERROR) {
+ qWarning("QWinFontEngine: unable to query transformed glyph metrics...");
+ return 0;
+ }
+
+ iw = tgm.gmBlackBoxX;
+ ih = tgm.gmBlackBoxY;
+
+ xform.eDx -= tgm.gmptGlyphOrigin.x;
+ xform.eDy += tgm.gmptGlyphOrigin.y;
+
+ SetGraphicsMode(hdc, GM_COMPATIBLE);
+ SelectObject(hdc, old_font);
+ ReleaseDC(0, hdc);
+ }
+ QWindowsNativeImage *ni = new QWindowsNativeImage(iw + 2 * margin + 4,
+ ih + 2 * margin + 4,
+ QWindowsNativeImage::systemFormat());
+
+ /*If cleartype is enabled we use the standard system format even on Windows CE
+ and not the special textbuffer format we have to use if cleartype is disabled*/
+
+ ni->image().fill(0xffffffff);
+
+ HDC hdc = ni->hdc();
+
+ SelectObject(hdc, GetStockObject(NULL_BRUSH));
+ SelectObject(hdc, GetStockObject(BLACK_PEN));
+ SetTextColor(hdc, RGB(0,0,0));
+ SetBkMode(hdc, TRANSPARENT);
+ SetTextAlign(hdc, TA_BASELINE);
+
+ HGDIOBJ old_font = SelectObject(hdc, font);
+
+ if (has_transformation) {
+ SetGraphicsMode(hdc, GM_ADVANCED);
+ SetWorldTransform(hdc, &xform);
+ ExtTextOut(hdc, 0, 0, options, 0, (LPCWSTR) &glyph, 1, 0);
+ } else
+ {
+ ExtTextOut(hdc, -gx + margin, -gy + margin, options, 0, (LPCWSTR) &glyph, 1, 0);
+ }
+
+ SelectObject(hdc, old_font);
+ return ni;
+}
+
+QImage QWindowsFontEngine::alphaMapForGlyph(glyph_t glyph, const QTransform &xform)
+{
+ HFONT font = hfont;
+ if (m_fontEngineData->clearTypeEnabled) {
+ LOGFONT lf = m_logfont;
+ lf.lfQuality = ANTIALIASED_QUALITY;
+ font = CreateFontIndirect(&lf);
+ }
+ QImage::Format mask_format = QWindowsNativeImage::systemFormat();
+ mask_format = QImage::Format_RGB32;
+
+ QWindowsNativeImage *mask = drawGDIGlyph(font, glyph, 0, xform, mask_format);
+ if (mask == 0)
+ return QImage();
+
+ QImage indexed(mask->width(), mask->height(), QImage::Format_Indexed8);
+
+ // ### This part is kinda pointless, but we'll crash later if we don't because some
+ // code paths expects there to be colortables for index8-bit...
+ QVector<QRgb> colors(256);
+ for (int i=0; i<256; ++i)
+ colors[i] = qRgba(0, 0, 0, i);
+ indexed.setColorTable(colors);
+
+ // Copy data... Cannot use QPainter here as GDI has messed up the
+ // Alpha channel of the ni.image pixels...
+ for (int y=0; y<mask->height(); ++y) {
+ uchar *dest = indexed.scanLine(y);
+ if (mask->image().format() == QImage::Format_RGB16) {
+ const qint16 *src = (qint16 *) ((const QImage &) mask->image()).scanLine(y);
+ for (int x=0; x<mask->width(); ++x)
+ dest[x] = 255 - qGray(src[x]);
+ } else {
+ const uint *src = (uint *) ((const QImage &) mask->image()).scanLine(y);
+ for (int x=0; x<mask->width(); ++x) {
+ if (QWindowsNativeImage::systemFormat() == QImage::Format_RGB16)
+ dest[x] = 255 - qGray(src[x]);
+ else
+ dest[x] = 255 - (m_fontEngineData->pow_gamma[qGray(src[x])] * 255. / 2047.);
+ }
+ }
+ }
+
+ // Cleanup...
+ delete mask;
+ if (m_fontEngineData->clearTypeEnabled) {
+ DeleteObject(font);
+ }
+
+ return indexed;
+}
+
+#define SPI_GETFONTSMOOTHINGCONTRAST 0x200C
+#define SPI_SETFONTSMOOTHINGCONTRAST 0x200D
+
+QImage QWindowsFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed, int margin, const QTransform &t)
+{
+ HFONT font = hfont;
+
+ int contrast;
+ SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &contrast, 0);
+ SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, (void *) 1000, 0);
+
+ QWindowsNativeImage *mask = drawGDIGlyph(font, glyph, margin, t, QImage::Format_RGB32);
+ SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, (void *) contrast, 0);
+
+ if (mask == 0)
+ return QImage();
+
+ // Gracefully handle the odd case when the display is 16-bit
+ const QImage source = mask->image().depth() == 32
+ ? mask->image()
+ : mask->image().convertToFormat(QImage::Format_RGB32);
+
+ QImage rgbMask(mask->width(), mask->height(), QImage::Format_RGB32);
+ for (int y=0; y<mask->height(); ++y) {
+ uint *dest = (uint *) rgbMask.scanLine(y);
+ const uint *src = (uint *) source.scanLine(y);
+ for (int x=0; x<mask->width(); ++x) {
+ dest[x] = 0xffffffff - (0x00ffffff & src[x]);
+ }
+ }
+
+ delete mask;
+
+ return rgbMask;
+}
+
+QFontEngine *QWindowsFontEngine::cloneWithSize(qreal pixelSize) const
+{
+ QFontDef request = fontDef;
+ QString actualFontName = request.family;
+ if (!uniqueFamilyName.isEmpty())
+ request.family = uniqueFamilyName;
+ request.pixelSize = pixelSize;
+
+ QFontEngine *fontEngine =
+ QWindowsFontDatabase::createEngine(QUnicodeTables::Common, request, 0,
+ QWindowsContext::instance()->defaultDPI(),
+ false,
+ QStringList(), m_fontEngineData);
+ if (fontEngine)
+ fontEngine->fontDef.family = actualFontName;
+ return fontEngine;
+}
+
+void QWindowsFontEngine::initFontInfo(const QFontDef &request,
+ HDC fontHdc,
+ int dpi)
+{
+ fontDef = request; // most settings are equal
+ HDC dc = ((request.styleStrategy & QFont::PreferDevice) && fontHdc) ? fontHdc : m_fontEngineData->hdc;
+ SelectObject(dc, hfont);
+ wchar_t n[64];
+ GetTextFace(dc, 64, n);
+ fontDef.family = QString::fromWCharArray(n);
+ fontDef.fixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
+ if (fontDef.pointSize < 0) {
+ fontDef.pointSize = fontDef.pixelSize * 72. / dpi;
+ } else if (fontDef.pixelSize == -1) {
+ fontDef.pixelSize = qRound(fontDef.pointSize * dpi / 72.);
+ }
+}
+
+/*!
+ \class QWindowsMultiFontEngine
+ \brief Standard Windows Multi font engine.
+ \ingroup qt-lighthouse-win
+
+ "Merges" several font engines that have gaps in the
+ supported writing systems.
+
+ Will probably be superseded by a common Free Type font engine in Qt 5.X.
+*/
+
+QWindowsMultiFontEngine::QWindowsMultiFontEngine(QFontEngine *first, const QStringList &fallbacks)
+ : QFontEngineMulti(fallbacks.size()+1),
+ fallbacks(fallbacks)
+{
+ if (QWindowsContext::verboseFonts)
+ qDebug() << __FUNCTION__ << engines.size() << first << first->fontDef.family << fallbacks;
+ engines[0] = first;
+ first->ref.ref();
+ fontDef = engines[0]->fontDef;
+ cache_cost = first->cache_cost;
+}
+
+QWindowsMultiFontEngine::~QWindowsMultiFontEngine()
+{
+ if (QWindowsContext::verboseFonts)
+ qDebug("%s", __FUNCTION__);
+}
+
+void QWindowsMultiFontEngine::loadEngine(int at)
+{
+ Q_ASSERT(at < engines.size());
+ Q_ASSERT(engines.at(at) == 0);
+
+ const QString fam = fallbacks.at(at-1);
+ QWindowsFontEngine *fe = static_cast<QWindowsFontEngine*>(engines.at(0));
+ LOGFONT lf = fe->logfont();
+ memcpy(lf.lfFaceName, fam.utf16(), sizeof(wchar_t) * qMin(fam.length() + 1, 32)); // 32 = Windows hard-coded
+ HFONT hfont = CreateFontIndirect(&lf);
+
+ bool stockFont = false;
+ if (hfont == 0) {
+ hfont = (HFONT)GetStockObject(ANSI_VAR_FONT);
+ stockFont = true;
+ }
+ engines[at] = new QWindowsFontEngine(fam, hfont, stockFont, lf, fe->fontEngineData());
+ engines[at]->ref.ref();
+ engines[at]->fontDef = fontDef;
+ if (QWindowsContext::verboseFonts)
+ qDebug("%s %d %s", __FUNCTION__, at, qPrintable(fam));
+
+
+ // TODO: increase cost in QFontCache for the font engine loaded here
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsfontengine.h b/src/plugins/platforms/windows/qwindowsfontengine.h
new file mode 100644
index 0000000000..bed5ecffbd
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsfontengine.h
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** 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 QtGui module 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$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSFONTENGINE_H
+#define QWINDOWSFONTENGINE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+// Enable access to HB_Face in harfbuzz includes included by qfontengine_p.h.
+#define QT_BUILD_GUI_LIB
+#include <QtGui/private/qfontengine_p.h>
+#undef QT_BUILD_GUI_LIB
+
+#include <QtGui/QImage>
+#include <QtCore/QSharedPointer>
+
+#include "qtwindows_additional.h"
+
+QT_BEGIN_NAMESPACE
+
+class QWindowsNativeImage;
+class QWindowsFontEngineData;
+
+class QWindowsFontEngine : public QFontEngine
+{
+ Q_DISABLE_COPY(QWindowsFontEngine)
+public:
+ QWindowsFontEngine(const QString &name, HFONT, bool, LOGFONT,
+ QSharedPointer<QWindowsFontEngineData> fontEngineData);
+
+ ~QWindowsFontEngine();
+ void initFontInfo(const QFontDef &request,
+ HDC fontHdc, int dpi);
+
+ virtual QFixed lineThickness() const;
+ virtual Properties properties() const;
+ virtual void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics);
+ virtual FaceId faceId() const;
+ virtual bool getSfntTableData(uint tag, uchar *buffer, uint *length) const;
+ virtual int synthesized() const;
+ virtual QFixed emSquareSize() const;
+
+ virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const;
+ virtual void recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags) const;
+
+ virtual void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags);
+ virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs,
+ QPainterPath *path, QTextItem::RenderFlags flags);
+
+ HGDIOBJ selectDesignFont() const;
+
+ virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs);
+ virtual glyph_metrics_t boundingBox(glyph_t g) { return boundingBox(g, QTransform()); }
+ virtual glyph_metrics_t boundingBox(glyph_t g, const QTransform &t);
+
+
+ virtual QFixed ascent() const;
+ virtual QFixed descent() const;
+ virtual QFixed leading() const;
+ virtual QFixed xHeight() const;
+ virtual QFixed averageCharWidth() const;
+ virtual qreal maxCharWidth() const;
+ virtual qreal minLeftBearing() const;
+ virtual qreal minRightBearing() const;
+
+ virtual const char *name() const;
+
+ bool canRender(const QChar *string, int len);
+
+ Type type() const;
+
+ virtual QImage alphaMapForGlyph(glyph_t t) { return alphaMapForGlyph(t, QTransform()); }
+ virtual QImage alphaMapForGlyph(glyph_t, const QTransform &xform);
+ virtual QImage alphaRGBMapForGlyph(glyph_t t, QFixed subPixelPosition, int margin, const QTransform &xform);
+
+ virtual QFontEngine *cloneWithSize(qreal pixelSize) const;
+
+#ifndef Q_CC_MINGW
+ virtual void getGlyphBearings(glyph_t glyph, qreal *leftBearing = 0, qreal *rightBearing = 0);
+#endif
+
+ int getGlyphIndexes(const QChar *ch, int numChars, QGlyphLayout *glyphs, bool mirrored) const;
+ void getCMap();
+
+ bool getOutlineMetrics(glyph_t glyph, const QTransform &t, glyph_metrics_t *metrics) const;
+
+ static QFontEngine *createEngine(int script, const QFontDef &request,
+ HDC fontHdc, int dpi, bool rawMode,
+ const QStringList &family_list,
+ const QSharedPointer<QWindowsFontEngineData> &data);
+
+ QSharedPointer<QWindowsFontEngineData> fontEngineData() const { return m_fontEngineData; }
+ LOGFONT logfont() const { return m_logfont; }
+
+private:
+ QWindowsNativeImage *drawGDIGlyph(HFONT font, glyph_t, int margin, const QTransform &xform,
+ QImage::Format mask_format);
+
+ const QSharedPointer<QWindowsFontEngineData> m_fontEngineData;
+
+ const QString _name;
+ QString uniqueFamilyName;
+ const HFONT hfont;
+ const LOGFONT m_logfont;
+ uint stockFont : 1;
+ uint ttf : 1;
+ uint hasOutline : 1;
+ TEXTMETRIC tm;
+ int lw;
+ const unsigned char *cmap;
+ QByteArray cmapTable;
+ mutable qreal lbearing;
+ mutable qreal rbearing;
+ QFixed designToDevice;
+ int unitsPerEm;
+ QFixed x_height;
+ FaceId _faceId;
+
+ mutable int synthesized_flags;
+ mutable QFixed lineWidth;
+ mutable unsigned char *widthCache;
+ mutable uint widthCacheSize;
+ mutable QFixed *designAdvances;
+ mutable int designAdvancesSize;
+};
+
+class QWindowsMultiFontEngine : public QFontEngineMulti
+{
+public:
+ QWindowsMultiFontEngine(QFontEngine *first, const QStringList &fallbacks);
+ virtual ~QWindowsMultiFontEngine();
+ void loadEngine(int at);
+
+ QStringList fallbacks;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSFONTENGINE_H
diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp
new file mode 100644
index 0000000000..46f0b0c336
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp
@@ -0,0 +1,737 @@
+/****************************************************************************
+**
+** 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 QtGui module 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$
+**
+****************************************************************************/
+
+#ifndef QT_NO_DIRECTWRITE
+
+#include "qwindowsfontenginedirectwrite.h"
+#include "qwindowsfontdatabase.h"
+#include "qwindowscontext.h"
+
+#include <QtCore/QSettings>
+#include <QtCore/QtEndian>
+
+#include <dwrite.h>
+#include <d2d1.h>
+
+QT_BEGIN_NAMESPACE
+
+// Convert from design units to logical pixels
+#define DESIGN_TO_LOGICAL(DESIGN_UNIT_VALUE) \
+ QFixed::fromReal((qreal(DESIGN_UNIT_VALUE) / qreal(m_unitsPerEm)) * fontDef.pixelSize)
+
+namespace {
+
+ class GeometrySink: public IDWriteGeometrySink
+ {
+ public:
+ GeometrySink(QPainterPath *path) : m_path(path), m_refCount(0)
+ {
+ Q_ASSERT(m_path != 0);
+ }
+
+ IFACEMETHOD_(void, AddBeziers)(const D2D1_BEZIER_SEGMENT *beziers, UINT bezierCount);
+ IFACEMETHOD_(void, AddLines)(const D2D1_POINT_2F *points, UINT pointCount);
+ IFACEMETHOD_(void, BeginFigure)(D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin);
+ IFACEMETHOD(Close)();
+ IFACEMETHOD_(void, EndFigure)(D2D1_FIGURE_END figureEnd);
+ IFACEMETHOD_(void, SetFillMode)(D2D1_FILL_MODE fillMode);
+ IFACEMETHOD_(void, SetSegmentFlags)(D2D1_PATH_SEGMENT vertexFlags);
+
+ IFACEMETHOD_(unsigned long, AddRef)();
+ IFACEMETHOD_(unsigned long, Release)();
+ IFACEMETHOD(QueryInterface)(IID const &riid, void **ppvObject);
+
+ private:
+ inline static QPointF fromD2D1_POINT_2F(const D2D1_POINT_2F &inp)
+ {
+ return QPointF(inp.x, inp.y);
+ }
+
+ unsigned long m_refCount;
+ QPointF m_startPoint;
+ QPainterPath *m_path;
+ };
+
+ void GeometrySink::AddBeziers(const D2D1_BEZIER_SEGMENT *beziers,
+ UINT bezierCount)
+ {
+ for (uint i=0; i<bezierCount; ++i) {
+ QPointF c1 = fromD2D1_POINT_2F(beziers[i].point1);
+ QPointF c2 = fromD2D1_POINT_2F(beziers[i].point2);
+ QPointF p2 = fromD2D1_POINT_2F(beziers[i].point3);
+
+ m_path->cubicTo(c1, c2, p2);
+ }
+ }
+
+ void GeometrySink::AddLines(const D2D1_POINT_2F *points, UINT pointsCount)
+ {
+ for (uint i=0; i<pointsCount; ++i)
+ m_path->lineTo(fromD2D1_POINT_2F(points[i]));
+ }
+
+ void GeometrySink::BeginFigure(D2D1_POINT_2F startPoint,
+ D2D1_FIGURE_BEGIN /*figureBegin*/)
+ {
+ m_startPoint = fromD2D1_POINT_2F(startPoint);
+ m_path->moveTo(m_startPoint);
+ }
+
+ IFACEMETHODIMP GeometrySink::Close()
+ {
+ return E_NOTIMPL;
+ }
+
+ void GeometrySink::EndFigure(D2D1_FIGURE_END figureEnd)
+ {
+ if (figureEnd == D2D1_FIGURE_END_CLOSED)
+ m_path->closeSubpath();
+ }
+
+ void GeometrySink::SetFillMode(D2D1_FILL_MODE fillMode)
+ {
+ m_path->setFillRule(fillMode == D2D1_FILL_MODE_ALTERNATE
+ ? Qt::OddEvenFill
+ : Qt::WindingFill);
+ }
+
+ void GeometrySink::SetSegmentFlags(D2D1_PATH_SEGMENT /*vertexFlags*/)
+ {
+ /* Not implemented */
+ }
+
+ IFACEMETHODIMP_(unsigned long) GeometrySink::AddRef()
+ {
+ return InterlockedIncrement(&m_refCount);
+ }
+
+ IFACEMETHODIMP_(unsigned long) GeometrySink::Release()
+ {
+ unsigned long newCount = InterlockedDecrement(&m_refCount);
+ if (newCount == 0)
+ {
+ delete this;
+ return 0;
+ }
+
+ return newCount;
+ }
+
+ IFACEMETHODIMP GeometrySink::QueryInterface(IID const &riid, void **ppvObject)
+ {
+ if (__uuidof(IDWriteGeometrySink) == riid) {
+ *ppvObject = this;
+ } else if (__uuidof(IUnknown) == riid) {
+ *ppvObject = this;
+ } else {
+ *ppvObject = NULL;
+ return E_FAIL;
+ }
+
+ AddRef();
+ return S_OK;
+ }
+
+}
+
+/*!
+ \class QWindowsFontEngineDirectWrite
+ \brief Windows font engine using Direct Write.
+ \ingroup qt-lighthouse-win
+
+ Font engine for subpixel positioned text on Windows Vista
+ (with platform update) and Windows 7. If selected during
+ configuration, the engine will be selected only when the hinting
+ preference of a font is set to None or Vertical hinting. The font
+ database uses most of the same logic but creates a direct write
+ font based on the LOGFONT rather than a GDI handle.
+
+ The engine is currently regarded as experimental, meaning that code
+ using it should do substantial testing to make sure it covers their
+ use cases.
+
+ Will probably be superseded by a common Free Type font engine in Qt 5.X.
+*/
+
+QWindowsFontEngineDirectWrite::QWindowsFontEngineDirectWrite(IDWriteFontFace *directWriteFontFace,
+ qreal pixelSize,
+ const QSharedPointer<QWindowsFontEngineData> &d)
+
+ : m_fontEngineData(d)
+ , m_directWriteFontFace(directWriteFontFace)
+ , m_directWriteBitmapRenderTarget(0)
+ , m_lineThickness(-1)
+ , m_unitsPerEm(-1)
+ , m_ascent(-1)
+ , m_descent(-1)
+ , m_xHeight(-1)
+ , m_lineGap(-1)
+{
+ if (QWindowsContext::verboseFonts)
+ qDebug("%s %g", __FUNCTION__, pixelSize);
+
+ d->directWriteFactory->AddRef();
+ m_directWriteFontFace->AddRef();
+
+ fontDef.pixelSize = pixelSize;
+ collectMetrics();
+}
+
+QWindowsFontEngineDirectWrite::~QWindowsFontEngineDirectWrite()
+{
+ if (QWindowsContext::verboseFonts)
+ qDebug("%s", __FUNCTION__);
+
+ m_fontEngineData->directWriteFactory->Release();
+ m_directWriteFontFace->Release();
+
+ if (m_directWriteBitmapRenderTarget != 0)
+ m_directWriteBitmapRenderTarget->Release();
+}
+
+void QWindowsFontEngineDirectWrite::collectMetrics()
+{
+ if (m_directWriteFontFace != 0) {
+ DWRITE_FONT_METRICS metrics;
+
+ m_directWriteFontFace->GetMetrics(&metrics);
+ m_unitsPerEm = metrics.designUnitsPerEm;
+
+ m_lineThickness = DESIGN_TO_LOGICAL(metrics.underlineThickness);
+ m_ascent = DESIGN_TO_LOGICAL(metrics.ascent);
+ m_descent = DESIGN_TO_LOGICAL(metrics.descent);
+ m_xHeight = DESIGN_TO_LOGICAL(metrics.xHeight);
+ m_lineGap = DESIGN_TO_LOGICAL(metrics.lineGap);
+ }
+}
+
+QFixed QWindowsFontEngineDirectWrite::lineThickness() const
+{
+ if (m_lineThickness > 0)
+ return m_lineThickness;
+ else
+ return QFontEngine::lineThickness();
+}
+
+bool QWindowsFontEngineDirectWrite::getSfntTableData(uint tag, uchar *buffer, uint *length) const
+{
+ if (m_directWriteFontFace) {
+ DWORD t = qbswap<quint32>(tag);
+
+ const void *tableData = 0;
+ void *tableContext = 0;
+ UINT32 tableSize;
+ BOOL exists;
+ HRESULT hr = m_directWriteFontFace->TryGetFontTable(
+ t, &tableData, &tableSize, &tableContext, &exists
+ );
+
+ if (SUCCEEDED(hr)) {
+ if (!exists)
+ return false;
+
+ if (buffer == 0) {
+ *length = tableSize;
+ return true;
+ } else if (*length < tableSize) {
+ return false;
+ }
+
+ qMemCopy(buffer, tableData, tableSize);
+ m_directWriteFontFace->ReleaseFontTable(tableContext);
+
+ return true;
+ } else {
+ qErrnoWarning("%s: TryGetFontTable failed", __FUNCTION__);
+ }
+ }
+
+ return false;
+}
+
+QFixed QWindowsFontEngineDirectWrite::emSquareSize() const
+{
+ if (m_unitsPerEm > 0)
+ return m_unitsPerEm;
+ else
+ return QFontEngine::emSquareSize();
+}
+
+inline unsigned int getChar(const QChar *str, int &i, const int len)
+{
+ unsigned int uc = str[i].unicode();
+ if (uc >= 0xd800 && uc < 0xdc00 && i < len-1) {
+ uint low = str[i+1].unicode();
+ if (low >= 0xdc00 && low < 0xe000) {
+ uc = (uc - 0xd800)*0x400 + (low - 0xdc00) + 0x10000;
+ ++i;
+ }
+ }
+ return uc;
+}
+
+bool QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs,
+ int *nglyphs, QTextEngine::ShaperFlags flags) const
+{
+ if (m_directWriteFontFace != 0) {
+ QVarLengthArray<UINT32> codePoints(len);
+ for (int i=0; i<len; ++i) {
+ codePoints[i] = getChar(str, i, len);
+ if (flags & QTextEngine::RightToLeft)
+ codePoints[i] = QChar::mirroredChar(codePoints[i]);
+ }
+
+ QVarLengthArray<UINT16> glyphIndices(len);
+ HRESULT hr = m_directWriteFontFace->GetGlyphIndicesW(codePoints.data(),
+ len,
+ glyphIndices.data());
+
+ if (SUCCEEDED(hr)) {
+ for (int i=0; i<len; ++i)
+ glyphs->glyphs[i] = glyphIndices[i];
+
+ *nglyphs = len;
+
+ if (!(flags & QTextEngine::GlyphIndicesOnly))
+ recalcAdvances(glyphs, 0);
+
+ return true;
+ } else {
+ qErrnoWarning("%s: GetGlyphIndicesW failed", __FUNCTION__);
+ }
+ }
+
+ return false;
+}
+
+void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags) const
+{
+ if (m_directWriteFontFace == 0)
+ return;
+
+ QVarLengthArray<UINT16> glyphIndices(glyphs->numGlyphs);
+
+ // ### Caching?
+ for(int i=0; i<glyphs->numGlyphs; i++)
+ glyphIndices[i] = UINT16(glyphs->glyphs[i]);
+
+ QVarLengthArray<DWRITE_GLYPH_METRICS> glyphMetrics(glyphIndices.size());
+ HRESULT hr = m_directWriteFontFace->GetDesignGlyphMetrics(glyphIndices.data(),
+ glyphIndices.size(),
+ glyphMetrics.data());
+ if (SUCCEEDED(hr)) {
+ for (int i=0; i<glyphs->numGlyphs; ++i) {
+ glyphs->advances_x[i] = DESIGN_TO_LOGICAL(glyphMetrics[i].advanceWidth);
+ if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
+ glyphs->advances_x[i] = glyphs->advances_x[i].round();
+ glyphs->advances_y[i] = 0;
+ }
+ } else {
+ qErrnoWarning("%s: GetDesignGlyphMetrics failed", __FUNCTION__);
+ }
+}
+
+void QWindowsFontEngineDirectWrite::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs,
+ QPainterPath *path, QTextItem::RenderFlags flags)
+{
+ if (m_directWriteFontFace == 0)
+ return;
+
+ QVarLengthArray<UINT16> glyphIndices(nglyphs);
+ QVarLengthArray<DWRITE_GLYPH_OFFSET> glyphOffsets(nglyphs);
+ QVarLengthArray<FLOAT> glyphAdvances(nglyphs);
+
+ for (int i=0; i<nglyphs; ++i) {
+ glyphIndices[i] = glyphs[i];
+ glyphOffsets[i].advanceOffset = positions[i].x.toReal();
+ glyphOffsets[i].ascenderOffset = -positions[i].y.toReal();
+ glyphAdvances[i] = 0.0;
+ }
+
+ GeometrySink geometrySink(path);
+ HRESULT hr = m_directWriteFontFace->GetGlyphRunOutline(
+ fontDef.pixelSize,
+ glyphIndices.data(),
+ glyphAdvances.data(),
+ glyphOffsets.data(),
+ nglyphs,
+ false,
+ flags & QTextItem::RightToLeft,
+ &geometrySink
+ );
+
+ if (FAILED(hr))
+ qErrnoWarning("%s: GetGlyphRunOutline failed", __FUNCTION__);
+}
+
+glyph_metrics_t QWindowsFontEngineDirectWrite::boundingBox(const QGlyphLayout &glyphs)
+{
+ if (glyphs.numGlyphs == 0)
+ return glyph_metrics_t();
+
+ bool round = fontDef.styleStrategy & QFont::ForceIntegerMetrics;
+
+ QFixed w = 0;
+ for (int i = 0; i < glyphs.numGlyphs; ++i) {
+ w += round ? glyphs.effectiveAdvance(i).round() : glyphs.effectiveAdvance(i);
+
+ }
+
+ return glyph_metrics_t(0, -m_ascent, w - lastRightBearing(glyphs), m_ascent + m_descent, w, 0);
+}
+
+glyph_metrics_t QWindowsFontEngineDirectWrite::boundingBox(glyph_t g)
+{
+ if (m_directWriteFontFace == 0)
+ return glyph_metrics_t();
+
+ UINT16 glyphIndex = g;
+
+ DWRITE_GLYPH_METRICS glyphMetrics;
+ HRESULT hr = m_directWriteFontFace->GetDesignGlyphMetrics(&glyphIndex, 1, &glyphMetrics);
+ if (SUCCEEDED(hr)) {
+ QFixed advanceWidth = DESIGN_TO_LOGICAL(glyphMetrics.advanceWidth);
+ QFixed leftSideBearing = DESIGN_TO_LOGICAL(glyphMetrics.leftSideBearing);
+ QFixed rightSideBearing = DESIGN_TO_LOGICAL(glyphMetrics.rightSideBearing);
+ QFixed advanceHeight = DESIGN_TO_LOGICAL(glyphMetrics.advanceHeight);
+ QFixed verticalOriginY = DESIGN_TO_LOGICAL(glyphMetrics.verticalOriginY);
+
+ if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
+ advanceWidth = advanceWidth.round();
+ advanceHeight = advanceHeight.round();
+ }
+
+ QFixed width = advanceWidth - leftSideBearing - rightSideBearing;
+
+ return glyph_metrics_t(-leftSideBearing, -verticalOriginY,
+ width, m_ascent + m_descent,
+ advanceWidth, advanceHeight);
+ } else {
+ qErrnoWarning("%s: GetDesignGlyphMetrics failed", __FUNCTION__);
+ }
+
+ return glyph_metrics_t();
+}
+
+QFixed QWindowsFontEngineDirectWrite::ascent() const
+{
+ return fontDef.styleStrategy & QFont::ForceIntegerMetrics
+ ? m_ascent.round()
+ : m_ascent;
+}
+
+QFixed QWindowsFontEngineDirectWrite::descent() const
+{
+ return fontDef.styleStrategy & QFont::ForceIntegerMetrics
+ ? (m_descent - 1).round()
+ : (m_descent - 1);
+}
+
+QFixed QWindowsFontEngineDirectWrite::leading() const
+{
+ return fontDef.styleStrategy & QFont::ForceIntegerMetrics
+ ? m_lineGap.round()
+ : m_lineGap;
+}
+
+QFixed QWindowsFontEngineDirectWrite::xHeight() const
+{
+ return fontDef.styleStrategy & QFont::ForceIntegerMetrics
+ ? m_xHeight.round()
+ : m_xHeight;
+}
+
+qreal QWindowsFontEngineDirectWrite::maxCharWidth() const
+{
+ // ###
+ return 0;
+}
+
+QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition)
+{
+ QImage im = imageForGlyph(glyph, subPixelPosition, 0, QTransform());
+
+ QImage indexed(im.width(), im.height(), QImage::Format_Indexed8);
+ QVector<QRgb> colors(256);
+ for (int i=0; i<256; ++i)
+ colors[i] = qRgba(0, 0, 0, i);
+ indexed.setColorTable(colors);
+
+ for (int y=0; y<im.height(); ++y) {
+ uint *src = (uint*) im.scanLine(y);
+ uchar *dst = indexed.scanLine(y);
+ for (int x=0; x<im.width(); ++x) {
+ *dst = 255 - (m_fontEngineData->pow_gamma[qGray(0xffffffff - *src)] * 255. / 2047.);
+ ++dst;
+ ++src;
+ }
+ }
+
+ return indexed;
+}
+
+bool QWindowsFontEngineDirectWrite::supportsSubPixelPositions() const
+{
+ return true;
+}
+
+QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
+ QFixed subPixelPosition,
+ int margin,
+ const QTransform &xform)
+{
+ glyph_metrics_t metrics = QFontEngine::boundingBox(t, xform);
+ int width = (metrics.width + margin * 2 + 4).ceil().toInt() ;
+ int height = (metrics.height + margin * 2 + 4).ceil().toInt();
+
+ UINT16 glyphIndex = t;
+ FLOAT glyphAdvance = metrics.xoff.toReal();
+
+ DWRITE_GLYPH_OFFSET glyphOffset;
+ glyphOffset.advanceOffset = 0;
+ glyphOffset.ascenderOffset = 0;
+
+ DWRITE_GLYPH_RUN glyphRun;
+ glyphRun.fontFace = m_directWriteFontFace;
+ glyphRun.fontEmSize = fontDef.pixelSize;
+ glyphRun.glyphCount = 1;
+ glyphRun.glyphIndices = &glyphIndex;
+ glyphRun.glyphAdvances = &glyphAdvance;
+ glyphRun.isSideways = false;
+ glyphRun.bidiLevel = 0;
+ glyphRun.glyphOffsets = &glyphOffset;
+
+ QFixed x = margin - metrics.x.round() + subPixelPosition;
+ QFixed y = margin - metrics.y.floor();
+
+ DWRITE_MATRIX transform;
+ transform.dx = x.toReal();
+ transform.dy = y.toReal();
+ transform.m11 = xform.m11();
+ transform.m12 = xform.m12();
+ transform.m21 = xform.m21();
+ transform.m22 = xform.m22();
+
+ IDWriteGlyphRunAnalysis *glyphAnalysis = NULL;
+ HRESULT hr = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis(
+ &glyphRun,
+ 1.0f,
+ &transform,
+ DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC,
+ DWRITE_MEASURING_MODE_NATURAL,
+ 0.0, 0.0,
+ &glyphAnalysis
+ );
+
+ if (SUCCEEDED(hr)) {
+ RECT rect;
+ rect.left = 0;
+ rect.top = 0;
+ rect.right = width;
+ rect.bottom = height;
+
+ int size = width * height * 3;
+ BYTE *alphaValues = new BYTE[size];
+ qMemSet(alphaValues, size, 0);
+
+ hr = glyphAnalysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1,
+ &rect,
+ alphaValues,
+ size);
+
+ if (SUCCEEDED(hr)) {
+ QImage img(width, height, QImage::Format_RGB32);
+ img.fill(0xffffffff);
+
+ for (int y=0; y<height; ++y) {
+ uint *dest = reinterpret_cast<uint *>(img.scanLine(y));
+ BYTE *src = alphaValues + width * 3 * y;
+
+ for (int x=0; x<width; ++x) {
+ dest[x] = *(src) << 16
+ | *(src + 1) << 8
+ | *(src + 2);
+
+ src += 3;
+ }
+ }
+
+ delete[] alphaValues;
+ glyphAnalysis->Release();
+
+ return img;
+ } else {
+ delete[] alphaValues;
+ glyphAnalysis->Release();
+
+ qErrnoWarning("%s: CreateAlphaTexture failed", __FUNCTION__);
+ }
+
+ } else {
+ qErrnoWarning("%s: CreateGlyphRunAnalysis failed", __FUNCTION__);
+ }
+
+ return QImage();
+}
+
+QImage QWindowsFontEngineDirectWrite::alphaRGBMapForGlyph(glyph_t t,
+ QFixed subPixelPosition,
+ int margin,
+ const QTransform &xform)
+{
+ QImage mask = imageForGlyph(t, subPixelPosition, margin, xform);
+ return mask.depth() == 32
+ ? mask
+ : mask.convertToFormat(QImage::Format_RGB32);
+}
+
+const char *QWindowsFontEngineDirectWrite::name() const
+{
+ return 0;
+}
+
+bool QWindowsFontEngineDirectWrite::canRender(const QChar *string, int len)
+{
+ QVarLengthArray<UINT32> codePoints(len);
+ int actualLength = 0;
+ for (int i=0; i<len; ++i, actualLength++)
+ codePoints[actualLength] = getChar(string, i, len);
+
+ QVarLengthArray<UINT16> glyphIndices(actualLength);
+ HRESULT hr = m_directWriteFontFace->GetGlyphIndices(codePoints.data(), actualLength,
+ glyphIndices.data());
+ if (FAILED(hr)) {
+ qErrnoWarning("%s: GetGlyphIndices failed", __FUNCTION__);
+ return false;
+ } else {
+ for (int i=0; i<glyphIndices.size(); ++i) {
+ if (glyphIndices.at(i) == 0)
+ return false;
+ }
+
+ return true;
+ }
+}
+
+QFontEngine::Type QWindowsFontEngineDirectWrite::type() const
+{
+ return QFontEngine::DirectWrite;
+}
+
+QFontEngine *QWindowsFontEngineDirectWrite::cloneWithSize(qreal pixelSize) const
+{
+ QFontEngine *fontEngine = new QWindowsFontEngineDirectWrite(m_directWriteFontFace,
+ pixelSize, m_fontEngineData);
+
+ fontEngine->fontDef = fontDef;
+ fontEngine->fontDef.pixelSize = pixelSize;
+
+ return fontEngine;
+}
+
+void QWindowsFontEngineDirectWrite::initFontInfo(const QFontDef &request,
+ int dpi, IDWriteFont *font)
+{
+ fontDef = request;
+
+ IDWriteFontFamily *fontFamily = NULL;
+ HRESULT hr = font->GetFontFamily(&fontFamily);
+
+ IDWriteLocalizedStrings *familyNames = NULL;
+ if (SUCCEEDED(hr))
+ hr = fontFamily->GetFamilyNames(&familyNames);
+
+ UINT32 index = 0;
+ BOOL exists = false;
+
+ wchar_t localeName[LOCALE_NAME_MAX_LENGTH];
+
+ if (SUCCEEDED(hr)) {
+ int defaultLocaleSuccess = GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH);
+
+ if (defaultLocaleSuccess)
+ hr = familyNames->FindLocaleName(localeName, &index, &exists);
+
+ if (SUCCEEDED(hr) && !exists)
+ hr = familyNames->FindLocaleName(L"en-us", &index, &exists);
+ }
+
+ if (!exists)
+ index = 0;
+
+ UINT32 length = 0;
+ if (SUCCEEDED(hr))
+ hr = familyNames->GetStringLength(index, &length);
+
+ wchar_t *name = new (std::nothrow) wchar_t[length+1];
+ if (name == NULL)
+ hr = E_OUTOFMEMORY;
+
+ // Get the family name.
+ if (SUCCEEDED(hr))
+ hr = familyNames->GetString(index, name, length + 1);
+
+ if (SUCCEEDED(hr))
+ fontDef.family = QString::fromWCharArray(name);
+
+ delete[] name;
+ if (familyNames != NULL)
+ familyNames->Release();
+
+ if (FAILED(hr))
+ qErrnoWarning(hr, "initFontInfo: Failed to get family name");
+
+ if (fontDef.pointSize < 0)
+ fontDef.pointSize = fontDef.pixelSize * 72. / dpi;
+ else if (fontDef.pixelSize == -1)
+ fontDef.pixelSize = qRound(fontDef.pointSize * dpi / 72.);
+}
+
+QString QWindowsFontEngineDirectWrite::fontNameSubstitute(const QString &familyName)
+{
+ static const char keyC[] = "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\"
+ "FontSubstitutes";
+ return QSettings(QLatin1String(keyC), QSettings::NativeFormat).value(familyName, familyName).toString();
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DIRECTWRITE
diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h
new file mode 100644
index 0000000000..1333720481
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** 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 QtGui module 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$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSFONTENGINEDIRECTWRITE_H
+#define QWINDOWSFONTENGINEDIRECTWRITE_H
+
+#ifndef QT_NO_DIRECTWRITE
+
+// Enable access to HB_Face in harfbuzz includes included by qfontengine_p.h.
+#define QT_BUILD_GUI_LIB
+#include <QtGui/private/qfontengine_p.h>
+#undef QT_BUILD_GUI_LIB
+
+#include <QtCore/QSharedPointer>
+
+class QWindowsFontEngineData;
+
+struct IDWriteFont ;
+struct IDWriteFontFace ;
+struct IDWriteFactory ;
+struct IDWriteBitmapRenderTarget ;
+struct IDWriteGdiInterop ;
+
+QT_BEGIN_NAMESPACE
+
+class QWindowsFontEngineDirectWrite : public QFontEngine
+{
+ Q_OBJECT
+public:
+ explicit QWindowsFontEngineDirectWrite(IDWriteFontFace *directWriteFontFace,
+ qreal pixelSize,
+ const QSharedPointer<QWindowsFontEngineData> &d);
+ ~QWindowsFontEngineDirectWrite();
+
+ void initFontInfo(const QFontDef &request, int dpi, IDWriteFont *font);
+
+ QFixed lineThickness() const;
+ bool getSfntTableData(uint tag, uchar *buffer, uint *length) const;
+ QFixed emSquareSize() const;
+
+ bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const;
+ void recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags) const;
+
+ void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs,
+ QPainterPath *path, QTextItem::RenderFlags flags);
+
+ glyph_metrics_t boundingBox(const QGlyphLayout &glyphs);
+ glyph_metrics_t boundingBox(glyph_t g);
+
+ QFixed ascent() const;
+ QFixed descent() const;
+ QFixed leading() const;
+ QFixed xHeight() const;
+ qreal maxCharWidth() const;
+
+ const char *name() const;
+
+ bool supportsSubPixelPositions() const;
+
+ QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition);
+ QImage alphaRGBMapForGlyph(glyph_t t, QFixed subPixelPosition, int margin,
+ const QTransform &xform);
+
+ QFontEngine *cloneWithSize(qreal pixelSize) const;
+
+ bool canRender(const QChar *string, int len);
+ Type type() const;
+
+ static QString fontNameSubstitute(const QString &familyName);
+
+private:
+ friend class QRawFontPrivate;
+
+ QImage imageForGlyph(glyph_t t, QFixed subPixelPosition, int margin, const QTransform &xform);
+ void collectMetrics();
+
+ const QSharedPointer<QWindowsFontEngineData> m_fontEngineData;
+
+ IDWriteFontFace *m_directWriteFontFace;
+ IDWriteBitmapRenderTarget *m_directWriteBitmapRenderTarget;
+
+ QFixed m_lineThickness;
+ int m_unitsPerEm;
+ QFixed m_ascent;
+ QFixed m_descent;
+ QFixed m_xHeight;
+ QFixed m_lineGap;
+ FaceId m_faceId;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DIRECTWRITE
+
+#endif // QWINDOWSFONTENGINEDIRECTWRITE_H
diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp
new file mode 100644
index 0000000000..e67f61a792
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp
@@ -0,0 +1,974 @@
+/****************************************************************************
+**
+** 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 "qwindowsglcontext.h"
+#include "qwindowscontext.h"
+#include "qwindowswindow.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QSysInfo>
+
+#include <WinGDI.h>
+#if defined(Q_CC_MINGW)
+# include <GL/Gl.h>
+#else
+# include <Gl.h>
+#endif
+
+// #define DEBUG_GL
+
+// ARB extension API
+#ifndef WGL_ARB_multisample
+#define WGL_SAMPLE_BUFFERS_ARB 0x2041
+#define WGL_SAMPLES_ARB 0x2042
+#endif
+
+#ifndef WGL_ARB_pixel_format
+#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
+#define WGL_DRAW_TO_WINDOW_ARB 0x2001
+#define WGL_DRAW_TO_BITMAP_ARB 0x2002
+#define WGL_ACCELERATION_ARB 0x2003
+#define WGL_NEED_PALETTE_ARB 0x2004
+#define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005
+#define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006
+#define WGL_SWAP_METHOD_ARB 0x2007
+#define WGL_NUMBER_OVERLAYS_ARB 0x2008
+#define WGL_NUMBER_UNDERLAYS_ARB 0x2009
+#define WGL_TRANSPARENT_ARB 0x200A
+#define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037
+#define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038
+#define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039
+#define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A
+#define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B
+#define WGL_SHARE_DEPTH_ARB 0x200C
+#define WGL_SHARE_STENCIL_ARB 0x200D
+#define WGL_SHARE_ACCUM_ARB 0x200E
+#define WGL_SUPPORT_GDI_ARB 0x200F
+#define WGL_SUPPORT_OPENGL_ARB 0x2010
+#define WGL_DOUBLE_BUFFER_ARB 0x2011
+#define WGL_STEREO_ARB 0x2012
+#define WGL_PIXEL_TYPE_ARB 0x2013
+#define WGL_COLOR_BITS_ARB 0x2014
+#define WGL_RED_BITS_ARB 0x2015
+#define WGL_RED_SHIFT_ARB 0x2016
+#define WGL_GREEN_BITS_ARB 0x2017
+#define WGL_GREEN_SHIFT_ARB 0x2018
+#define WGL_BLUE_BITS_ARB 0x2019
+#define WGL_BLUE_SHIFT_ARB 0x201A
+#define WGL_ALPHA_BITS_ARB 0x201B
+#define WGL_ALPHA_SHIFT_ARB 0x201C
+#define WGL_ACCUM_BITS_ARB 0x201D
+#define WGL_ACCUM_RED_BITS_ARB 0x201E
+#define WGL_ACCUM_GREEN_BITS_ARB 0x201F
+#define WGL_ACCUM_BLUE_BITS_ARB 0x2020
+#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021
+#define WGL_DEPTH_BITS_ARB 0x2022
+#define WGL_STENCIL_BITS_ARB 0x2023
+#define WGL_AUX_BUFFERS_ARB 0x2024
+#define WGL_NO_ACCELERATION_ARB 0x2025
+#define WGL_GENERIC_ACCELERATION_ARB 0x2026
+#define WGL_FULL_ACCELERATION_ARB 0x2027
+#define WGL_SWAP_EXCHANGE_ARB 0x2028
+#define WGL_SWAP_COPY_ARB 0x2029
+#define WGL_SWAP_UNDEFINED_ARB 0x202A
+#define WGL_TYPE_RGBA_ARB 0x202B
+#define WGL_TYPE_COLORINDEX_ARB 0x202C
+#endif
+
+#ifndef WGL_ARB_create_context
+#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
+#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
+#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093
+#define WGL_CONTEXT_FLAGS_ARB 0x2094
+#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
+#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001
+#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
+#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x0001
+#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x0002
+// Error codes returned by GetLastError().
+#define ERROR_INVALID_VERSION_ARB 0x2095
+#define ERROR_INVALID_PROFILE_ARB 0x2096
+#endif
+
+#ifndef GL_VERSION_3_2
+#define GL_CONTEXT_PROFILE_MASK 0x9126
+#define GL_MAJOR_VERSION 0x821B
+#define GL_MINOR_VERSION 0x821C
+#define GL_NUM_EXTENSIONS 0x821D
+#define GL_CONTEXT_FLAGS 0x821E
+#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x0001
+#endif
+
+QT_BEGIN_NAMESPACE
+
+template <class MaskType, class FlagType> inline bool testFlag(MaskType mask, FlagType flag)
+{
+ return (mask & MaskType(flag)) != 0;
+}
+
+static inline bool hasGLOverlay(const PIXELFORMATDESCRIPTOR &pd)
+{ return (pd.bReserved & 0x0f) != 0; }
+
+static inline bool isDirectRendering(const PIXELFORMATDESCRIPTOR &pfd)
+{ return (pfd.dwFlags & PFD_GENERIC_ACCELERATED) || !(pfd.dwFlags & PFD_GENERIC_FORMAT); }
+
+static inline void initPixelFormatDescriptor(PIXELFORMATDESCRIPTOR *d)
+{
+ memset(d, 0, sizeof(PIXELFORMATDESCRIPTOR));
+ d->nSize = sizeof(PIXELFORMATDESCRIPTOR);
+ d->nVersion = 1;
+}
+
+QDebug operator<<(QDebug d, const PIXELFORMATDESCRIPTOR &pd)
+{
+ QDebug nsp = d.nospace();
+ nsp << "PIXELFORMATDESCRIPTOR "
+ << "dwFlags=" << hex << showbase << pd.dwFlags << dec << noshowbase;
+ if (pd.dwFlags & PFD_DRAW_TO_WINDOW) nsp << " PFD_DRAW_TO_WINDOW";
+ if (pd.dwFlags & PFD_DRAW_TO_BITMAP) nsp << " PFD_DRAW_TO_BITMAP";
+ if (pd.dwFlags & PFD_SUPPORT_GDI) nsp << " PFD_SUPPORT_GDI";
+ if (pd.dwFlags & PFD_SUPPORT_OPENGL) nsp << " PFD_SUPPORT_OPENGL";
+ if (pd.dwFlags & PFD_GENERIC_ACCELERATED) nsp << " PFD_GENERIC_ACCELERATED";
+ if (pd.dwFlags & PFD_SUPPORT_DIRECTDRAW) nsp << " PFD_SUPPORT_DIRECTDRAW";
+ if (pd.dwFlags & PFD_DIRECT3D_ACCELERATED) nsp << " PFD_DIRECT3D_ACCELERATED";
+ if (pd.dwFlags & PFD_SUPPORT_COMPOSITION) nsp << " PFD_SUPPORT_COMPOSITION";
+ if (pd.dwFlags & PFD_GENERIC_FORMAT) nsp << " PFD_GENERIC_FORMAT";
+ if (pd.dwFlags & PFD_NEED_PALETTE) nsp << " PFD_NEED_PALETTE";
+ if (pd.dwFlags & PFD_NEED_SYSTEM_PALETTE) nsp << " PFD_NEED_SYSTEM_PALETTE";
+ if (pd.dwFlags & PFD_DOUBLEBUFFER) nsp << " PFD_DOUBLEBUFFER";
+ if (pd.dwFlags & PFD_STEREO) nsp << " PFD_STEREO";
+ if (pd.dwFlags & PFD_SWAP_LAYER_BUFFERS) nsp << " PFD_SWAP_LAYER_BUFFERS";
+ if (hasGLOverlay(pd)) nsp << " overlay";
+ nsp << " iPixelType=" << pd.iPixelType << " cColorBits=" << pd.cColorBits
+ << " cRedBits=" << pd.cRedBits << " cRedShift=" << pd.cRedShift
+ << " cGreenBits=" << pd.cGreenBits << " cGreenShift=" << pd.cGreenShift
+ << " cBlueBits=" << pd.cBlueBits << " cBlueShift=" << pd.cBlueShift;
+ nsp << " cDepthBits=" << pd.cDepthBits;
+ if (pd.cStencilBits)
+ nsp << " cStencilBits=" << pd.cStencilBits;
+ if (pd.cAuxBuffers)
+ nsp << " cAuxBuffers=" << pd.cAuxBuffers;
+ nsp << " iLayerType=" << pd.iLayerType;
+ if (pd.dwVisibleMask)
+ nsp << " dwVisibleMask=" << pd.dwVisibleMask;
+ if (pd.cAlphaBits)
+ nsp << " cAlphaBits=" << pd.cAlphaBits << " cAlphaShift=" << pd.cAlphaShift;
+ if (pd.cAccumBits)
+ nsp << " cAccumBits=" << pd.cAccumBits << " cAccumRedBits=" << pd.cAccumRedBits
+ << " cAccumGreenBits=" << pd.cAccumGreenBits << " cAccumBlueBits=" << pd.cAccumBlueBits
+ << " cAccumAlphaBits=" << pd.cAccumAlphaBits;
+ return d;
+}
+
+// Check whether an obtained PIXELFORMATDESCRIPTOR matches the request.
+static inline bool
+ isAcceptableFormat(const QWindowsOpenGLAdditionalFormat &additional,
+ const PIXELFORMATDESCRIPTOR &pfd,
+ bool ignoreGLSupport = false) // ARB format may not contain it.
+{
+ const bool pixmapRequested = testFlag(additional.formatFlags, QWindowsGLRenderToPixmap);
+ return (ignoreGLSupport || testFlag(pfd.dwFlags, PFD_SUPPORT_OPENGL))
+ && testFlag(pfd.dwFlags, PFD_DRAW_TO_BITMAP) == pixmapRequested
+ && hasGLOverlay(pfd) == testFlag(additional.formatFlags, QWindowsGLOverlay)
+ && (!pixmapRequested || pfd.cColorBits == additional.pixmapDepth);
+}
+
+static void describeFormats(HDC hdc)
+{
+ const int pfiMax = DescribePixelFormat(hdc, 0, 0, NULL);
+ for (int i = 0; i < pfiMax; i++) {
+ PIXELFORMATDESCRIPTOR pfd;
+ initPixelFormatDescriptor(&pfd);
+ DescribePixelFormat(hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
+ qDebug() << '#' << i << '/' << pfiMax << ':' << pfd;
+ }
+}
+
+// Classic GDI API
+namespace GDI {
+static QSurfaceFormat
+ qSurfaceFormatFromPixelFormat(const PIXELFORMATDESCRIPTOR &pfd,
+ QWindowsOpenGLAdditionalFormat *additionalIn = 0)
+{
+ QSurfaceFormat format;
+ if (pfd.dwFlags & PFD_DOUBLEBUFFER)
+ format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
+ format.setDepthBufferSize(pfd.cDepthBits);
+
+ if (pfd.iPixelType == PFD_TYPE_RGBA)
+ format.setAlphaBufferSize(pfd.cAlphaBits);
+ format.setRedBufferSize(pfd.cRedBits);
+ format.setGreenBufferSize(pfd.cGreenBits);
+ format.setBlueBufferSize(pfd.cBlueBits);
+ format.setStencilBufferSize(pfd.cStencilBits);
+ format.setStereo(pfd.dwFlags & PFD_STEREO);
+ if (additionalIn) {
+ QWindowsOpenGLAdditionalFormat additional;
+ if (isDirectRendering(pfd))
+ additional.formatFlags |= QWindowsGLDirectRendering;
+ if (hasGLOverlay(pfd))
+ additional.formatFlags |= QWindowsGLOverlay;
+ if (pfd.cAccumRedBits)
+ additional.formatFlags |= QWindowsGLAccumBuffer;
+ if (testFlag(pfd.dwFlags, PFD_DRAW_TO_BITMAP)) {
+ additional.formatFlags |= QWindowsGLRenderToPixmap;
+ additional.pixmapDepth = pfd.cColorBits;
+ }
+ *additionalIn = additional;
+ }
+ return format;
+}
+
+static PIXELFORMATDESCRIPTOR
+ qPixelFormatFromSurfaceFormat(const QSurfaceFormat &format,
+ const QWindowsOpenGLAdditionalFormat &additional)
+{
+ PIXELFORMATDESCRIPTOR pfd;
+ initPixelFormatDescriptor(&pfd);
+ pfd.iPixelType = PFD_TYPE_RGBA;
+ pfd.iLayerType = PFD_MAIN_PLANE;
+ pfd.dwFlags = PFD_SUPPORT_OPENGL;
+ if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA)
+ pfd.dwFlags = PFD_SUPPORT_COMPOSITION;
+ const bool isPixmap = (additional.formatFlags & QWindowsGLRenderToPixmap) != 0;
+ pfd.dwFlags |= isPixmap ? PFD_DRAW_TO_BITMAP : PFD_DRAW_TO_WINDOW;
+ if (!(additional.formatFlags & QWindowsGLDirectRendering))
+ pfd.dwFlags |= PFD_GENERIC_FORMAT;
+
+ if (format.stereo())
+ pfd.dwFlags |= PFD_STEREO;
+ if (format.swapBehavior() == QSurfaceFormat::DoubleBuffer && !isPixmap)
+ pfd.dwFlags |= PFD_DOUBLEBUFFER;
+ pfd.cDepthBits =
+ format.depthBufferSize() >= 0 ? format.depthBufferSize() : 32;
+ pfd.cAlphaBits = format.alphaBufferSize() > 0 ? format.alphaBufferSize() : 8;
+ pfd.cStencilBits = format.stencilBufferSize() > 0 ? format.stencilBufferSize() : 8;
+ if (additional.formatFlags & QWindowsGLAccumBuffer)
+ pfd.cAccumRedBits = pfd.cAccumGreenBits = pfd.cAccumBlueBits = pfd.cAccumAlphaBits = 16;
+ return pfd;
+}
+
+// Choose a suitable pixelformat using GDI WinAPI in case ARB
+// functions cannot be found. First tries to find a suitable
+// format using GDI function ChoosePixelFormat(). Since that
+// does not handle overlay and direct-rendering requests, manually loop
+// over the available formats to find the best one.
+// Note: As of Windows 7, it seems direct-rendering is handled, so,
+// the code might be obsolete?
+static int choosePixelFormat(HDC hdc, const QSurfaceFormat &format,
+ const QWindowsOpenGLAdditionalFormat &additional,
+ PIXELFORMATDESCRIPTOR *obtainedPfd)
+{
+ // 1) Try ChoosePixelFormat().
+ PIXELFORMATDESCRIPTOR requestedPfd = qPixelFormatFromSurfaceFormat(format, QWindowsGLDirectRendering);
+ initPixelFormatDescriptor(obtainedPfd);
+ int pixelFormat = ChoosePixelFormat(hdc, &requestedPfd);
+ if (pixelFormat >= 0) {
+ DescribePixelFormat(hdc, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), obtainedPfd);
+ if (isAcceptableFormat(additional, *obtainedPfd))
+ return pixelFormat;
+ }
+ // 2) No matching format found, manual search loop.
+ const int pfiMax = DescribePixelFormat(hdc, 0, 0, NULL);
+ int bestScore = -1;
+ int bestPfi = -1;
+ const bool stereoRequested = format.stereo();
+ const bool accumBufferRequested = testFlag(additional.formatFlags, QWindowsGLAccumBuffer);
+ const bool doubleBufferRequested = format.swapBehavior() == QSurfaceFormat::DoubleBuffer;
+ const bool directRenderingRequested = testFlag(additional.formatFlags, QWindowsGLDirectRendering);
+ for (int pfi = 1; pfi <= pfiMax; pfi++) {
+ PIXELFORMATDESCRIPTOR checkPfd;
+ initPixelFormatDescriptor(&checkPfd);
+ DescribePixelFormat(hdc, pfi, sizeof(PIXELFORMATDESCRIPTOR), &checkPfd);
+ if (isAcceptableFormat(additional, checkPfd)) {
+ int score = checkPfd.cColorBits + checkPfd.cAlphaBits + checkPfd.cStencilBits;
+ if (accumBufferRequested)
+ score += checkPfd.cAccumBits;
+ if (doubleBufferRequested == testFlag(checkPfd.dwFlags, PFD_DOUBLEBUFFER))
+ score += 1000;
+ if (stereoRequested == testFlag(checkPfd.dwFlags, PFD_STEREO))
+ score += 2000;
+ if (directRenderingRequested == isDirectRendering(checkPfd))
+ score += 4000;
+ if (checkPfd.iPixelType == PFD_TYPE_RGBA)
+ score += 8000;
+ if (score > bestScore) {
+ bestScore = score;
+ bestPfi = pfi;
+ *obtainedPfd = checkPfd;
+ }
+ if (QWindowsContext::verboseGL)
+ qDebug() << __FUNCTION__ << " checking " << pfi << '/' << pfiMax
+ << " score=" << score << " (best " << bestPfi << '/' << bestScore
+ << ") " << checkPfd;
+ }
+ } // for
+ if (bestPfi > 0)
+ pixelFormat = bestPfi;
+ return pixelFormat;
+}
+
+static inline HGLRC createContext(HDC hdc, HGLRC shared)
+{
+ HGLRC result = wglCreateContext(hdc);
+ if (!result) {
+ qErrnoWarning("%s: wglCreateContext failed.", __FUNCTION__);
+ return 0;
+ }
+ if (shared && !wglShareLists(shared, result))
+ qErrnoWarning("%s: wglShareLists() failed.", __FUNCTION__);
+ return result;
+}
+} // namespace GDI
+
+// ARB OpenGL extension API
+namespace ARB {
+// Choose a suitable pixelformat using ARB extension functions.
+static int choosePixelFormat(HDC hdc,
+ const QOpenGLStaticContext &staticContext,
+ const QSurfaceFormat &format,
+ const QWindowsOpenGLAdditionalFormat &additional,
+ PIXELFORMATDESCRIPTOR *obtainedPfd)
+{
+ enum { attribSize =40 };
+ if ((additional.formatFlags & QWindowsGLRenderToPixmap) || !staticContext.hasExtensions())
+ return 0;
+
+ int iAttributes[attribSize];
+ qFill(iAttributes, iAttributes + attribSize, int(0));
+ int i = 0;
+ iAttributes[i++] = WGL_ACCELERATION_ARB;
+ iAttributes[i++] = testFlag(additional.formatFlags, QWindowsGLDirectRendering) ?
+ WGL_FULL_ACCELERATION_ARB : WGL_NO_ACCELERATION_ARB;
+ iAttributes[i++] = WGL_SUPPORT_OPENGL_ARB;
+ iAttributes[i++] = TRUE;
+ iAttributes[i++] = WGL_DRAW_TO_WINDOW_ARB;
+ iAttributes[i++] = TRUE;
+ iAttributes[i++] = WGL_COLOR_BITS_ARB;
+ iAttributes[i++] = 24;
+ switch (format.swapBehavior()) {
+ case QSurfaceFormat::DefaultSwapBehavior:
+ case QSurfaceFormat::TripleBuffer:
+ break;
+ case QSurfaceFormat::SingleBuffer:
+ iAttributes[i++] = WGL_DOUBLE_BUFFER_ARB;
+ iAttributes[i++] = FALSE;
+ break;
+ case QSurfaceFormat::DoubleBuffer:
+ iAttributes[i++] = WGL_DOUBLE_BUFFER_ARB;
+ iAttributes[i++] = TRUE;
+ break;
+ }
+ if (format.stereo()) {
+ iAttributes[i++] = WGL_STEREO_ARB;
+ iAttributes[i++] = TRUE;
+ }
+ if (format.depthBufferSize() >= 0) {
+ iAttributes[i++] = WGL_DEPTH_BITS_ARB;
+ iAttributes[i++] = format.depthBufferSize();
+ }
+ iAttributes[i++] = WGL_PIXEL_TYPE_ARB;
+ iAttributes[i++] = WGL_TYPE_RGBA_ARB;
+ if (format.redBufferSize() >= 0) {
+ iAttributes[i++] = WGL_RED_BITS_ARB;
+ iAttributes[i++] = format.redBufferSize();
+ }
+ if (format.greenBufferSize() >= 0) {
+ iAttributes[i++] = WGL_GREEN_BITS_ARB;
+ iAttributes[i++] = format.greenBufferSize();
+ }
+ if (format.blueBufferSize() >= 0) {
+ iAttributes[i++] = WGL_BLUE_BITS_ARB;
+ iAttributes[i++] = format.blueBufferSize();
+ }
+ iAttributes[i++] = WGL_ALPHA_BITS_ARB;
+ iAttributes[i++] = format.alphaBufferSize() >= 0 ? format.alphaBufferSize() : 8;
+ if (additional.formatFlags & QWindowsGLAccumBuffer) {
+ iAttributes[i++] = WGL_ACCUM_BITS_ARB;
+ iAttributes[i++] = 16;
+ }
+ iAttributes[i++] = WGL_STENCIL_BITS_ARB;
+ iAttributes[i++] = 8;
+ if (additional.formatFlags & QWindowsGLOverlay) {
+ iAttributes[i++] = WGL_NUMBER_OVERLAYS_ARB;
+ iAttributes[i++] = 1;
+ }
+ const bool sampleBuffersRequested = format.samples() > 1
+ && testFlag(staticContext.extensions, QOpenGLStaticContext::SampleBuffers);
+ int samplesValuePosition = 0;
+ int samplesEnabledPosition = 0;
+ if (sampleBuffersRequested) {
+ iAttributes[i++] = WGL_SAMPLE_BUFFERS_ARB;
+ samplesEnabledPosition = i;
+ iAttributes[i++] = TRUE;
+ iAttributes[i++] = WGL_SAMPLES_ARB;
+ samplesValuePosition = i;
+ iAttributes[i++] = format.samples();
+ }
+ // If sample buffer request cannot be satisfied, reduce request.
+ int pixelFormat = 0;
+ uint numFormats = 0;
+ while (true) {
+ const bool valid =
+ staticContext.wglChoosePixelFormatARB(hdc, iAttributes, 0, 1,
+ &pixelFormat, &numFormats)
+ && numFormats >= 1;
+ if (valid || !sampleBuffersRequested)
+ break;
+ if (iAttributes[samplesValuePosition] > 1) {
+ iAttributes[samplesValuePosition] /= 2;
+ } else {
+ break;
+ }
+ }
+ // Verify if format is acceptable. Note that the returned
+ // formats have been observed to not contain PFD_SUPPORT_OPENGL, ignore.
+ initPixelFormatDescriptor(obtainedPfd);
+ DescribePixelFormat(hdc, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), obtainedPfd);
+ if (!isAcceptableFormat(additional, *obtainedPfd, true)) {
+ if (QWindowsContext::verboseGL)
+ qDebug() << __FUNCTION__ << " obtained px #" << pixelFormat
+ << " not acceptable=" << *obtainedPfd;
+ pixelFormat = 0;
+ }
+
+ if (QWindowsContext::verboseGL) {
+ QDebug nsp = qDebug().nospace();
+ nsp << __FUNCTION__;
+ if (sampleBuffersRequested)
+ nsp << " samples=" << iAttributes[samplesValuePosition];
+ nsp << " Attributes: " << hex << showbase;
+ for (int ii = 0; ii < i; ++ii)
+ nsp << iAttributes[ii] << ',';
+ nsp << noshowbase << dec << "\n obtained px #" << pixelFormat
+ << " of " << numFormats << "\n " << *obtainedPfd;
+ } // Debug
+
+ return pixelFormat;
+}
+
+static QSurfaceFormat
+ qSurfaceFormatFromHDC(const QOpenGLStaticContext &staticContext,
+ HDC hdc, int pixelFormat,
+ QWindowsOpenGLAdditionalFormat *additionalIn = 0)
+{
+ enum { attribSize =40 };
+
+ QSurfaceFormat result;
+ if (!staticContext.hasExtensions())
+ return result;
+ int iAttributes[attribSize];
+ int iValues[attribSize];
+ qFill(iAttributes, iAttributes + attribSize, int(0));
+ qFill(iValues, iValues + attribSize, int(0));
+
+ int i = 0;
+ const bool hasSampleBuffers = testFlag(staticContext.extensions, QOpenGLStaticContext::SampleBuffers);
+
+ iAttributes[i++] = WGL_DOUBLE_BUFFER_ARB; // 0
+ iAttributes[i++] = WGL_DEPTH_BITS_ARB; // 1
+ iAttributes[i++] = WGL_PIXEL_TYPE_ARB; // 2
+ iAttributes[i++] = WGL_RED_BITS_ARB; // 3
+ iAttributes[i++] = WGL_GREEN_BITS_ARB; // 4
+ iAttributes[i++] = WGL_BLUE_BITS_ARB; // 5
+ iAttributes[i++] = WGL_ALPHA_BITS_ARB; // 6
+ iAttributes[i++] = WGL_ACCUM_BITS_ARB; // 7
+ iAttributes[i++] = WGL_STENCIL_BITS_ARB; // 8
+ iAttributes[i++] = WGL_STEREO_ARB; // 9
+ iAttributes[i++] = WGL_ACCELERATION_ARB; // 10
+ iAttributes[i++] = WGL_NUMBER_OVERLAYS_ARB; // 11
+ if (hasSampleBuffers) {
+ iAttributes[i++] = WGL_SAMPLE_BUFFERS_ARB; // 12
+ iAttributes[i++] = WGL_SAMPLES_ARB; // 13
+ }
+ if (!staticContext.wglGetPixelFormatAttribIVARB(hdc, pixelFormat, 0, i,
+ iAttributes, iValues))
+ return result;
+ if (iValues[0])
+ result.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
+ result.setDepthBufferSize(iValues[1]);
+ result.setRedBufferSize(iValues[3]);
+ result.setGreenBufferSize(iValues[4]);
+ result.setBlueBufferSize(iValues[5]);
+ result.setAlphaBufferSize(iValues[6]);
+ result.setStencilBufferSize(iValues[8]);
+ result.setStereo(iValues[9]);
+ if (hasSampleBuffers)
+ result.setSamples(iValues[13]);
+ if (additionalIn) {
+ if (iValues[7])
+ additionalIn->formatFlags |= QWindowsGLAccumBuffer;
+ if (iValues[10] == WGL_FULL_ACCELERATION_ARB)
+ additionalIn->formatFlags |= QWindowsGLDirectRendering;
+ if (iValues[11])
+ additionalIn->formatFlags |= QWindowsGLOverlay;
+ }
+ return result;
+}
+
+static HGLRC createContext(const QOpenGLStaticContext &staticContext,
+ HDC hdc,
+ const QSurfaceFormat &format,
+ const QWindowsOpenGLAdditionalFormat &additional,
+ int majorVersion = 0,
+ int minorVersion = 0,
+ HGLRC shared = 0)
+{
+ enum { attribSize = 11 };
+
+ if (!staticContext.hasExtensions())
+ return 0;
+ int attributes[attribSize];
+ int attribIndex = 0;
+ qFill(attributes, attributes + attribSize, int(0));
+
+ if (majorVersion) {
+ attributes[attribIndex++] = WGL_CONTEXT_MAJOR_VERSION_ARB;
+ attributes[attribIndex++] = majorVersion;
+ attributes[attribIndex++] = WGL_CONTEXT_MINOR_VERSION_ARB;
+ attributes[attribIndex++] = minorVersion;
+ }
+ if (majorVersion >= 3 && additional.formatFlags & QWindowsGLDeprecatedFunctions) {
+ attributes[attribIndex++] = WGL_CONTEXT_FLAGS_ARB;
+ attributes[attribIndex++] = WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
+ }
+ if ((staticContext.majorVersion == 3 && staticContext.minorVersion >= 2)
+ || staticContext.majorVersion > 3) {
+ const QSurfaceFormat::OpenGLContextProfile profile = QSurfaceFormat::NoProfile;
+ // format.profile(): TODO: Not implemented yet.
+ Q_UNUSED(format);
+ switch (profile) {
+ case QSurfaceFormat::NoProfile:
+ break;
+ case QSurfaceFormat::CoreProfile:
+ attributes[attribIndex++] = WGL_CONTEXT_PROFILE_MASK_ARB;
+ attributes[attribIndex++] = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
+ break;
+ case QSurfaceFormat::CompatibilityProfile:
+ attributes[attribIndex++] = WGL_CONTEXT_PROFILE_MASK_ARB;
+ attributes[attribIndex++] = WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
+ break;
+ }
+ }
+ const HGLRC result =
+ staticContext.wglCreateContextAttribsARB(hdc, shared, attributes);
+ if (!result)
+ qErrnoWarning("%s: wglCreateContextAttribsARB() failed.", __FUNCTION__);
+ return result;
+}
+
+} // namespace ARB
+
+// Helpers for temporary contexts
+static inline HWND createDummyGLWindow()
+{
+ return QWindowsContext::instance()->
+ createDummyWindow(QStringLiteral("QtOpenGLDummyWindow"),
+ L"OpenGLDummyWindow", 0, WS_OVERLAPPED | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
+}
+
+// Create a dummy GL context (see QOpenGLTemporaryContext).
+static inline HGLRC createDummyGLContext(HDC dc)
+{
+ if (!dc)
+ return 0;
+ PIXELFORMATDESCRIPTOR pixelFormDescriptor;
+ initPixelFormatDescriptor(&pixelFormDescriptor);
+ pixelFormDescriptor.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_GENERIC_FORMAT;
+ pixelFormDescriptor.iPixelType = PFD_TYPE_RGBA;
+ const int pixelFormat = ChoosePixelFormat(dc, &pixelFormDescriptor);
+ if (!pixelFormat) {
+ qErrnoWarning("%s: ChoosePixelFormat failed.", __FUNCTION__);
+ return 0;
+ }
+ if (!SetPixelFormat(dc, pixelFormat, &pixelFormDescriptor)) {
+ qErrnoWarning("%s: SetPixelFormat failed.", __FUNCTION__);
+ return 0;
+ }
+ HGLRC rc = wglCreateContext(dc);
+ if (!rc) {
+ qErrnoWarning("%s: wglCreateContext failed.", __FUNCTION__);
+ return 0;
+ }
+ return rc;
+}
+
+static inline QOpenGLContextData currentOpenGLContextData()
+{
+ QOpenGLContextData result;
+ result.hdc = wglGetCurrentDC();
+ result.renderingContext = wglGetCurrentContext();
+ return result;
+}
+
+static inline QOpenGLContextData createDummyWindowOpenGLContextData()
+{
+ QOpenGLContextData result;
+ result.hwnd = createDummyGLWindow();
+ result.hdc = GetDC(result.hwnd);
+ result.renderingContext = createDummyGLContext(result.hdc);
+ return result;
+}
+
+/*!
+ \class QOpenGLTemporaryContext
+ \brief A temporary context that can be instantiated on the stack.
+
+ Functions like wglGetProcAddress() or glGetString() only work if there
+ is a current GL context.
+
+ \ingroup qt-lighthouse-win
+*/
+
+class QOpenGLTemporaryContext
+{
+ Q_DISABLE_COPY(QOpenGLTemporaryContext)
+public:
+ QOpenGLTemporaryContext();
+ ~QOpenGLTemporaryContext();
+
+private:
+ const QOpenGLContextData m_previous;
+ const QOpenGLContextData m_current;
+};
+
+QOpenGLTemporaryContext::QOpenGLTemporaryContext() :
+ m_previous(currentOpenGLContextData()),
+ m_current(createDummyWindowOpenGLContextData())
+{
+ wglMakeCurrent(m_current.hdc, m_current.renderingContext);
+}
+
+QOpenGLTemporaryContext::~QOpenGLTemporaryContext()
+{
+ wglMakeCurrent(m_previous.hdc, m_previous.renderingContext);
+ ReleaseDC(m_current.hwnd, m_current.hdc);
+ DestroyWindow(m_current.hwnd);
+ wglDeleteContext(m_current.renderingContext);
+}
+
+/*!
+ \class QWindowsOpenGLAdditionalFormat
+ \brief Additional format information that is not in QSurfaceFormat
+ \ingroup qt-lighthouse-win
+*/
+
+/*!
+ \class QOpenGLStaticContext
+ \brief Static Open GL context containing version information, extension function pointers, etc.
+
+ Functions pending integration in the next version of OpenGL are post-fixed ARB.
+
+ \note Initialization requires an active context (see create()).
+
+ \sa QWindowsGLContext
+ \ingroup qt-lighthouse-win
+*/
+
+#define SAMPLE_BUFFER_EXTENSION "GL_ARB_multisample"
+
+QOpenGLStaticContext::QOpenGLStaticContext() :
+ vendor(QOpenGLStaticContext::getGlString(GL_VENDOR)),
+ renderer(QOpenGLStaticContext::getGlString(GL_RENDERER)),
+ extensionNames(QOpenGLStaticContext::getGlString(GL_EXTENSIONS)),
+ majorVersion(0), minorVersion(0),
+ extensions(0),
+ wglGetPixelFormatAttribIVARB((WglGetPixelFormatAttribIVARB)wglGetProcAddress("wglGetPixelFormatAttribivARB")),
+ wglChoosePixelFormatARB((WglChoosePixelFormatARB)wglGetProcAddress("wglChoosePixelFormatARB")),
+ wglCreateContextAttribsARB((WglCreateContextAttribsARB)wglGetProcAddress("wglCreateContextAttribsARB"))
+{
+ if (extensionNames.startsWith(SAMPLE_BUFFER_EXTENSION" ")
+ || extensionNames.indexOf(" "SAMPLE_BUFFER_EXTENSION" ") != -1)
+ extensions |= SampleBuffers;
+ // Get version
+ do {
+ const QByteArray version = QOpenGLStaticContext::getGlString(GL_VERSION);
+ if (version.isEmpty())
+ break;
+ const int majorDot = version.indexOf('.');
+ if (majorDot == -1)
+ break;
+ int minorDot = version.indexOf('.', majorDot + 1);
+ if (minorDot == -1)
+ minorDot = version.size();
+ majorVersion = version.mid(0, majorDot).toInt();
+ minorVersion = version.mid(majorDot + 1, minorDot - majorDot - 1).toInt();
+ } while (false);
+}
+
+QByteArray QOpenGLStaticContext::getGlString(unsigned int which)
+{
+ if (const GLubyte *s = glGetString(which))
+ return QByteArray((const char*)s);
+ return QByteArray();
+}
+
+QOpenGLStaticContext *QOpenGLStaticContext::create()
+{
+ // We need a current context for wglGetProcAdress()/getGLString() to work.
+ QScopedPointer<QOpenGLTemporaryContext> temporaryContext;
+ if (!wglGetCurrentContext())
+ temporaryContext.reset(new QOpenGLTemporaryContext);
+ QOpenGLStaticContext *result = new QOpenGLStaticContext;
+ if (QWindowsContext::verboseGL)
+ qDebug() << __FUNCTION__ << *result;
+ return result;
+}
+
+QDebug operator<<(QDebug d, const QOpenGLStaticContext &s)
+{
+ QDebug nsp = d.nospace();
+ nsp << "OpenGL: " << s.vendor << ',' << s.renderer << ",v"
+ << s.majorVersion << '.' << s.minorVersion;
+ if (s.extensions & QOpenGLStaticContext::SampleBuffers)
+ nsp << ",SampleBuffers";
+ if (s.hasExtensions())
+ nsp << ", Extension-API present";
+ nsp << "\nExtensions: " << s.extensionNames;
+ return d;
+}
+
+/*!
+ \class QWindowsGLContext
+ \brief Open GL context.
+
+ An Open GL context for use with several windows.
+ As opposed to other implementations, activating a GL context for
+ a window requires a HDC allocated for it. The first time this
+ HDC is created for the window, the pixel format must be applied,
+ which will affect the window as well. The HDCs are stored in a list of
+ QOpenGLContextData and are released in doneCurrent().
+
+ \ingroup qt-lighthouse-win
+*/
+
+QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContext,
+ QGuiGLContext *context) :
+ m_staticContext(staticContext),
+ m_context(context),
+ m_pixelFormat(0), m_extensionsUsed(false)
+{
+ // workaround for matrox driver:
+ // make a cheap call to opengl to force loading of DLL
+ static bool opengl32dll = false;
+ if (!opengl32dll) {
+ GLint params;
+ glGetIntegerv(GL_DEPTH_BITS, &params);
+ opengl32dll = true;
+ }
+
+ // SetPixelFormat (as of Windows 7) requires a real window.
+ // Create a dummy one as we are not associated with a window yet.
+ // Try to find a suitable pixel format using preferably ARB extensions
+ // (default to GDI) and store that.
+ HWND dummyWindow = 0;
+ HDC hdc = 0;
+ do {
+ dummyWindow = createDummyGLWindow();
+ if (!dummyWindow)
+ break;
+ hdc = GetDC(dummyWindow);
+ if (!hdc)
+ break;
+
+ if (QWindowsContext::verboseGL > 1)
+ describeFormats(hdc);
+ // Preferably use direct rendering and ARB extensions (unless pixmap)
+ const QWindowsOpenGLAdditionalFormat
+ requestedAdditional(QWindowsGLDirectRendering|QWindowsGLDeprecatedFunctions);
+ const bool tryExtensions = m_staticContext->hasExtensions()
+ && !testFlag(requestedAdditional.formatFlags, QWindowsGLRenderToPixmap);
+ QWindowsOpenGLAdditionalFormat obtainedAdditional;
+ if (tryExtensions) {
+ m_pixelFormat =
+ ARB::choosePixelFormat(hdc, *m_staticContext, context->format(),
+ requestedAdditional, &m_obtainedPixelFormatDescriptor);
+ if (m_pixelFormat > 0) {
+ m_obtainedFormat =
+ ARB::qSurfaceFormatFromHDC(*m_staticContext, hdc, m_pixelFormat,
+ &obtainedAdditional);
+ m_extensionsUsed = true;
+ }
+ } // tryExtensions
+ if (!m_pixelFormat) { // Failed, try GDI
+ m_pixelFormat = GDI::choosePixelFormat(hdc, context->format(), requestedAdditional,
+ &m_obtainedPixelFormatDescriptor);
+ if (m_pixelFormat)
+ m_obtainedFormat =
+ GDI::qSurfaceFormatFromPixelFormat(m_obtainedPixelFormatDescriptor,
+ &obtainedAdditional);
+ } // try GDI
+ if (!m_pixelFormat) {
+ qWarning("%s: Unable find a suitable pixel format.", __FUNCTION__);
+ break;
+ }
+ if (!SetPixelFormat(hdc, m_pixelFormat, &m_obtainedPixelFormatDescriptor)) {
+ qErrnoWarning("SetPixelFormat failed.");
+ break;
+ }
+ // Create context with sharing, again preferably using ARB.
+ HGLRC sharingRenderingContext = 0;
+ if (const QPlatformGLContext *sc = context->shareHandle())
+ sharingRenderingContext = static_cast<const QWindowsGLContext *>(sc)->renderingContext();
+
+ if (m_extensionsUsed)
+ m_renderingContext =
+ ARB::createContext(*m_staticContext, hdc, context->format(),
+ requestedAdditional, 0, 0, sharingRenderingContext);
+ if (!m_renderingContext)
+ m_renderingContext = GDI::createContext(hdc, sharingRenderingContext);
+
+ if (!m_renderingContext) {
+ qWarning("Unable to create a GL Context.");
+ break;
+ }
+ } while (false);
+ if (hdc)
+ ReleaseDC(dummyWindow, hdc);
+ if (dummyWindow)
+ DestroyWindow(dummyWindow);
+
+ if (QWindowsContext::verboseGL)
+ qDebug()
+ << __FUNCTION__ << this << " requested: " << context->format()
+ << "\n obtained #" << m_pixelFormat << (m_extensionsUsed ? "ARB" : "GDI")
+ << m_obtainedFormat << "\n " << m_obtainedPixelFormatDescriptor
+ << "\n HGLRC=" << m_renderingContext;
+}
+
+QWindowsGLContext::~QWindowsGLContext()
+{
+ if (m_renderingContext)
+ wglDeleteContext(m_renderingContext);
+ releaseDCs();
+}
+
+void QWindowsGLContext::releaseDCs()
+{
+ const QOpenGLContextData *end = m_windowContexts.end();
+ for (const QOpenGLContextData *p = m_windowContexts.begin(); p < end; ++p)
+ ReleaseDC(p->hwnd, p->hdc);
+ m_windowContexts.resize(0);
+}
+
+static inline QWindowsWindow *glWindowOf(QPlatformSurface *s)
+{
+ return static_cast<QWindowsWindow *>(s);
+}
+
+static inline HWND handleOf(QPlatformSurface *s)
+{
+ return glWindowOf(s)->handle();
+}
+
+// Find a window in a context list.
+static inline const QOpenGLContextData *
+ findByHWND(const Array<QOpenGLContextData> &data, HWND hwnd)
+{
+ const QOpenGLContextData *end = data.end();
+ for (const QOpenGLContextData *p = data.begin(); p < end; ++p)
+ if (p->hwnd == hwnd)
+ return p;
+ return 0;
+}
+
+void QWindowsGLContext::swapBuffers(QPlatformSurface *surface)
+{
+ if (QWindowsContext::verboseGL > 1)
+ qDebug() << __FUNCTION__ << surface;
+ if (const QOpenGLContextData *contextData = findByHWND(m_windowContexts, handleOf(surface))) {
+ SwapBuffers(contextData->hdc);
+ } else {
+ qWarning("%s: Cannot find window %p", __FUNCTION__, handleOf(surface));
+ }
+}
+
+bool QWindowsGLContext::makeCurrent(QPlatformSurface *surface)
+{
+#ifdef DEBUG_GL
+ if (QWindowsContext::verboseGL > 1)
+ qDebug("%s context=%p contexts=%d", __FUNCTION__, this, m_windowContexts.size());
+#endif // DEBUG_GL
+ // Do we already have a DC entry for that window?
+ QWindowsWindow *window = static_cast<QWindowsWindow *>(surface);
+ const HWND hwnd = window->handle();
+ if (const QOpenGLContextData *contextData = findByHWND(m_windowContexts, hwnd))
+ return wglMakeCurrent(contextData->hdc, contextData->renderingContext);
+ // Create a new entry.
+ const QOpenGLContextData newContext(m_renderingContext, hwnd, GetDC(hwnd));
+ if (!newContext.hdc)
+ return false;
+ // Initialize pixel format first time. This will apply to
+ // the HWND as well and must be done only once.
+ if (!window->testFlag(QWindowsWindow::PixelFormatInitialized)) {
+ if (!SetPixelFormat(newContext.hdc, m_pixelFormat, &m_obtainedPixelFormatDescriptor)) {
+ qErrnoWarning("%s: SetPixelFormat() failed", __FUNCTION__);
+ ReleaseDC(newContext.hwnd, newContext.hdc);
+ return false;
+ }
+ window->setFlag(QWindowsWindow::PixelFormatInitialized);
+ }
+ m_windowContexts.append(newContext);
+ return wglMakeCurrent(newContext.hdc, newContext.renderingContext);
+}
+
+void QWindowsGLContext::doneCurrent()
+{
+#ifdef DEBUG_GL
+ if (QWindowsContext::verboseGL > 1)
+ qDebug("%s context=%p %d contexts", __FUNCTION__, this, m_windowContexts.size());
+#endif // DEBUG_GL
+ wglMakeCurrent(0, 0);
+ releaseDCs();
+}
+
+QWindowsGLContext::GL_Proc QWindowsGLContext::getProcAddress(const QByteArray &procName)
+{
+ // TODO: Will that work with the calling conventions?
+ GL_Proc procAddress = reinterpret_cast<GL_Proc>(wglGetProcAddress(procName.constData()));
+ if (QWindowsContext::verboseGL)
+ qDebug("%s('%s') with current_hglrc=%p returns %p",
+ __FUNCTION__, procName.constData(),
+ wglGetCurrentContext(), procAddress);
+ return procAddress;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsglcontext.h b/src/plugins/platforms/windows/qwindowsglcontext.h
new file mode 100644
index 0000000000..c5edd8978f
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsglcontext.h
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSGLCONTEXT_H
+#define QWINDOWSGLCONTEXT_H
+
+#include "array.h"
+#include "qtwindows_additional.h"
+
+#include <QtGui/QPlatformGLContext>
+#include <QtGui/QGuiGLContext>
+#include <QtCore/QSharedPointer>
+
+QT_BEGIN_NAMESPACE
+
+class QDebug;
+
+enum QWindowsGLFormatFlags
+{
+ QWindowsGLDirectRendering = 0x1,
+ QWindowsGLOverlay = 0x2,
+ QWindowsGLRenderToPixmap = 0x4,
+ QWindowsGLAccumBuffer = 0x8,
+ QWindowsGLDeprecatedFunctions = 0x10
+};
+
+// Additional format information for Windows.
+struct QWindowsOpenGLAdditionalFormat
+{
+ QWindowsOpenGLAdditionalFormat(unsigned formatFlagsIn = 0, unsigned pixmapDepthIn = 0) :
+ formatFlags(formatFlagsIn), pixmapDepth(pixmapDepthIn) {}
+ unsigned formatFlags; // QWindowsGLFormatFlags.
+ unsigned pixmapDepth; // for QWindowsGLRenderToPixmap
+};
+
+// Per-window data for active OpenGL contexts.
+struct QOpenGLContextData
+{
+ QOpenGLContextData(HGLRC r, HWND h, HDC d) : renderingContext(r), hwnd(h), hdc(d) {}
+ QOpenGLContextData() : renderingContext(0), hwnd(0), hdc(0) {}
+
+ HGLRC renderingContext;
+ HWND hwnd;
+ HDC hdc;
+};
+
+class QOpenGLStaticContext
+{
+ Q_DISABLE_COPY(QOpenGLStaticContext)
+ QOpenGLStaticContext();
+public:
+ enum Extensions
+ {
+ SampleBuffers = 0x1
+ };
+
+ typedef bool
+ (APIENTRY *WglGetPixelFormatAttribIVARB)
+ (HDC hdc, int iPixelFormat, int iLayerPlane,
+ uint nAttributes, const int *piAttributes, int *piValues);
+
+ typedef bool
+ (APIENTRY *WglChoosePixelFormatARB)(HDC hdc, const int *piAttribList,
+ const float *pfAttribFList, uint nMaxFormats, int *piFormats,
+ UINT *nNumFormats);
+
+ typedef HGLRC
+ (APIENTRY *WglCreateContextAttribsARB)(HDC, HGLRC, const int *);
+
+ bool hasExtensions() const
+ { return wglGetPixelFormatAttribIVARB && wglChoosePixelFormatARB && wglCreateContextAttribsARB; }
+
+ static QOpenGLStaticContext *create();
+ static QByteArray getGlString(unsigned int which);
+
+ const QByteArray vendor;
+ const QByteArray renderer;
+ const QByteArray extensionNames;
+ int majorVersion;
+ int minorVersion;
+ unsigned extensions;
+
+ WglGetPixelFormatAttribIVARB wglGetPixelFormatAttribIVARB;
+ WglChoosePixelFormatARB wglChoosePixelFormatARB;
+ WglCreateContextAttribsARB wglCreateContextAttribsARB;
+};
+
+QDebug operator<<(QDebug d, const QOpenGLStaticContext &);
+
+class QWindowsGLContext : public QPlatformGLContext
+{
+public:
+ typedef QSharedPointer<QOpenGLStaticContext> QOpenGLStaticContextPtr;
+
+ explicit QWindowsGLContext(const QOpenGLStaticContextPtr &staticContext,
+ QGuiGLContext *context);
+ virtual ~QWindowsGLContext();
+ bool isValid() const { return m_renderingContext; }
+ virtual QSurfaceFormat format() const { return m_obtainedFormat; }
+
+ virtual void swapBuffers(QPlatformSurface *surface);
+
+ virtual bool makeCurrent(QPlatformSurface *surface);
+ virtual void doneCurrent();
+
+ typedef void (*GL_Proc) ();
+
+ virtual GL_Proc getProcAddress(const QByteArray &procName);
+
+ HGLRC renderingContext() const { return m_renderingContext; }
+
+private:
+ inline void releaseDCs();
+
+ const QOpenGLStaticContextPtr m_staticContext;
+ QGuiGLContext *m_context;
+ QSurfaceFormat m_obtainedFormat;
+ HGLRC m_renderingContext;
+ Array<QOpenGLContextData> m_windowContexts;
+ PIXELFORMATDESCRIPTOR m_obtainedPixelFormatDescriptor;
+ int m_pixelFormat;
+ bool m_extensionsUsed;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSGLCONTEXT_H
diff --git a/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp b/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp
new file mode 100644
index 0000000000..fcfdd4fbdd
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp
@@ -0,0 +1,209 @@
+/****************************************************************************
+**
+** 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 "qwindowsguieventdispatcher.h"
+#include "qwindowscontext.h"
+
+#include <QtGui/QWindowSystemInterface>
+
+#include <QtCore/QStack>
+#include <QtCore/QDebug>
+
+#include <windowsx.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QWindowsGuiEventDispatcher
+ \brief Event dispatcher for Windows
+
+ Maintains a global stack storing the current event dispatcher and
+ its processing flags for access from the Windows procedure
+ qWindowsWndProc. Handling the Lighthouse gui events should be done
+ from within the qWindowsWndProc to ensure correct processing of messages.
+
+ \ingroup qt-lighthouse-win
+*/
+
+typedef QStack<QWindowsGuiEventDispatcher::DispatchContext> DispatchContextStack;
+
+Q_GLOBAL_STATIC(DispatchContextStack, dispatchContextStack)
+
+QWindowsGuiEventDispatcher::QWindowsGuiEventDispatcher(QObject *parent) :
+ QEventDispatcherWin32(parent)
+{
+ setObjectName(QStringLiteral("QWindowsGuiEventDispatcher_0x") + QString::number((quintptr)this, 16));
+ if (QWindowsContext::verboseEvents)
+ qDebug("%s %s", __FUNCTION__, qPrintable(objectName()));
+ dispatchContextStack()->push(DispatchContext(this, QEventLoop::AllEvents));
+}
+
+QWindowsGuiEventDispatcher::~QWindowsGuiEventDispatcher()
+{
+ if (QWindowsContext::verboseEvents)
+ qDebug("%s %s", __FUNCTION__, qPrintable(objectName()));
+ if (!dispatchContextStack()->isEmpty())
+ dispatchContextStack()->pop();
+}
+
+bool QWindowsGuiEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
+{
+ DispatchContextStack &stack = *dispatchContextStack();
+ if (QWindowsContext::verboseEvents > 2)
+ qDebug(">%s %s %d", __FUNCTION__, qPrintable(objectName()), stack.size());
+ stack.push(DispatchContext(this, flags));
+ const bool rc = QEventDispatcherWin32::processEvents(flags);
+ stack.pop();
+ if (QWindowsContext::verboseEvents > 2)
+ qDebug("<%s %s returns %d", __FUNCTION__, qPrintable(objectName()), rc);
+ return rc;
+}
+
+QWindowsGuiEventDispatcher::DispatchContext QWindowsGuiEventDispatcher::currentDispatchContext()
+{
+ const DispatchContextStack &stack = *dispatchContextStack();
+ if (stack.isEmpty()) {
+ qWarning("%s: No dispatch context", __FUNCTION__);
+ return DispatchContext(0, 0);
+ }
+ return stack.top();
+}
+
+// Helpers for printing debug output for WM_* messages.
+struct MessageDebugEntry
+{
+ UINT message;
+ const char *description;
+ bool interesting;
+};
+
+static const MessageDebugEntry
+messageDebugEntries[] = {
+ {WM_CREATE, "WM_CREATE", true},
+ {WM_PAINT, "WM_PAINT", true},
+ {WM_CLOSE, "WM_CLOSE", true},
+ {WM_DESTROY, "WM_DESTROY", true},
+ {WM_MOVE, "WM_MOVE", true},
+ {WM_SIZE, "WM_SIZE", true},
+ {WM_MOUSEACTIVATE,"WM_MOUSEACTIVATE", true},
+ {WM_CHILDACTIVATE, "WM_CHILDACTIVATE", true},
+ {WM_PARENTNOTIFY, "WM_PARENTNOTIFY", true},
+ {WM_GETICON, "WM_GETICON", false},
+ {WM_KEYDOWN, "WM_KEYDOWN", true},
+ {WM_SYSKEYDOWN, "WM_SYSKEYDOWN", true},
+ {WM_SYSCOMMAND, "WM_SYSCOMMAND", true},
+ {WM_KEYUP, "WM_KEYUP", true},
+ {WM_SYSKEYUP, "WM_SYSKEYUP", true},
+ {WM_IME_CHAR, "WM_IMECHAR", true},
+ {WM_IME_KEYDOWN, "WM_IMECHAR", true},
+ {WM_CANCELMODE, "WM_CANCELMODE", true},
+ {WM_CHAR, "WM_CHAR", true},
+ {WM_DEADCHAR, "WM_DEADCHAR", true},
+ {WM_ACTIVATE, "WM_ACTIVATE", true},
+ {WM_GETMINMAXINFO, "WM_GETMINMAXINFO", true},
+ {WM_SETFOCUS, "WM_SETFOCUS", true},
+ {WM_KILLFOCUS, "WM_KILLFOCUS", true},
+ {WM_ENABLE, "WM_ENABLE", true},
+ {WM_SHOWWINDOW, "WM_SHOWWINDOW", true},
+ {WM_GETMINMAXINFO, "WM_GETMINMAXINFO"},
+ {WM_WINDOWPOSCHANGING, "WM_WINDOWPOSCHANGING", true},
+ {WM_WINDOWPOSCHANGED, "WM_WINDOWPOSCHANGED", true},
+ {WM_SETCURSOR, "WM_SETCURSOR", false},
+ {WM_GETFONT, "WM_GETFONT", true},
+ {WM_NCMOUSEMOVE, "WM_NCMOUSEMOVE", true},
+ {WM_LBUTTONDOWN, "WM_LBUTTONDOWN", true},
+ {WM_LBUTTONUP, "WM_LBUTTONUP", true},
+ {WM_LBUTTONDBLCLK, "WM_LBUTTONDBLCLK", true},
+ {WM_RBUTTONDOWN, "WM_RBUTTONDOWN", true},
+ {WM_RBUTTONUP, "WM_RBUTTONUP", true},
+ {WM_RBUTTONDBLCLK, "WM_RBUTTONDBLCLK", true},
+ {WM_MBUTTONDOWN, "WM_MBUTTONDOWN", true},
+ {WM_MBUTTONUP, "WM_MBUTTONUP", true},
+ {WM_MBUTTONDBLCLK, "WM_MBUTTONDBLCLK", true},
+ {WM_MOUSEWHEEL, "WM_MOUSEWHEEL", true},
+ {WM_XBUTTONDOWN, "WM_XBUTTONDOWN", true},
+ {WM_XBUTTONUP, "WM_XBUTTONUP", true},
+ {WM_XBUTTONDBLCLK, "WM_XBUTTONDBLCLK", true},
+ {WM_MOUSEHWHEEL, "WM_MOUSEHWHEEL", true},
+ {WM_NCCREATE, "WM_NCCREATE", true},
+ {WM_NCCALCSIZE, "WM_NCCALCSIZE", true},
+ {WM_NCACTIVATE, "WM_NCACTIVATE", true},
+ {WM_NCMOUSELEAVE, "WM_NCMOUSELEAVE", true},
+ {WM_NCLBUTTONDOWN, "WM_NCLBUTTONDOWN", true},
+ {WM_NCLBUTTONUP, "WM_NCLBUTTONUP", true},
+ {WM_ACTIVATEAPP, "WM_ACTIVATEAPP", true},
+ {WM_NCPAINT, "WM_NCPAINT", true},
+ {WM_ERASEBKGND, "WM_ERASEBKGND", true},
+ {WM_MOUSEMOVE, "WM_MOUSEMOVE", true},
+ {WM_MOUSELEAVE, "WM_MOUSELEAVE", true},
+ {WM_NCHITTEST, "WM_NCHITTEST", false},
+ {WM_IME_SETCONTEXT, "WM_IME_SETCONTEXT", true},
+ {WM_IME_NOTIFY, "WM_IME_NOTIFY", true},
+#if defined(WM_DWMNCRENDERINGCHANGED)
+ {WM_DWMNCRENDERINGCHANGED, "WM_DWMNCRENDERINGCHANGED", true},
+#endif
+ {WM_IME_SETCONTEXT, "WM_IME_SETCONTEXT", true},
+ {WM_IME_NOTIFY, "WM_IME_NOTIFY", true},
+ {WM_TOUCH, "WM_TOUCH", true},
+ {WM_CHANGECBCHAIN, "WM_CHANGECBCHAIN", true},
+ {WM_DRAWCLIPBOARD, "WM_DRAWCLIPBOARD", true},
+ {WM_RENDERFORMAT, "WM_RENDERFORMAT", true},
+ {WM_RENDERALLFORMATS, "WM_RENDERALLFORMATS", true},
+ {WM_DESTROYCLIPBOARD, "WM_DESTROYCLIPBOARD", true},
+ {WM_CAPTURECHANGED, "WM_CAPTURECHANGED", true}
+};
+
+static inline const MessageDebugEntry *messageDebugEntry(UINT msg)
+{
+ for (size_t i = 0; i < sizeof(messageDebugEntries)/sizeof(MessageDebugEntry); i++)
+ if (messageDebugEntries[i].message == msg)
+ return messageDebugEntries + i;
+ return 0;
+}
+
+const char *QWindowsGuiEventDispatcher::windowsMessageName(UINT msg)
+{
+ if (const MessageDebugEntry *e = messageDebugEntry(msg))
+ return e->description;
+ return "Unknown";
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsguieventdispatcher.h b/src/plugins/platforms/windows/qwindowsguieventdispatcher.h
new file mode 100644
index 0000000000..00fd234eff
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsguieventdispatcher.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSGUIEVENTDISPATCHER_H
+#define QWINDOWSGUIEVENTDISPATCHER_H
+
+#include "qtwindowsglobal.h"
+#include "qtwindows_additional.h"
+
+#include <QtCore/QPair>
+#include <QtCore/private/qeventdispatcher_win_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWindowsGuiEventDispatcher : public QEventDispatcherWin32
+{
+ Q_OBJECT
+public:
+ explicit QWindowsGuiEventDispatcher(QObject *parent = 0);
+ ~QWindowsGuiEventDispatcher();
+
+ typedef QPair<QAbstractEventDispatcher *, QEventLoop::ProcessEventsFlags> DispatchContext;
+
+ static DispatchContext currentDispatchContext();
+
+ static const char *windowsMessageName(UINT msg);
+
+ virtual bool QT_ENSURE_STACK_ALIGNED_FOR_SSE processEvents(QEventLoop::ProcessEventsFlags flags);
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSGUIEVENTDISPATCHER_H
diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp
new file mode 100644
index 0000000000..a0fada2ca5
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsintegration.cpp
@@ -0,0 +1,275 @@
+/****************************************************************************
+**
+** 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 "qwindowsintegration.h"
+#include "qwindowsbackingstore.h"
+#include "qwindowswindow.h"
+#include "qwindowscontext.h"
+#include "qwindowsglcontext.h"
+#include "qwindowsscreen.h"
+#include "qwindowsfontdatabase.h"
+#include "qwindowsprintersupport.h"
+#include "qwindowsguieventdispatcher.h"
+#include "qwindowsclipboard.h"
+#include "qwindowsdrag.h"
+
+#include <QtGui/QPlatformNativeInterface>
+#include <QtGui/QWindowSystemInterface>
+#include <QtGui/QBackingStore>
+#include <QtGui/private/qpixmap_raster_p.h>
+#include <QtGui/private/qguiapplication_p.h>
+
+#include <QtCore/private/qeventdispatcher_win_p.h>
+#include <QtCore/QDebug>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QWindowsNativeInterface
+ \brief Provides access to native handles.
+
+ Currently implemented keys
+ \list
+ \o handle (HWND)
+ \o getDC (DC)
+ \o releaseDC Releases the previously acquired DC and returns 0.
+ \endlist
+
+ \ingroup qt-lighthouse-win
+*/
+
+class QWindowsNativeInterface : public QPlatformNativeInterface
+{
+public:
+ virtual void *nativeResourceForWindow(const QByteArray &resource, QWindow *window);
+ virtual void *nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *bs);
+};
+
+void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resource, QWindow *window)
+{
+ if (!window || !window->handle()) {
+ qWarning("%s: '%s' requested for null window or window without handle.", __FUNCTION__, resource.constData());
+ return 0;
+ }
+ QWindowsWindow *bw = static_cast<QWindowsWindow *>(window->handle());
+ if (resource == "handle")
+ return bw->handle();
+ if (window->surfaceType() == QWindow::RasterSurface) {
+ if (resource == "getDC")
+ return bw->getDC();
+ if (resource == "releaseDC") {
+ bw->releaseDC();
+ return 0;
+ }
+ }
+ qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData());
+ return 0;
+}
+
+void *QWindowsNativeInterface::nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *bs)
+{
+ if (!bs || !bs->handle()) {
+ qWarning("%s: '%s' requested for null backingstore or backingstore without handle.", __FUNCTION__, resource.constData());
+ return 0;
+ }
+ QWindowsBackingStore *wbs = static_cast<QWindowsBackingStore *>(bs->handle());
+ if (resource == "getDC")
+ return wbs->getDC();
+ qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData());
+ return 0;
+}
+
+/*!
+ \class QWindowsIntegration
+ \brief QPlatformIntegration implementation for Windows.
+ \ingroup qt-lighthouse-win
+*/
+
+struct QWindowsIntegrationPrivate
+{
+ typedef QSharedPointer<QOpenGLStaticContext> QOpenGLStaticContextPtr;
+
+ explicit QWindowsIntegrationPrivate(bool openGL);
+
+ const bool m_openGL;
+ QWindowsContext m_context;
+ QWindowsPrinterSupport m_printerSupport;
+ QWindowsFontDatabase m_fontDatabase;
+ QWindowsNativeInterface m_nativeInterface;
+ QWindowsClipboard m_clipboard;
+ QWindowsDrag m_drag;
+ QWindowsGuiEventDispatcher *m_eventDispatcher;
+ QOpenGLStaticContextPtr m_staticOpenGLContext;
+};
+
+QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(bool openGL)
+ : m_openGL(openGL)
+ , m_context(openGL)
+ , m_eventDispatcher(new QWindowsGuiEventDispatcher)
+{
+}
+
+QWindowsIntegration::QWindowsIntegration(bool openGL) :
+ d(new QWindowsIntegrationPrivate(openGL))
+{
+ QGuiApplicationPrivate::instance()->setEventDispatcher(d->m_eventDispatcher);
+ d->m_clipboard.registerViewer();
+ foreach (QPlatformScreen *pscr, QWindowsScreen::screens())
+ screenAdded(pscr);
+}
+
+QWindowsIntegration::~QWindowsIntegration()
+{
+ if (QWindowsContext::verboseIntegration)
+ qDebug("%s", __FUNCTION__);
+}
+
+bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) const
+{
+ switch (cap) {
+ case ThreadedPixmaps:
+ return true;
+ default:
+ return QPlatformIntegration::hasCapability(cap);
+ }
+ return false;
+}
+
+QPlatformPixmap *QWindowsIntegration::createPlatformPixmap(QPlatformPixmap::PixelType type) const
+{
+ if (QWindowsContext::verboseIntegration)
+ qDebug() << __FUNCTION__ << type;
+ return new QRasterPlatformPixmap(type);
+}
+
+QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) const
+{
+ const bool isGL = window->surfaceType() == QWindow::OpenGLSurface;
+ QWindowsWindow::WindowData requested;
+ requested.flags = window->windowFlags();
+ requested.geometry = window->geometry();
+ const QWindowsWindow::WindowData obtained
+ = QWindowsWindow::WindowData::create(window, requested, window->windowTitle(), isGL);
+ if (QWindowsContext::verboseIntegration || QWindowsContext::verboseWindows)
+ qDebug().nospace()
+ << __FUNCTION__ << ' ' << window << '\n'
+ << " Requested: " << requested.geometry << " Flags="
+ << QWindowsWindow::debugWindowFlags(requested.flags) << '\n'
+ << " Obtained : " << obtained.geometry << " Margins "
+ << obtained.frame << " Flags="
+ << QWindowsWindow::debugWindowFlags(obtained.flags)
+ << " Handle=" << obtained.hwnd << '\n';
+ if (!obtained.hwnd)
+ return 0;
+ if (requested.flags != obtained.flags)
+ window->setWindowFlags(obtained.flags);
+ if (requested.geometry != obtained.geometry)
+ QWindowSystemInterface::handleGeometryChange(window, obtained.geometry);
+ return new QWindowsWindow(window, obtained);
+}
+
+QPlatformBackingStore *QWindowsIntegration::createPlatformBackingStore(QWindow *window) const
+{
+ if (QWindowsContext::verboseIntegration)
+ qDebug() << __FUNCTION__ << window;
+ return new QWindowsBackingStore(window);
+}
+
+QPlatformGLContext
+ *QWindowsIntegration::createPlatformGLContext(QGuiGLContext *context) const
+{
+ if (QWindowsContext::verboseIntegration)
+ qDebug() << __FUNCTION__ << context->format();
+ if (d->m_staticOpenGLContext.isNull())
+ d->m_staticOpenGLContext =
+ QSharedPointer<QOpenGLStaticContext>(QOpenGLStaticContext::create());
+ QScopedPointer<QWindowsGLContext> result(new QWindowsGLContext(d->m_staticOpenGLContext, context));
+ if (result->isValid())
+ return result.take();
+ return 0;
+}
+
+QPlatformFontDatabase *QWindowsIntegration::fontDatabase() const
+{
+ return &d->m_fontDatabase;
+}
+
+QPlatformPrinterSupport *QWindowsIntegration::printerSupport() const
+{
+ if (QWindowsContext::verboseIntegration)
+ qDebug() << __FUNCTION__;
+ return &d->m_printerSupport;
+}
+
+QPlatformNativeInterface *QWindowsIntegration::nativeInterface() const
+{
+ return &d->m_nativeInterface;
+}
+
+QPlatformClipboard * QWindowsIntegration::clipboard() const
+{
+ return &d->m_clipboard;
+}
+
+QPlatformDrag *QWindowsIntegration::drag() const
+{
+ if (QWindowsContext::verboseIntegration)
+ qDebug("%s", __FUNCTION__ );
+ return &d->m_drag;
+}
+
+QPlatformInputContext * QWindowsIntegration::inputContext() const
+{
+ Q_UNIMPLEMENTED();
+ return QPlatformIntegration::inputContext();
+}
+
+QWindowsIntegration *QWindowsIntegration::instance()
+{
+ return static_cast<QWindowsIntegration *>(QGuiApplicationPrivate::platformIntegration());
+}
+
+QAbstractEventDispatcher * QWindowsIntegration::guiThreadEventDispatcher() const
+{
+ return d->m_eventDispatcher;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h
new file mode 100644
index 0000000000..a2d3d3acf0
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsintegration.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSINTEGRATION_H
+#define QWINDOWSINTEGRATION_H
+
+#include <QtGui/QPlatformIntegration>
+#include <QtCore/QScopedPointer>
+
+QT_BEGIN_NAMESPACE
+
+struct QWindowsIntegrationPrivate;
+
+class QWindowsIntegration : public QPlatformIntegration
+{
+public:
+ QWindowsIntegration(bool openGL = false);
+ virtual ~QWindowsIntegration();
+
+ bool hasCapability(QPlatformIntegration::Capability cap) const;
+
+ virtual QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const;
+ QPlatformWindow *createPlatformWindow(QWindow *window) const;
+ QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const;
+ virtual QPlatformGLContext *createPlatformGLContext(QGuiGLContext *context) const;
+ virtual QAbstractEventDispatcher *guiThreadEventDispatcher() const;
+
+ virtual QPlatformClipboard *clipboard() const;
+ virtual QPlatformDrag *drag() const;
+ virtual QPlatformInputContext *inputContext() const;
+ virtual QPlatformNativeInterface *nativeInterface() const;
+ virtual QPlatformPrinterSupport *printerSupport() const;
+ virtual QPlatformFontDatabase *fontDatabase() const;
+
+ static QWindowsIntegration *instance();
+
+private:
+ QScopedPointer<QWindowsIntegrationPrivate> d;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/windows/qwindowsinternalmimedata.h b/src/plugins/platforms/windows/qwindowsinternalmimedata.h
new file mode 100644
index 0000000000..49fc69059b
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsinternalmimedata.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSINTERNALMIME_H
+#define QWINDOWSINTERNALMIME_H
+
+#include "qtwindows_additional.h"
+
+#include <QtGui/private/qdnd_p.h> // QInternalMime
+#include <QtCore/QVariant>
+
+QT_BEGIN_NAMESPACE
+
+class QDebug;
+
+// Implementation in qwindowsclipboard.cpp.
+class QWindowsInternalMimeData : public QInternalMimeData {
+public:
+ virtual bool hasFormat_sys(const QString &mimetype) const;
+ virtual QStringList formats_sys() const;
+ virtual QVariant retrieveData_sys(const QString &mimetype, QVariant::Type preferredType) const;
+
+protected:
+ virtual IDataObject *retrieveDataObject() const = 0;
+ virtual void releaseDataObject(IDataObject *) const {}
+};
+
+QDebug operator<<(QDebug d, const QMimeData &m);
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSINTERNALMIME_H
diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp
new file mode 100644
index 0000000000..3ec32b2325
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp
@@ -0,0 +1,1076 @@
+/****************************************************************************
+**
+** 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 "qwindowskeymapper.h"
+#include "qwindowscontext.h"
+#include "qwindowswindow.h"
+#include "qwindowsguieventdispatcher.h"
+
+#include <QtGui/QWindow>
+#include <QtGui/QWindowSystemInterface>
+#include <QtGui/QKeyEvent>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QWindowsKeyMapper
+ \brief Translates Windows keys to QWindowSystemInterface events.
+ \ingroup qt-lighthouse-win
+
+ In addition, handles some special keys to display system menus, etc.
+ The code originates from \c qkeymapper_win.cpp.
+*/
+
+QWindowsKeyMapper::QWindowsKeyMapper()
+ : m_useRTLExtensions(false), m_keyGrabber(0)
+{
+ memset(keyLayout, 0, sizeof(keyLayout));
+}
+
+QWindowsKeyMapper::~QWindowsKeyMapper()
+{
+ deleteLayouts();
+}
+
+#ifndef LANG_PASHTO
+#define LANG_PASHTO 0x63
+#endif
+#ifndef LANG_SYRIAC
+#define LANG_SYRIAC 0x5a
+#endif
+#ifndef LANG_DIVEHI
+#define LANG_DIVEHI 0x65
+#endif
+#ifndef VK_OEM_PLUS
+#define VK_OEM_PLUS 0xBB
+#endif
+#ifndef VK_OEM_3
+#define VK_OEM_3 0xC0
+#endif
+
+// Key recorder ------------------------------------------------------------------------[ start ] --
+struct KeyRecord {
+ KeyRecord(int c, int a, int s, const QString &t) : code(c), ascii(a), state(s), text(t) {}
+ KeyRecord() {}
+
+ int code;
+ int ascii;
+ int state;
+ QString text;
+};
+
+static const int QT_MAX_KEY_RECORDINGS = 64; // User has LOTS of fingers...
+struct KeyRecorder
+{
+ KeyRecorder() : nrecs(0) {}
+
+ inline KeyRecord *findKey(int code, bool remove);
+ inline void storeKey(int code, int ascii, int state, const QString& text);
+ inline void clearKeys();
+
+ int nrecs;
+ KeyRecord deleted_record; // A copy of last entry removed from records[]
+ KeyRecord records[QT_MAX_KEY_RECORDINGS];
+};
+static KeyRecorder key_recorder;
+
+KeyRecord *KeyRecorder::findKey(int code, bool remove)
+{
+ KeyRecord *result = 0;
+ for (int i = 0; i < nrecs; ++i) {
+ if (records[i].code == code) {
+ if (remove) {
+ deleted_record = records[i];
+ // Move rest down, and decrease count
+ while (i + 1 < nrecs) {
+ records[i] = records[i + 1];
+ ++i;
+ }
+ --nrecs;
+ result = &deleted_record;
+ } else {
+ result = &records[i];
+ }
+ break;
+ }
+ }
+ return result;
+}
+
+void KeyRecorder::storeKey(int code, int ascii, int state, const QString& text)
+{
+ Q_ASSERT_X(nrecs != QT_MAX_KEY_RECORDINGS,
+ "Internal KeyRecorder",
+ "Keyboard recorder buffer overflow, consider increasing QT_MAX_KEY_RECORDINGS");
+
+ if (nrecs == QT_MAX_KEY_RECORDINGS) {
+ qWarning("Qt: Internal keyboard buffer overflow");
+ return;
+ }
+ records[nrecs++] = KeyRecord(code,ascii,state,text);
+}
+
+void KeyRecorder::clearKeys()
+{
+ nrecs = 0;
+}
+// Key recorder --------------------------------------------------------------------------[ end ] --
+
+
+// Key translation ---------------------------------------------------------------------[ start ] --
+// Meaning of values:
+// 0 = Character output key, needs keyboard driver mapping
+// Key_unknown = Unknown Virtual Key, no translation possible, ignore
+static const uint KeyTbl[] = { // Keyboard mapping table
+ // Dec | Hex | Windows Virtual key
+ Qt::Key_unknown, // 0 0x00
+ Qt::Key_unknown, // 1 0x01 VK_LBUTTON | Left mouse button
+ Qt::Key_unknown, // 2 0x02 VK_RBUTTON | Right mouse button
+ Qt::Key_Cancel, // 3 0x03 VK_CANCEL | Control-Break processing
+ Qt::Key_unknown, // 4 0x04 VK_MBUTTON | Middle mouse button
+ Qt::Key_unknown, // 5 0x05 VK_XBUTTON1 | X1 mouse button
+ Qt::Key_unknown, // 6 0x06 VK_XBUTTON2 | X2 mouse button
+ Qt::Key_unknown, // 7 0x07 -- unassigned --
+ Qt::Key_Backspace, // 8 0x08 VK_BACK | BackSpace key
+ Qt::Key_Tab, // 9 0x09 VK_TAB | Tab key
+ Qt::Key_unknown, // 10 0x0A -- reserved --
+ Qt::Key_unknown, // 11 0x0B -- reserved --
+ Qt::Key_Clear, // 12 0x0C VK_CLEAR | Clear key
+ Qt::Key_Return, // 13 0x0D VK_RETURN | Enter key
+ Qt::Key_unknown, // 14 0x0E -- unassigned --
+ Qt::Key_unknown, // 15 0x0F -- unassigned --
+ Qt::Key_Shift, // 16 0x10 VK_SHIFT | Shift key
+ Qt::Key_Control, // 17 0x11 VK_CONTROL | Ctrl key
+ Qt::Key_Alt, // 18 0x12 VK_MENU | Alt key
+ Qt::Key_Pause, // 19 0x13 VK_PAUSE | Pause key
+ Qt::Key_CapsLock, // 20 0x14 VK_CAPITAL | Caps-Lock
+ Qt::Key_unknown, // 21 0x15 VK_KANA / VK_HANGUL | IME Kana or Hangul mode
+ Qt::Key_unknown, // 22 0x16 -- unassigned --
+ Qt::Key_unknown, // 23 0x17 VK_JUNJA | IME Junja mode
+ Qt::Key_unknown, // 24 0x18 VK_FINAL | IME final mode
+ Qt::Key_unknown, // 25 0x19 VK_HANJA / VK_KANJI | IME Hanja or Kanji mode
+ Qt::Key_unknown, // 26 0x1A -- unassigned --
+ Qt::Key_Escape, // 27 0x1B VK_ESCAPE | Esc key
+ Qt::Key_unknown, // 28 0x1C VK_CONVERT | IME convert
+ Qt::Key_unknown, // 29 0x1D VK_NONCONVERT | IME non-convert
+ Qt::Key_unknown, // 30 0x1E VK_ACCEPT | IME accept
+ Qt::Key_Mode_switch,// 31 0x1F VK_MODECHANGE | IME mode change request
+ Qt::Key_Space, // 32 0x20 VK_SPACE | Spacebar
+ Qt::Key_PageUp, // 33 0x21 VK_PRIOR | Page Up key
+ Qt::Key_PageDown, // 34 0x22 VK_NEXT | Page Down key
+ Qt::Key_End, // 35 0x23 VK_END | End key
+ Qt::Key_Home, // 36 0x24 VK_HOME | Home key
+ Qt::Key_Left, // 37 0x25 VK_LEFT | Left arrow key
+ Qt::Key_Up, // 38 0x26 VK_UP | Up arrow key
+ Qt::Key_Right, // 39 0x27 VK_RIGHT | Right arrow key
+ Qt::Key_Down, // 40 0x28 VK_DOWN | Down arrow key
+ Qt::Key_Select, // 41 0x29 VK_SELECT | Select key
+ Qt::Key_Printer, // 42 0x2A VK_PRINT | Print key
+ Qt::Key_Execute, // 43 0x2B VK_EXECUTE | Execute key
+ Qt::Key_Print, // 44 0x2C VK_SNAPSHOT | Print Screen key
+ Qt::Key_Insert, // 45 0x2D VK_INSERT | Ins key
+ Qt::Key_Delete, // 46 0x2E VK_DELETE | Del key
+ Qt::Key_Help, // 47 0x2F VK_HELP | Help key
+ 0, // 48 0x30 (VK_0) | 0 key
+ 0, // 49 0x31 (VK_1) | 1 key
+ 0, // 50 0x32 (VK_2) | 2 key
+ 0, // 51 0x33 (VK_3) | 3 key
+ 0, // 52 0x34 (VK_4) | 4 key
+ 0, // 53 0x35 (VK_5) | 5 key
+ 0, // 54 0x36 (VK_6) | 6 key
+ 0, // 55 0x37 (VK_7) | 7 key
+ 0, // 56 0x38 (VK_8) | 8 key
+ 0, // 57 0x39 (VK_9) | 9 key
+ Qt::Key_unknown, // 58 0x3A -- unassigned --
+ Qt::Key_unknown, // 59 0x3B -- unassigned --
+ Qt::Key_unknown, // 60 0x3C -- unassigned --
+ Qt::Key_unknown, // 61 0x3D -- unassigned --
+ Qt::Key_unknown, // 62 0x3E -- unassigned --
+ Qt::Key_unknown, // 63 0x3F -- unassigned --
+ Qt::Key_unknown, // 64 0x40 -- unassigned --
+ 0, // 65 0x41 (VK_A) | A key
+ 0, // 66 0x42 (VK_B) | B key
+ 0, // 67 0x43 (VK_C) | C key
+ 0, // 68 0x44 (VK_D) | D key
+ 0, // 69 0x45 (VK_E) | E key
+ 0, // 70 0x46 (VK_F) | F key
+ 0, // 71 0x47 (VK_G) | G key
+ 0, // 72 0x48 (VK_H) | H key
+ 0, // 73 0x49 (VK_I) | I key
+ 0, // 74 0x4A (VK_J) | J key
+ 0, // 75 0x4B (VK_K) | K key
+ 0, // 76 0x4C (VK_L) | L key
+ 0, // 77 0x4D (VK_M) | M key
+ 0, // 78 0x4E (VK_N) | N key
+ 0, // 79 0x4F (VK_O) | O key
+ 0, // 80 0x50 (VK_P) | P key
+ 0, // 81 0x51 (VK_Q) | Q key
+ 0, // 82 0x52 (VK_R) | R key
+ 0, // 83 0x53 (VK_S) | S key
+ 0, // 84 0x54 (VK_T) | T key
+ 0, // 85 0x55 (VK_U) | U key
+ 0, // 86 0x56 (VK_V) | V key
+ 0, // 87 0x57 (VK_W) | W key
+ 0, // 88 0x58 (VK_X) | X key
+ 0, // 89 0x59 (VK_Y) | Y key
+ 0, // 90 0x5A (VK_Z) | Z key
+ Qt::Key_Meta, // 91 0x5B VK_LWIN | Left Windows - MS Natural kbd
+ Qt::Key_Meta, // 92 0x5C VK_RWIN | Right Windows - MS Natural kbd
+ Qt::Key_Menu, // 93 0x5D VK_APPS | Application key-MS Natural kbd
+ Qt::Key_unknown, // 94 0x5E -- reserved --
+ Qt::Key_Sleep, // 95 0x5F VK_SLEEP
+ Qt::Key_0, // 96 0x60 VK_NUMPAD0 | Numeric keypad 0 key
+ Qt::Key_1, // 97 0x61 VK_NUMPAD1 | Numeric keypad 1 key
+ Qt::Key_2, // 98 0x62 VK_NUMPAD2 | Numeric keypad 2 key
+ Qt::Key_3, // 99 0x63 VK_NUMPAD3 | Numeric keypad 3 key
+ Qt::Key_4, // 100 0x64 VK_NUMPAD4 | Numeric keypad 4 key
+ Qt::Key_5, // 101 0x65 VK_NUMPAD5 | Numeric keypad 5 key
+ Qt::Key_6, // 102 0x66 VK_NUMPAD6 | Numeric keypad 6 key
+ Qt::Key_7, // 103 0x67 VK_NUMPAD7 | Numeric keypad 7 key
+ Qt::Key_8, // 104 0x68 VK_NUMPAD8 | Numeric keypad 8 key
+ Qt::Key_9, // 105 0x69 VK_NUMPAD9 | Numeric keypad 9 key
+ Qt::Key_Asterisk, // 106 0x6A VK_MULTIPLY | Multiply key
+ Qt::Key_Plus, // 107 0x6B VK_ADD | Add key
+ Qt::Key_Comma, // 108 0x6C VK_SEPARATOR | Separator key
+ Qt::Key_Minus, // 109 0x6D VK_SUBTRACT | Subtract key
+ Qt::Key_Period, // 110 0x6E VK_DECIMAL | Decimal key
+ Qt::Key_Slash, // 111 0x6F VK_DIVIDE | Divide key
+ Qt::Key_F1, // 112 0x70 VK_F1 | F1 key
+ Qt::Key_F2, // 113 0x71 VK_F2 | F2 key
+ Qt::Key_F3, // 114 0x72 VK_F3 | F3 key
+ Qt::Key_F4, // 115 0x73 VK_F4 | F4 key
+ Qt::Key_F5, // 116 0x74 VK_F5 | F5 key
+ Qt::Key_F6, // 117 0x75 VK_F6 | F6 key
+ Qt::Key_F7, // 118 0x76 VK_F7 | F7 key
+ Qt::Key_F8, // 119 0x77 VK_F8 | F8 key
+ Qt::Key_F9, // 120 0x78 VK_F9 | F9 key
+ Qt::Key_F10, // 121 0x79 VK_F10 | F10 key
+ Qt::Key_F11, // 122 0x7A VK_F11 | F11 key
+ Qt::Key_F12, // 123 0x7B VK_F12 | F12 key
+ Qt::Key_F13, // 124 0x7C VK_F13 | F13 key
+ Qt::Key_F14, // 125 0x7D VK_F14 | F14 key
+ Qt::Key_F15, // 126 0x7E VK_F15 | F15 key
+ Qt::Key_F16, // 127 0x7F VK_F16 | F16 key
+ Qt::Key_F17, // 128 0x80 VK_F17 | F17 key
+ Qt::Key_F18, // 129 0x81 VK_F18 | F18 key
+ Qt::Key_F19, // 130 0x82 VK_F19 | F19 key
+ Qt::Key_F20, // 131 0x83 VK_F20 | F20 key
+ Qt::Key_F21, // 132 0x84 VK_F21 | F21 key
+ Qt::Key_F22, // 133 0x85 VK_F22 | F22 key
+ Qt::Key_F23, // 134 0x86 VK_F23 | F23 key
+ Qt::Key_F24, // 135 0x87 VK_F24 | F24 key
+ Qt::Key_unknown, // 136 0x88 -- unassigned --
+ Qt::Key_unknown, // 137 0x89 -- unassigned --
+ Qt::Key_unknown, // 138 0x8A -- unassigned --
+ Qt::Key_unknown, // 139 0x8B -- unassigned --
+ Qt::Key_unknown, // 140 0x8C -- unassigned --
+ Qt::Key_unknown, // 141 0x8D -- unassigned --
+ Qt::Key_unknown, // 142 0x8E -- unassigned --
+ Qt::Key_unknown, // 143 0x8F -- unassigned --
+ Qt::Key_NumLock, // 144 0x90 VK_NUMLOCK | Num Lock key
+ Qt::Key_ScrollLock, // 145 0x91 VK_SCROLL | Scroll Lock key
+ // Fujitsu/OASYS kbd --------------------
+ 0, //Qt::Key_Jisho, // 146 0x92 VK_OEM_FJ_JISHO | 'Dictionary' key /
+ // VK_OEM_NEC_EQUAL = key on numpad on NEC PC-9800 kbd
+ Qt::Key_Massyo, // 147 0x93 VK_OEM_FJ_MASSHOU | 'Unregister word' key
+ Qt::Key_Touroku, // 148 0x94 VK_OEM_FJ_TOUROKU | 'Register word' key
+ 0, //Qt::Key_Oyayubi_Left,//149 0x95 VK_OEM_FJ_LOYA | 'Left OYAYUBI' key
+ 0, //Qt::Key_Oyayubi_Right,//150 0x96 VK_OEM_FJ_ROYA | 'Right OYAYUBI' key
+ Qt::Key_unknown, // 151 0x97 -- unassigned --
+ Qt::Key_unknown, // 152 0x98 -- unassigned --
+ Qt::Key_unknown, // 153 0x99 -- unassigned --
+ Qt::Key_unknown, // 154 0x9A -- unassigned --
+ Qt::Key_unknown, // 155 0x9B -- unassigned --
+ Qt::Key_unknown, // 156 0x9C -- unassigned --
+ Qt::Key_unknown, // 157 0x9D -- unassigned --
+ Qt::Key_unknown, // 158 0x9E -- unassigned --
+ Qt::Key_unknown, // 159 0x9F -- unassigned --
+ Qt::Key_Shift, // 160 0xA0 VK_LSHIFT | Left Shift key
+ Qt::Key_Shift, // 161 0xA1 VK_RSHIFT | Right Shift key
+ Qt::Key_Control, // 162 0xA2 VK_LCONTROL | Left Ctrl key
+ Qt::Key_Control, // 163 0xA3 VK_RCONTROL | Right Ctrl key
+ Qt::Key_Alt, // 164 0xA4 VK_LMENU | Left Menu key
+ Qt::Key_Alt, // 165 0xA5 VK_RMENU | Right Menu key
+ Qt::Key_Back, // 166 0xA6 VK_BROWSER_BACK | Browser Back key
+ Qt::Key_Forward, // 167 0xA7 VK_BROWSER_FORWARD | Browser Forward key
+ Qt::Key_Refresh, // 168 0xA8 VK_BROWSER_REFRESH | Browser Refresh key
+ Qt::Key_Stop, // 169 0xA9 VK_BROWSER_STOP | Browser Stop key
+ Qt::Key_Search, // 170 0xAA VK_BROWSER_SEARCH | Browser Search key
+ Qt::Key_Favorites, // 171 0xAB VK_BROWSER_FAVORITES| Browser Favorites key
+ Qt::Key_HomePage, // 172 0xAC VK_BROWSER_HOME | Browser Start and Home key
+ Qt::Key_VolumeMute, // 173 0xAD VK_VOLUME_MUTE | Volume Mute key
+ Qt::Key_VolumeDown, // 174 0xAE VK_VOLUME_DOWN | Volume Down key
+ Qt::Key_VolumeUp, // 175 0xAF VK_VOLUME_UP | Volume Up key
+ Qt::Key_MediaNext, // 176 0xB0 VK_MEDIA_NEXT_TRACK | Next Track key
+ Qt::Key_MediaPrevious, //177 0xB1 VK_MEDIA_PREV_TRACK | Previous Track key
+ Qt::Key_MediaStop, // 178 0xB2 VK_MEDIA_STOP | Stop Media key
+ Qt::Key_MediaPlay, // 179 0xB3 VK_MEDIA_PLAY_PAUSE | Play/Pause Media key
+ Qt::Key_LaunchMail, // 180 0xB4 VK_LAUNCH_MAIL | Start Mail key
+ Qt::Key_LaunchMedia,// 181 0xB5 VK_LAUNCH_MEDIA_SELECT Select Media key
+ Qt::Key_Launch0, // 182 0xB6 VK_LAUNCH_APP1 | Start Application 1 key
+ Qt::Key_Launch1, // 183 0xB7 VK_LAUNCH_APP2 | Start Application 2 key
+ Qt::Key_unknown, // 184 0xB8 -- reserved --
+ Qt::Key_unknown, // 185 0xB9 -- reserved --
+ 0, // 186 0xBA VK_OEM_1 | ';:' for US
+ 0, // 187 0xBB VK_OEM_PLUS | '+' any country
+ 0, // 188 0xBC VK_OEM_COMMA | ',' any country
+ 0, // 189 0xBD VK_OEM_MINUS | '-' any country
+ 0, // 190 0xBE VK_OEM_PERIOD | '.' any country
+ 0, // 191 0xBF VK_OEM_2 | '/?' for US
+ 0, // 192 0xC0 VK_OEM_3 | '`~' for US
+ Qt::Key_unknown, // 193 0xC1 -- reserved --
+ Qt::Key_unknown, // 194 0xC2 -- reserved --
+ Qt::Key_unknown, // 195 0xC3 -- reserved --
+ Qt::Key_unknown, // 196 0xC4 -- reserved --
+ Qt::Key_unknown, // 197 0xC5 -- reserved --
+ Qt::Key_unknown, // 198 0xC6 -- reserved --
+ Qt::Key_unknown, // 199 0xC7 -- reserved --
+ Qt::Key_unknown, // 200 0xC8 -- reserved --
+ Qt::Key_unknown, // 201 0xC9 -- reserved --
+ Qt::Key_unknown, // 202 0xCA -- reserved --
+ Qt::Key_unknown, // 203 0xCB -- reserved --
+ Qt::Key_unknown, // 204 0xCC -- reserved --
+ Qt::Key_unknown, // 205 0xCD -- reserved --
+ Qt::Key_unknown, // 206 0xCE -- reserved --
+ Qt::Key_unknown, // 207 0xCF -- reserved --
+ Qt::Key_unknown, // 208 0xD0 -- reserved --
+ Qt::Key_unknown, // 209 0xD1 -- reserved --
+ Qt::Key_unknown, // 210 0xD2 -- reserved --
+ Qt::Key_unknown, // 211 0xD3 -- reserved --
+ Qt::Key_unknown, // 212 0xD4 -- reserved --
+ Qt::Key_unknown, // 213 0xD5 -- reserved --
+ Qt::Key_unknown, // 214 0xD6 -- reserved --
+ Qt::Key_unknown, // 215 0xD7 -- reserved --
+ Qt::Key_unknown, // 216 0xD8 -- unassigned --
+ Qt::Key_unknown, // 217 0xD9 -- unassigned --
+ Qt::Key_unknown, // 218 0xDA -- unassigned --
+ 0, // 219 0xDB VK_OEM_4 | '[{' for US
+ 0, // 220 0xDC VK_OEM_5 | '\|' for US
+ 0, // 221 0xDD VK_OEM_6 | ']}' for US
+ 0, // 222 0xDE VK_OEM_7 | ''"' for US
+ 0, // 223 0xDF VK_OEM_8
+ Qt::Key_unknown, // 224 0xE0 -- reserved --
+ Qt::Key_unknown, // 225 0xE1 VK_OEM_AX | 'AX' key on Japanese AX kbd
+ Qt::Key_unknown, // 226 0xE2 VK_OEM_102 | "<>" or "\|" on RT 102-key kbd
+ Qt::Key_unknown, // 227 0xE3 VK_ICO_HELP | Help key on ICO
+ Qt::Key_unknown, // 228 0xE4 VK_ICO_00 | 00 key on ICO
+ Qt::Key_unknown, // 229 0xE5 VK_PROCESSKEY | IME Process key
+ Qt::Key_unknown, // 230 0xE6 VK_ICO_CLEAR |
+ Qt::Key_unknown, // 231 0xE7 VK_PACKET | Unicode char as keystrokes
+ Qt::Key_unknown, // 232 0xE8 -- unassigned --
+ // Nokia/Ericsson definitions ---------------
+ Qt::Key_unknown, // 233 0xE9 VK_OEM_RESET
+ Qt::Key_unknown, // 234 0xEA VK_OEM_JUMP
+ Qt::Key_unknown, // 235 0xEB VK_OEM_PA1
+ Qt::Key_unknown, // 236 0xEC VK_OEM_PA2
+ Qt::Key_unknown, // 237 0xED VK_OEM_PA3
+ Qt::Key_unknown, // 238 0xEE VK_OEM_WSCTRL
+ Qt::Key_unknown, // 239 0xEF VK_OEM_CUSEL
+ Qt::Key_unknown, // 240 0xF0 VK_OEM_ATTN
+ Qt::Key_unknown, // 241 0xF1 VK_OEM_FINISH
+ Qt::Key_unknown, // 242 0xF2 VK_OEM_COPY
+ Qt::Key_unknown, // 243 0xF3 VK_OEM_AUTO
+ Qt::Key_unknown, // 244 0xF4 VK_OEM_ENLW
+ Qt::Key_unknown, // 245 0xF5 VK_OEM_BACKTAB
+ Qt::Key_unknown, // 246 0xF6 VK_ATTN | Attn key
+ Qt::Key_unknown, // 247 0xF7 VK_CRSEL | CrSel key
+ Qt::Key_unknown, // 248 0xF8 VK_EXSEL | ExSel key
+ Qt::Key_unknown, // 249 0xF9 VK_EREOF | Erase EOF key
+ Qt::Key_Play, // 250 0xFA VK_PLAY | Play key
+ Qt::Key_Zoom, // 251 0xFB VK_ZOOM | Zoom key
+ Qt::Key_unknown, // 252 0xFC VK_NONAME | Reserved
+ Qt::Key_unknown, // 253 0xFD VK_PA1 | PA1 key
+ Qt::Key_Clear, // 254 0xFE VK_OEM_CLEAR | Clear key
+ 0
+};
+
+// Possible modifier states.
+// NOTE: The order of these states match the order in QWindowsKeyMapper::updatePossibleKeyCodes()!
+static const Qt::KeyboardModifiers ModsTbl[] = {
+ Qt::NoModifier, // 0
+ Qt::ShiftModifier, // 1
+ Qt::ControlModifier, // 2
+ Qt::ControlModifier | Qt::ShiftModifier, // 3
+ Qt::AltModifier, // 4
+ Qt::AltModifier | Qt::ShiftModifier, // 5
+ Qt::AltModifier | Qt::ControlModifier, // 6
+ Qt::AltModifier | Qt::ShiftModifier | Qt::ControlModifier, // 7
+ Qt::NoModifier, // Fall-back to raw Key_*
+};
+
+/**
+ Remap return or action key to select key for windows mobile.
+*/
+inline int winceKeyBend(int keyCode)
+{
+ return KeyTbl[keyCode];
+}
+
+// Translate a VK into a Qt key code, or unicode character
+static inline int toKeyOrUnicode(int vk, int scancode, unsigned char *kbdBuffer, bool *isDeadkey = 0)
+{
+ Q_ASSERT(vk > 0 && vk < 256);
+ int code = 0;
+ QChar unicodeBuffer[5];
+ int res = ToUnicode(vk, scancode, kbdBuffer, reinterpret_cast<LPWSTR>(unicodeBuffer), 5, 0);
+ if (res)
+ code = unicodeBuffer[0].toUpper().unicode();
+
+ // Qt::Key_*'s are not encoded below 0x20, so try again, and DEL keys (0x7f) is encoded with a
+ // proper Qt::Key_ code
+ if (code < 0x20 || code == 0x7f) // Handles res==0 too
+ code = winceKeyBend(vk);
+
+ if (isDeadkey)
+ *isDeadkey = (res == -1);
+
+ return code == Qt::Key_unknown ? 0 : code;
+}
+
+int qt_translateKeyCode(int vk)
+{
+ int code = winceKeyBend((vk < 0 || vk > 255) ? 0 : vk);
+ return code == Qt::Key_unknown ? 0 : code;
+}
+
+static inline int asciiToKeycode(char a, int state)
+{
+ if (a >= 'a' && a <= 'z')
+ a = toupper(a);
+ if ((state & Qt::ControlModifier) != 0) {
+ if (a >= 0 && a <= 31) // Ctrl+@..Ctrl+A..CTRL+Z..Ctrl+_
+ a += '@'; // to @..A..Z.._
+ }
+ return a & 0xff;
+}
+
+static inline bool isModifierKey(int code)
+{
+ return (code >= Qt::Key_Shift) && (code <= Qt::Key_ScrollLock);
+}
+// Key translation -----------------------------------------------------------------------[ end ]---
+
+
+// Keyboard map private ----------------------------------------------------------------[ start ]---
+
+/*
+ \internal
+ A Windows KeyboardLayoutItem has 8 possible states:
+ 1. Unmodified
+ 2. Shift
+ 3. Control
+ 4. Control + Shift
+ 5. Alt
+ 6. Alt + Shift
+ 7. Alt + Control
+ 8. Alt + Control + Shift
+*/
+struct KeyboardLayoutItem {
+ bool dirty;
+ quint8 deadkeys;
+ quint32 qtKey[9]; // Can by any Qt::Key_<foo>, or unicode character
+};
+
+void QWindowsKeyMapper::deleteLayouts()
+{
+ for (int i = 0; i < 255; ++i) {
+ if (keyLayout[i]) {
+ delete keyLayout[i];
+ keyLayout[i] = 0;
+ }
+ }
+}
+
+void QWindowsKeyMapper::changeKeyboard()
+{
+ deleteLayouts();
+
+ /* MAKELCID()'s first argument is a WORD, and GetKeyboardLayout()
+ * returns a DWORD. */
+
+ LCID newLCID = MAKELCID((quintptr)GetKeyboardLayout(0), SORT_DEFAULT);
+// keyboardInputLocale = qt_localeFromLCID(newLCID);
+
+ bool bidi = false;
+ wchar_t LCIDFontSig[16];
+ if (GetLocaleInfo(newLCID, LOCALE_FONTSIGNATURE, LCIDFontSig, sizeof(LCIDFontSig) / sizeof(wchar_t))
+ && (LCIDFontSig[7] & (wchar_t)0x0800))
+ bidi = true;
+
+ keyboardInputDirection = bidi ? Qt::RightToLeft : Qt::LeftToRight;
+}
+
+void QWindowsKeyMapper::clearRecordedKeys()
+{
+ key_recorder.clearKeys();
+}
+
+
+inline void setKbdState(unsigned char *kbd, bool shift, bool ctrl, bool alt)
+{
+ kbd[VK_LSHIFT ] = (shift ? 0x80 : 0);
+ kbd[VK_SHIFT ] = (shift ? 0x80 : 0);
+ kbd[VK_LCONTROL] = (ctrl ? 0x80 : 0);
+ kbd[VK_CONTROL ] = (ctrl ? 0x80 : 0);
+ kbd[VK_RMENU ] = (alt ? 0x80 : 0);
+ kbd[VK_MENU ] = (alt ? 0x80 : 0);
+}
+
+void QWindowsKeyMapper::updateKeyMap(const MSG &msg)
+{
+ unsigned char kbdBuffer[256]; // Will hold the complete keyboard state
+ GetKeyboardState(kbdBuffer);
+ quint32 scancode = (msg.lParam >> 16) & 0xfff;
+ updatePossibleKeyCodes(kbdBuffer, scancode, msg.wParam);
+}
+
+void QWindowsKeyMapper::updatePossibleKeyCodes(unsigned char *kbdBuffer, quint32 scancode,
+ quint32 vk_key)
+{
+ if (!vk_key || (keyLayout[vk_key] && !keyLayout[vk_key]->dirty))
+ return;
+
+ if (!keyLayout[vk_key])
+ keyLayout[vk_key] = new KeyboardLayoutItem;
+
+ // Copy keyboard state, so we can modify and query output for each possible permutation
+ unsigned char buffer[256];
+ memcpy(buffer, kbdBuffer, sizeof(buffer));
+ // Always 0, as Windows doesn't treat these as modifiers;
+ buffer[VK_LWIN ] = 0;
+ buffer[VK_RWIN ] = 0;
+ buffer[VK_CAPITAL ] = 0;
+ buffer[VK_NUMLOCK ] = 0;
+ buffer[VK_SCROLL ] = 0;
+ // Always 0, since we'll only change the other versions
+ buffer[VK_RSHIFT ] = 0;
+ buffer[VK_RCONTROL] = 0;
+ buffer[VK_LMENU ] = 0; // Use right Alt, since left Ctrl + right Alt is considered AltGraph
+
+ bool isDeadKey = false;
+ keyLayout[vk_key]->deadkeys = 0;
+ keyLayout[vk_key]->dirty = false;
+ setKbdState(buffer, false, false, false);
+ keyLayout[vk_key]->qtKey[0] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey);
+ keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x01 : 0;
+ setKbdState(buffer, true, false, false);
+ keyLayout[vk_key]->qtKey[1] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey);
+ keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x02 : 0;
+ setKbdState(buffer, false, true, false);
+ keyLayout[vk_key]->qtKey[2] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey);
+ keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x04 : 0;
+ setKbdState(buffer, true, true, false);
+ keyLayout[vk_key]->qtKey[3] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey);
+ keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x08 : 0;
+ setKbdState(buffer, false, false, true);
+ keyLayout[vk_key]->qtKey[4] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey);
+ keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x10 : 0;
+ setKbdState(buffer, true, false, true);
+ keyLayout[vk_key]->qtKey[5] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey);
+ keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x20 : 0;
+ setKbdState(buffer, false, true, true);
+ keyLayout[vk_key]->qtKey[6] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey);
+ keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x40 : 0;
+ setKbdState(buffer, true, true, true);
+ keyLayout[vk_key]->qtKey[7] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey);
+ keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x80 : 0;
+ // Add a fall back key for layouts which don't do composition and show non-latin1 characters
+ int fallbackKey = winceKeyBend(vk_key);
+ if (!fallbackKey || fallbackKey == Qt::Key_unknown) {
+ fallbackKey = 0;
+ if (vk_key != keyLayout[vk_key]->qtKey[0] && vk_key < 0x5B && vk_key > 0x2F)
+ fallbackKey = vk_key;
+ }
+ keyLayout[vk_key]->qtKey[8] = fallbackKey;
+
+ // If this vk_key a Dead Key
+ if (MapVirtualKey(vk_key, 2) & 0x80000000) {
+ // Push a Space, then the original key through the low-level ToAscii functions.
+ // We do this because these functions (ToAscii / ToUnicode) will alter the internal state of
+ // the keyboard driver By doing the following, we set the keyboard driver state back to what
+ // it was before we wrecked it with the code above.
+ // We need to push the space with an empty keystate map, since the driver checks the map for
+ // transitions in modifiers, so this helps us capture all possible deadkeys.
+ unsigned char emptyBuffer[256];
+ memset(emptyBuffer, 0, sizeof(emptyBuffer));
+ ::ToAscii(VK_SPACE, 0, emptyBuffer, reinterpret_cast<LPWORD>(&buffer), 0);
+ ::ToAscii(vk_key, scancode, kbdBuffer, reinterpret_cast<LPWORD>(&buffer), 0);
+ }
+
+ if (QWindowsContext::verboseEvents > 1) {
+ qDebug("updatePossibleKeyCodes for virtual key = 0x%02x!", vk_key);
+ for (int i = 0; i < 9; ++i) {
+ qDebug(" [%d] (%d,0x%02x,'%c') %s", i,
+ keyLayout[vk_key]->qtKey[i],
+ keyLayout[vk_key]->qtKey[i],
+ keyLayout[vk_key]->qtKey[i] ? keyLayout[vk_key]->qtKey[i] : 0x03,
+ keyLayout[vk_key]->deadkeys & (1<<i) ? "deadkey" : "");
+ }
+ }
+}
+
+bool QWindowsKeyMapper::isADeadKey(unsigned int vk_key, unsigned int modifiers)
+{
+ if (keyLayout && (vk_key < 256) && keyLayout[vk_key]) {
+ for (register int i = 0; i < 9; ++i) {
+ if (uint(ModsTbl[i]) == modifiers)
+ return bool(keyLayout[vk_key]->deadkeys & 1<<i);
+ }
+ }
+ return false;
+}
+
+static inline QString messageKeyText(const MSG &msg)
+{
+ const QChar ch = QChar((ushort)msg.wParam);
+ return ch.isNull() ? QString() : QString(ch);
+}
+
+static void showSystemMenu(QWindow* w)
+{
+ QWindow *topLevel = QWindowsWindow::topLevelOf(w);
+ HWND topLevelHwnd = QWindowsWindow::handleOf(topLevel);
+ HMENU menu = GetSystemMenu(topLevelHwnd, FALSE);
+ if (!menu)
+ return; // no menu for this window
+
+#define enabled (MF_BYCOMMAND | MF_ENABLED)
+#define disabled (MF_BYCOMMAND | MF_GRAYED)
+
+ EnableMenuItem(menu, SC_MINIMIZE, (topLevel->windowFlags() & Qt::WindowMinimizeButtonHint)?enabled:disabled);
+ bool maximized = IsZoomed(topLevelHwnd);
+
+ EnableMenuItem(menu, SC_MAXIMIZE, ! (topLevel->windowFlags() & Qt::WindowMaximizeButtonHint) || maximized?disabled:enabled);
+ EnableMenuItem(menu, SC_RESTORE, maximized?enabled:disabled);
+
+ // We should _not_ check with the setFixedSize(x,y) case here, since Windows is not able to check
+ // this and our menu here would be out-of-sync with the menu produced by mouse-click on the
+ // System Menu, or right-click on the title bar.
+ EnableMenuItem(menu, SC_SIZE, (topLevel->windowFlags() & Qt::MSWindowsFixedSizeDialogHint) || maximized?disabled:enabled);
+ EnableMenuItem(menu, SC_MOVE, maximized?disabled:enabled);
+ EnableMenuItem(menu, SC_CLOSE, enabled);
+ // Set bold on close menu item
+ MENUITEMINFO closeItem;
+ closeItem.cbSize = sizeof(MENUITEMINFO);
+ closeItem.fMask = MIIM_STATE;
+ closeItem.fState = MFS_DEFAULT;
+ SetMenuItemInfo(menu, SC_CLOSE, FALSE, &closeItem);
+
+#undef enabled
+#undef disabled
+ const int ret = TrackPopupMenuEx(menu,
+ TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD,
+ topLevel->geometry().x(), topLevel->geometry().y(),
+ topLevelHwnd,
+ 0);
+ if (ret)
+ qWindowsWndProc(topLevelHwnd, WM_SYSCOMMAND, ret, 0);
+}
+
+static inline void sendExtendedPressRelease(QWindow *w, int k,
+ Qt::KeyboardModifiers mods,
+ quint32 nativeScanCode,
+ quint32 nativeVirtualKey,
+ quint32 nativeModifiers,
+ const QString & text = QString(),
+ bool autorep = false,
+ ushort count = 1)
+{
+ QWindowSystemInterface::handleExtendedKeyEvent(w, QEvent::KeyPress, k, mods, nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count);
+ QWindowSystemInterface::handleExtendedKeyEvent(w, QEvent::KeyRelease, k, mods, nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count);
+}
+
+/*!
+ \brief To be called from the window procedure.
+*/
+
+bool QWindowsKeyMapper::translateKeyEvent(QWindow *widget, HWND hwnd,
+ const MSG &msg, LRESULT *result)
+{
+ *result = 0;
+ MSG peekedMsg;
+ // consume dead chars?(for example, typing '`','a' resulting in a-accent).
+ if (PeekMessage(&peekedMsg, hwnd, 0, 0, PM_NOREMOVE) && peekedMsg.message == WM_DEADCHAR)
+ return true;
+ if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN)
+ updateKeyMap(msg);
+ translateKeyEventInternal(widget, msg, false);
+ return true;
+}
+
+bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &msg, bool /* grab */)
+{
+ const int msgType = msg.message;
+
+ const quint32 scancode = (msg.lParam >> 16) & 0xfff;
+ const quint32 vk_key = MapVirtualKey(scancode, 1);
+ const bool isNumpad = (msg.wParam >= VK_NUMPAD0 && msg.wParam <= VK_NUMPAD9);
+ quint32 nModifiers = 0;
+
+ QWindow *receiver = m_keyGrabber ? m_keyGrabber : window;
+
+ // Map native modifiers to some bit representation
+ nModifiers |= (GetKeyState(VK_LSHIFT ) & 0x80 ? ShiftLeft : 0);
+ nModifiers |= (GetKeyState(VK_RSHIFT ) & 0x80 ? ShiftRight : 0);
+ nModifiers |= (GetKeyState(VK_LCONTROL) & 0x80 ? ControlLeft : 0);
+ nModifiers |= (GetKeyState(VK_RCONTROL) & 0x80 ? ControlRight : 0);
+ nModifiers |= (GetKeyState(VK_LMENU ) & 0x80 ? AltLeft : 0);
+ nModifiers |= (GetKeyState(VK_RMENU ) & 0x80 ? AltRight : 0);
+ nModifiers |= (GetKeyState(VK_LWIN ) & 0x80 ? MetaLeft : 0);
+ nModifiers |= (GetKeyState(VK_RWIN ) & 0x80 ? MetaRight : 0);
+ // Add Lock keys to the same bits
+ nModifiers |= (GetKeyState(VK_CAPITAL ) & 0x01 ? CapsLock : 0);
+ nModifiers |= (GetKeyState(VK_NUMLOCK ) & 0x01 ? NumLock : 0);
+ nModifiers |= (GetKeyState(VK_SCROLL ) & 0x01 ? ScrollLock : 0);
+
+ if (msg.lParam & ExtendedKey)
+ nModifiers |= msg.lParam & ExtendedKey;
+
+ // Get the modifier states (may be altered later, depending on key code)
+ int state = 0;
+ state |= (nModifiers & ShiftAny ? Qt::ShiftModifier : 0);
+ state |= (nModifiers & ControlAny ? Qt::ControlModifier : 0);
+ state |= (nModifiers & AltAny ? Qt::AltModifier : 0);
+ state |= (nModifiers & MetaAny ? Qt::MetaModifier : 0);
+
+ // Now we know enough to either have MapVirtualKey or our own keymap tell us if it's a deadkey
+ const bool isDeadKey = isADeadKey(msg.wParam, state)
+ || MapVirtualKey(msg.wParam, 2) & 0x80000000;
+
+ // A multi-character key or a Input method character
+ // not found by our look-ahead
+ if (msgType == WM_CHAR || msgType == WM_IME_CHAR) {
+ sendExtendedPressRelease(receiver, 0, Qt::KeyboardModifier(state), scancode, vk_key, nModifiers, messageKeyText(msg), false, 0);
+ return true;
+ }
+
+ bool result = false;
+ // handle Directionality changes (BiDi) with RTL extensions
+ if (m_useRTLExtensions) {
+ static int dirStatus = 0;
+ if (!dirStatus && state == Qt::ControlModifier
+ && msg.wParam == VK_CONTROL
+ && msgType == WM_KEYDOWN) {
+ if (GetKeyState(VK_LCONTROL) < 0)
+ dirStatus = VK_LCONTROL;
+ else if (GetKeyState(VK_RCONTROL) < 0)
+ dirStatus = VK_RCONTROL;
+ } else if (dirStatus) {
+ if (msgType == WM_KEYDOWN) {
+ if (msg.wParam == VK_SHIFT) {
+ if (dirStatus == VK_LCONTROL && GetKeyState(VK_LSHIFT) < 0)
+ dirStatus = VK_LSHIFT;
+ else if (dirStatus == VK_RCONTROL && GetKeyState(VK_RSHIFT) < 0)
+ dirStatus = VK_RSHIFT;
+ } else {
+ dirStatus = 0;
+ }
+ } else if (msgType == WM_KEYUP) {
+ if (dirStatus == VK_LSHIFT
+ && ((msg.wParam == VK_SHIFT && GetKeyState(VK_LCONTROL))
+ || (msg.wParam == VK_CONTROL && GetKeyState(VK_LSHIFT)))) {
+ sendExtendedPressRelease(receiver, Qt::Key_Direction_L, 0, scancode, msg.wParam, nModifiers, QString(), false, 0);
+ result = true;
+ dirStatus = 0;
+ } else if (dirStatus == VK_RSHIFT
+ && ( (msg.wParam == VK_SHIFT && GetKeyState(VK_RCONTROL))
+ || (msg.wParam == VK_CONTROL && GetKeyState(VK_RSHIFT)))) {
+ sendExtendedPressRelease(receiver, Qt::Key_Direction_R, 0, scancode, msg.wParam, nModifiers, QString(), false, 0);
+ result = true;
+ dirStatus = 0;
+ } else {
+ dirStatus = 0;
+ }
+ } else {
+ dirStatus = 0;
+ }
+ }
+ } // RTL
+
+ // IME will process these keys, so simply return
+ if (msg.wParam == VK_PROCESSKEY)
+ return true;
+
+ // Ignore invalid virtual keycodes (see bugs 127424, QTBUG-3630)
+ if (msg.wParam == 0 || msg.wParam == 0xFF)
+ return true;
+
+ // Translate VK_* (native) -> Key_* (Qt) keys
+ // If it's a dead key, we cannot use the toKeyOrUnicode() function, since that will change
+ // the internal state of the keyboard driver, resulting in that dead keys no longer works.
+ // ..also if we're typing numbers on the keypad, while holding down the Alt modifier.
+ int code = 0;
+ if (isNumpad && (nModifiers & AltAny)) {
+ code = winceKeyBend(msg.wParam);
+ } else if (!isDeadKey) {
+ unsigned char kbdBuffer[256]; // Will hold the complete keyboard state
+ GetKeyboardState(kbdBuffer);
+ code = toKeyOrUnicode(msg.wParam, scancode, kbdBuffer);
+ }
+
+ // Invert state logic:
+ // If the key actually pressed is a modifier key, then we remove its modifier key from the
+ // state, since a modifier-key can't have itself as a modifier
+ if (code == Qt::Key_Control)
+ state = state ^ Qt::ControlModifier;
+ else if (code == Qt::Key_Shift)
+ state = state ^ Qt::ShiftModifier;
+ else if (code == Qt::Key_Alt)
+ state = state ^ Qt::AltModifier;
+
+ // If the bit 24 of lParm is set you received a enter,
+ // otherwise a Return. (This is the extended key bit)
+ if ((code == Qt::Key_Return) && (msg.lParam & 0x1000000))
+ code = Qt::Key_Enter;
+
+ // All cursor keys without extended bit
+ if (!(msg.lParam & 0x1000000)) {
+ switch (code) {
+ case Qt::Key_Left:
+ case Qt::Key_Right:
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ case Qt::Key_PageUp:
+ case Qt::Key_PageDown:
+ case Qt::Key_Home:
+ case Qt::Key_End:
+ case Qt::Key_Insert:
+ case Qt::Key_Delete:
+ case Qt::Key_Asterisk:
+ case Qt::Key_Plus:
+ case Qt::Key_Minus:
+ case Qt::Key_Period:
+ case Qt::Key_0:
+ case Qt::Key_1:
+ case Qt::Key_2:
+ case Qt::Key_3:
+ case Qt::Key_4:
+ case Qt::Key_5:
+ case Qt::Key_6:
+ case Qt::Key_7:
+ case Qt::Key_8:
+ case Qt::Key_9:
+ state |= ((msg.wParam >= '0' && msg.wParam <= '9')
+ || (msg.wParam >= VK_OEM_PLUS && msg.wParam <= VK_OEM_3))
+ ? 0 : Qt::KeypadModifier;
+ default:
+ if ((uint)msg.lParam == 0x004c0001 || (uint)msg.lParam == 0xc04c0001)
+ state |= Qt::KeypadModifier;
+ break;
+ }
+ }
+ // Other keys with with extended bit
+ else {
+ switch (code) {
+ case Qt::Key_Enter:
+ case Qt::Key_Slash:
+ case Qt::Key_NumLock:
+ state |= Qt::KeypadModifier;
+ default:
+ break;
+ }
+ }
+
+ // KEYDOWN ---------------------------------------------------------------------------------
+ if (msgType == WM_KEYDOWN || msgType == WM_IME_KEYDOWN || msgType == WM_SYSKEYDOWN) {
+ // Get the last record of this key press, so we can validate the current state
+ // The record is not removed from the list
+ KeyRecord *rec = key_recorder.findKey(msg.wParam, false);
+
+ // If rec's state doesn't match the current state, something has changed behind our back
+ // (Consumed by modal widget is one possibility) So, remove the record from the list
+ // This will stop the auto-repeat of the key, should a modifier change, for example
+ if (rec && rec->state != state) {
+ key_recorder.findKey(msg.wParam, true);
+ rec = 0;
+ }
+
+ // Find unicode character from Windows Message Queue
+ MSG wm_char;
+ UINT charType = (msgType == WM_KEYDOWN
+ ? WM_CHAR
+ : msgType == WM_IME_KEYDOWN ? WM_IME_CHAR : WM_SYSCHAR);
+
+ QChar uch;
+ if (PeekMessage(&wm_char, 0, charType, charType, PM_REMOVE)) {
+ // Found a ?_CHAR
+ uch = QChar((ushort)wm_char.wParam);
+ if (msgType == WM_SYSKEYDOWN && uch.isLetter() && (msg.lParam & KF_ALTDOWN))
+ uch = uch.toLower(); // (See doc of WM_SYSCHAR) Alt-letter
+ if (!code && !uch.row())
+ code = asciiToKeycode(uch.cell(), state);
+ }
+
+ // Special handling for the WM_IME_KEYDOWN message. Microsoft IME (Korean) will not
+ // generate a WM_IME_CHAR message corresponding to this message. We might get wrong
+ // results, if we map this virtual key-code directly (for eg '?' US layouts). So try
+ // to find the correct key using the current message parameters & keyboard state.
+ if (uch.isNull() && msgType == WM_IME_KEYDOWN) {
+ BYTE keyState[256];
+ wchar_t newKey[3] = {0};
+ GetKeyboardState(keyState);
+ int val = ToUnicode(vk_key, scancode, keyState, newKey, 2, 0);
+ if (val == 1) {
+ uch = QChar(newKey[0]);
+ } else {
+ // If we are still not able to find a unicode key, pass the WM_IME_KEYDOWN
+ // message to DefWindowProc() for generating a proper WM_KEYDOWN.
+ return false;
+ }
+ }
+
+ // If no ?_CHAR was found in the queue; deduct character from the ?_KEYDOWN parameters
+ if (uch.isNull()) {
+ if (msg.wParam == VK_DELETE) {
+ uch = QChar(QLatin1Char(0x7f)); // Windows doesn't know this one.
+ } else {
+ if (msgType != WM_SYSKEYDOWN || !code) {
+ UINT map = MapVirtualKey(msg.wParam, 2);
+ // If the high bit of the return value is set, it's a deadkey
+ if (!(map & 0x80000000))
+ uch = QChar((ushort)map);
+ }
+ }
+ if (!code && !uch.row())
+ code = asciiToKeycode(uch.cell(), state);
+ }
+
+ // Special handling of global Windows hotkeys
+ if (state == Qt::AltModifier) {
+ switch (code) {
+ case Qt::Key_Escape:
+ case Qt::Key_Tab:
+ case Qt::Key_Enter:
+ case Qt::Key_F4:
+ return false; // Send the event on to Windows
+ case Qt::Key_Space:
+ // do not pass this key to windows, we will process it ourselves
+ showSystemMenu(receiver);
+ return true;
+ default:
+ break;
+ }
+ }
+
+ // Map SHIFT + Tab to SHIFT + BackTab, QShortcutMap knows about this translation
+ if (code == Qt::Key_Tab && (state & Qt::ShiftModifier) == Qt::ShiftModifier)
+ code = Qt::Key_Backtab;
+
+ // If we have a record, it means that the key is already pressed, the state is the same
+ // so, we have an auto-repeating key
+ if (rec) {
+ if (code < Qt::Key_Shift || code > Qt::Key_ScrollLock) {
+ QWindowSystemInterface::handleExtendedKeyEvent(receiver, QEvent::KeyRelease, code,
+ Qt::KeyboardModifier(state), scancode, msg.wParam, nModifiers, rec->text, true, 0);
+ QWindowSystemInterface::handleExtendedKeyEvent(receiver, QEvent::KeyPress, code,
+ Qt::KeyboardModifier(state), scancode, msg.wParam, nModifiers, rec->text, true, 0);
+ result = true;
+ }
+ }
+ // No record of the key being previous pressed, so we now send a QEvent::KeyPress event,
+ // and store the key data into our records.
+ else {
+ const QString text = uch.isNull() ? QString() : QString(uch);
+ const char a = uch.row() ? 0 : uch.cell();
+ key_recorder.storeKey(msg.wParam, a, state, text);
+ QWindowSystemInterface::handleExtendedKeyEvent(receiver, QEvent::KeyPress, code,
+ Qt::KeyboardModifier(state), scancode, msg.wParam, nModifiers, text, false, 0);
+ result =true;
+ bool store = true;
+ // Alt+<alphanumerical> go to the Win32 menu system if unhandled by Qt
+ if (msgType == WM_SYSKEYDOWN && !result && a) {
+ HWND parent = GetParent(QWindowsWindow::handleOf(receiver));
+ while (parent) {
+ if (GetMenu(parent)) {
+ SendMessage(parent, WM_SYSCOMMAND, SC_KEYMENU, a);
+ store = false;
+ result = true;
+ break;
+ }
+ parent = GetParent(parent);
+ }
+ }
+ if (!store)
+ key_recorder.findKey(msg.wParam, true);
+ }
+ }
+
+ // KEYUP -----------------------------------------------------------------------------------
+ else {
+ // Try to locate the key in our records, and remove it if it exists.
+ // The key may not be in our records if, for example, the down event was handled by
+ // win32 natively, or our window gets focus while a key is already press, but now gets
+ // the key release event.
+ KeyRecord* rec = key_recorder.findKey(msg.wParam, true);
+ if (!rec && !(code == Qt::Key_Shift
+ || code == Qt::Key_Control
+ || code == Qt::Key_Meta
+ || code == Qt::Key_Alt)) {
+ // Someone ate the key down event
+ } else {
+ if (!code)
+ code = asciiToKeycode(rec->ascii ? rec->ascii : msg.wParam, state);
+
+ // Map SHIFT + Tab to SHIFT + BackTab, QShortcutMap knows about this translation
+ if (code == Qt::Key_Tab && (state & Qt::ShiftModifier) == Qt::ShiftModifier)
+ code = Qt::Key_Backtab;
+ QWindowSystemInterface::handleExtendedKeyEvent(receiver, QEvent::KeyRelease, code,
+ Qt::KeyboardModifier(state), scancode, msg.wParam, nModifiers,
+ (rec ? rec->text : QString()), false, 0);
+ result = true;
+ // don't pass Alt to Windows unless we are embedded in a non-Qt window
+ if (code == Qt::Key_Alt) {
+ const QWindowsContext *context = QWindowsContext::instance();
+ HWND parent = GetParent(QWindowsWindow::handleOf(receiver));
+ while (parent) {
+ if (!context->findPlatformWindow(parent) && GetMenu(parent)) {
+ result = false;
+ break;
+ }
+ parent = GetParent(parent);
+ }
+ }
+ }
+ }
+ return result;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowskeymapper.h b/src/plugins/platforms/windows/qwindowskeymapper.h
new file mode 100644
index 0000000000..0d50193730
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowskeymapper.h
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSKEYMAPPER_H
+#define QWINDOWSKEYMAPPER_H
+
+#include "qtwindows_additional.h"
+
+#include <QtCore/QLocale>
+
+QT_BEGIN_NAMESPACE
+
+class QWindow;
+
+struct KeyboardLayoutItem;
+
+class QWindowsKeyMapper
+{
+ Q_DISABLE_COPY(QWindowsKeyMapper)
+public:
+ explicit QWindowsKeyMapper();
+ ~QWindowsKeyMapper();
+
+ void changeKeyboard();
+
+ void setUseRTLExtensions(bool e) { m_useRTLExtensions = e; }
+ bool useRTLExtensions() const { return m_useRTLExtensions; }
+
+ bool translateKeyEvent(QWindow *widget, HWND hwnd, const MSG &msg, LRESULT *result);
+
+ QWindow *keyGrabber() const { return m_keyGrabber; }
+ void setKeyGrabber(QWindow *w) { m_keyGrabber = w; }
+
+private:
+ bool translateKeyEventInternal(QWindow *receiver, const MSG &msg, bool grab);
+ void updateKeyMap(const MSG &msg);
+
+ bool m_useRTLExtensions;
+
+ QLocale keyboardInputLocale;
+ Qt::LayoutDirection keyboardInputDirection;
+
+ void clearRecordedKeys();
+ void updatePossibleKeyCodes(unsigned char *kbdBuffer, quint32 scancode, quint32 vk_key);
+ bool isADeadKey(unsigned int vk_key, unsigned int modifiers);
+ void deleteLayouts();
+
+ KeyboardLayoutItem *keyLayout[256];
+ QWindow *m_keyGrabber;
+};
+
+enum WindowsNativeModifiers {
+ ShiftLeft = 0x00000001,
+ ControlLeft = 0x00000002,
+ AltLeft = 0x00000004,
+ MetaLeft = 0x00000008,
+ ShiftRight = 0x00000010,
+ ControlRight = 0x00000020,
+ AltRight = 0x00000040,
+ MetaRight = 0x00000080,
+ CapsLock = 0x00000100,
+ NumLock = 0x00000200,
+ ScrollLock = 0x00000400,
+ ExtendedKey = 0x01000000,
+
+ // Convenience mappings
+ ShiftAny = 0x00000011,
+ ControlAny = 0x00000022,
+ AltAny = 0x00000044,
+ MetaAny = 0x00000088,
+ LockAny = 0x00000700
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSKEYMAPPER_H
diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp
new file mode 100644
index 0000000000..09104a43cf
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsmime.cpp
@@ -0,0 +1,1557 @@
+/****************************************************************************
+**
+** 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 "qwindowsmime.h"
+#include "qwindowscontext.h"
+
+#include <QtGui/private/qdnd_p.h>
+#include <QtCore/QTextCodec>
+#include <QtCore/QMap>
+#include <QtCore/QUrl>
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+#include <QtCore/QBuffer>
+#include <QtGui/QImageReader>
+#include <QtGui/QImageWriter>
+
+#include <shlobj.h>
+
+QT_BEGIN_NAMESPACE
+
+/* The MSVC compilers allows multi-byte characters, that has the behavior of
+ * that each character gets shifted into position. 0x73524742 below is for MSVC
+ * equivalent to doing 'sRGB', but this does of course not work
+ * on conformant C++ compilers. */
+#define BMP_LCS_sRGB 0x73524742
+#define BMP_LCS_GM_IMAGES 0x00000004L
+
+struct _CIEXYZ {
+ long ciexyzX, ciexyzY, ciexyzZ;
+};
+
+struct _CIEXYZTRIPLE {
+ _CIEXYZ ciexyzRed, ciexyzGreen, ciexyzBlue;
+};
+
+struct BMP_BITMAPV5HEADER {
+ DWORD bV5Size;
+ LONG bV5Width;
+ LONG bV5Height;
+ WORD bV5Planes;
+ WORD bV5BitCount;
+ DWORD bV5Compression;
+ DWORD bV5SizeImage;
+ LONG bV5XPelsPerMeter;
+ LONG bV5YPelsPerMeter;
+ DWORD bV5ClrUsed;
+ DWORD bV5ClrImportant;
+ DWORD bV5RedMask;
+ DWORD bV5GreenMask;
+ DWORD bV5BlueMask;
+ DWORD bV5AlphaMask;
+ DWORD bV5CSType;
+ _CIEXYZTRIPLE bV5Endpoints;
+ DWORD bV5GammaRed;
+ DWORD bV5GammaGreen;
+ DWORD bV5GammaBlue;
+ DWORD bV5Intent;
+ DWORD bV5ProfileData;
+ DWORD bV5ProfileSize;
+ DWORD bV5Reserved;
+};
+static const int BMP_BITFIELDS = 3;
+
+static const char dibFormatC[] = "dib";
+
+static inline QByteArray msgConversionError(const char *func, const char *format)
+{
+ QByteArray msg = func;
+ msg += ": Unable to convert DIB image. The image converter plugin for '";
+ msg += format;
+ msg += "' is not available. Available formats: ";
+ foreach (const QByteArray &af, QImageReader::supportedImageFormats()) {
+ msg += af;
+ msg += ' ';
+ }
+ return msg;
+}
+
+static inline QImage readDib(QByteArray data)
+{
+ QBuffer buffer(&data);
+ buffer.open(QIODevice::ReadOnly);
+ QImageReader reader(&buffer, dibFormatC);
+ if (!reader.canRead()) {
+ qWarning("%s", msgConversionError(__FUNCTION__, dibFormatC).constData());
+ return QImage();
+ }
+ return reader.read();
+}
+
+static QByteArray writeDib(const QImage &img)
+{
+ QByteArray ba;
+ QBuffer buffer(&ba);
+ buffer.open(QIODevice::ReadWrite);
+ QImageWriter writer(&buffer, dibFormatC);
+ if (!writer.canWrite()) {
+ qWarning("%s", msgConversionError(__FUNCTION__, dibFormatC).constData());
+ return ba;
+ }
+ if (!writer.write(img))
+ ba.clear();
+ return ba;
+}
+
+static bool qt_write_dibv5(QDataStream &s, QImage image)
+{
+ QIODevice* d = s.device();
+ if (!d->isWritable())
+ return false;
+
+ //depth will be always 32
+ int bpl_bmp = image.width()*4;
+
+ BMP_BITMAPV5HEADER bi ={0};
+ bi.bV5Size = sizeof(BMP_BITMAPV5HEADER);
+ bi.bV5Width = image.width();
+ bi.bV5Height = image.height();
+ bi.bV5Planes = 1;
+ bi.bV5BitCount = 32;
+ bi.bV5Compression = BI_BITFIELDS;
+ bi.bV5SizeImage = bpl_bmp*image.height();
+ bi.bV5XPelsPerMeter = 0;
+ bi.bV5YPelsPerMeter = 0;
+ bi.bV5ClrUsed = 0;
+ bi.bV5ClrImportant = 0;
+ bi.bV5BlueMask = 0x000000ff;
+ bi.bV5GreenMask = 0x0000ff00;
+ bi.bV5RedMask = 0x00ff0000;
+ bi.bV5AlphaMask = 0xff000000;
+ bi.bV5CSType = BMP_LCS_sRGB; //LCS_sRGB
+ bi.bV5Intent = BMP_LCS_GM_IMAGES; //LCS_GM_IMAGES
+
+ d->write(reinterpret_cast<const char*>(&bi), bi.bV5Size);
+ if (s.status() != QDataStream::Ok)
+ return false;
+
+ DWORD colorSpace[3] = {0x00ff0000,0x0000ff00,0x000000ff};
+ d->write(reinterpret_cast<const char*>(colorSpace), sizeof(colorSpace));
+ if (s.status() != QDataStream::Ok)
+ return false;
+
+ if (image.format() != QImage::Format_ARGB32)
+ image = image.convertToFormat(QImage::Format_ARGB32);
+
+ uchar *buf = new uchar[bpl_bmp];
+ uchar *b;
+
+ memset(buf, 0, bpl_bmp);
+ for (int y=image.height()-1; y>=0; y--) {
+ // write the image bits
+ QRgb *p = (QRgb *)image.scanLine(y);
+ QRgb *end = p + image.width();
+ b = buf;
+ while (p < end) {
+ int alpha = qAlpha(*p);
+ if (alpha) {
+ *b++ = qBlue(*p);
+ *b++ = qGreen(*p);
+ *b++ = qRed(*p);
+ } else {
+ //white for fully transparent pixels.
+ *b++ = 0xff;
+ *b++ = 0xff;
+ *b++ = 0xff;
+ }
+ *b++ = alpha;
+ p++;
+ }
+ d->write((char*)buf, bpl_bmp);
+ if (s.status() != QDataStream::Ok) {
+ delete[] buf;
+ return false;
+ }
+ }
+ delete[] buf;
+ return true;
+}
+
+static int calc_shift(int mask)
+{
+ int result = 0;
+ while (!(mask & 1)) {
+ result++;
+ mask >>= 1;
+ }
+ return result;
+}
+
+//Supports only 32 bit DIBV5
+static bool qt_read_dibv5(QDataStream &s, QImage &image)
+{
+ BMP_BITMAPV5HEADER bi;
+ QIODevice* d = s.device();
+ if (d->atEnd())
+ return false;
+
+ d->read((char *)&bi, sizeof(bi)); // read BITMAPV5HEADER header
+ if (s.status() != QDataStream::Ok)
+ return false;
+
+ int nbits = bi.bV5BitCount;
+ int comp = bi.bV5Compression;
+ if (nbits != 32 || bi.bV5Planes != 1 || comp != BMP_BITFIELDS)
+ return false; //Unsupported DIBV5 format
+
+ int w = bi.bV5Width, h = bi.bV5Height;
+ int red_mask = bi.bV5RedMask;
+ int green_mask = bi.bV5GreenMask;
+ int blue_mask = bi.bV5BlueMask;
+ int alpha_mask = bi.bV5AlphaMask;
+ int red_shift = 0;
+ int green_shift = 0;
+ int blue_shift = 0;
+ int alpha_shift = 0;
+ QImage::Format format = QImage::Format_ARGB32;
+
+ if (bi.bV5Height < 0)
+ h = -h; // support images with negative height
+ if (image.size() != QSize(w, h) || image.format() != format) {
+ image = QImage(w, h, format);
+ if (image.isNull()) // could not create image
+ return false;
+ }
+ image.setDotsPerMeterX(bi.bV5XPelsPerMeter);
+ image.setDotsPerMeterY(bi.bV5YPelsPerMeter);
+ // read color table
+ DWORD colorSpace[3];
+ if (d->read((char *)colorSpace, sizeof(colorSpace)) != sizeof(colorSpace))
+ return false;
+
+ red_shift = calc_shift(red_mask);
+ green_shift = calc_shift(green_mask);
+ blue_shift = calc_shift(blue_mask);
+ if (alpha_mask) {
+ alpha_shift = calc_shift(alpha_mask);
+ }
+
+ int bpl = image.bytesPerLine();
+ uchar *data = image.bits();
+ register QRgb *p;
+ QRgb *end;
+ uchar *buf24 = new uchar[bpl];
+ int bpl24 = ((w*nbits+31)/32)*4;
+ uchar *b;
+ unsigned int c;
+
+ while (--h >= 0) {
+ p = (QRgb *)(data + h*bpl);
+ end = p + w;
+ if (d->read((char *)buf24,bpl24) != bpl24)
+ break;
+ b = buf24;
+ while (p < end) {
+ c = *b | (*(b+1))<<8 | (*(b+2))<<16 | (*(b+3))<<24;
+ *p++ = qRgba(((c & red_mask) >> red_shift) ,
+ ((c & green_mask) >> green_shift),
+ ((c & blue_mask) >> blue_shift),
+ ((c & alpha_mask) >> alpha_shift));
+ b += 4;
+ }
+ }
+ delete[] buf24;
+
+ if (bi.bV5Height < 0) {
+ // Flip the image
+ uchar *buf = new uchar[bpl];
+ h = -bi.bV5Height;
+ for (int y = 0; y < h/2; ++y) {
+ memcpy(buf, data + y*bpl, bpl);
+ memcpy(data + y*bpl, data + (h-y-1)*bpl, bpl);
+ memcpy(data + (h-y-1)*bpl, buf, bpl);
+ }
+ delete [] buf;
+ }
+
+ return true;
+}
+
+//#define QMIME_DEBUG
+
+// helpers for using global memory
+
+static int getCf(const FORMATETC &formatetc)
+{
+ return formatetc.cfFormat;
+}
+
+static FORMATETC setCf(int cf)
+{
+ FORMATETC formatetc;
+ formatetc.cfFormat = cf;
+ formatetc.dwAspect = DVASPECT_CONTENT;
+ formatetc.lindex = -1;
+ formatetc.ptd = NULL;
+ formatetc.tymed = TYMED_HGLOBAL;
+ return formatetc;
+}
+
+static bool setData(const QByteArray &data, STGMEDIUM *pmedium)
+{
+ HGLOBAL hData = GlobalAlloc(0, data.size());
+ if (!hData)
+ return false;
+
+ void *out = GlobalLock(hData);
+ memcpy(out, data.data(), data.size());
+ GlobalUnlock(hData);
+ pmedium->tymed = TYMED_HGLOBAL;
+ pmedium->hGlobal = hData;
+ pmedium->pUnkForRelease = 0;
+ return true;
+}
+
+static QByteArray getData(int cf, IDataObject *pDataObj)
+{
+ QByteArray data;
+ FORMATETC formatetc = setCf(cf);
+ STGMEDIUM s;
+ if (pDataObj->GetData(&formatetc, &s) == S_OK) {
+ DWORD * val = (DWORD*)GlobalLock(s.hGlobal);
+ data = QByteArray::fromRawData((char*)val, GlobalSize(s.hGlobal));
+ data.detach();
+ GlobalUnlock(s.hGlobal);
+ ReleaseStgMedium(&s);
+ } else {
+ //Try reading IStream data
+ formatetc.tymed = TYMED_ISTREAM;
+ if (pDataObj->GetData(&formatetc, &s) == S_OK) {
+ char szBuffer[4096];
+ ULONG actualRead = 0;
+ LARGE_INTEGER pos = {{0, 0}};
+ //Move to front (can fail depending on the data model implemented)
+ HRESULT hr = s.pstm->Seek(pos, STREAM_SEEK_SET, NULL);
+ while(SUCCEEDED(hr)){
+ hr = s.pstm->Read(szBuffer, sizeof(szBuffer), &actualRead);
+ if (SUCCEEDED(hr) && actualRead > 0) {
+ data += QByteArray::fromRawData(szBuffer, actualRead);
+ }
+ if (actualRead != sizeof(szBuffer))
+ break;
+ }
+ data.detach();
+ ReleaseStgMedium(&s);
+ }
+ }
+ return data;
+}
+
+static bool canGetData(int cf, IDataObject * pDataObj)
+{
+ FORMATETC formatetc = setCf(cf);
+ if (pDataObj->QueryGetData(&formatetc) != S_OK){
+ formatetc.tymed = TYMED_ISTREAM;
+ return pDataObj->QueryGetData(&formatetc) == S_OK;
+ }
+ return true;
+}
+
+/*!
+ \class QWindowsMime
+ \brief The QWindowsMime class maps open-standard MIME to Window Clipboard formats.
+ \ingroup qt-lighthouse-win
+
+ Qt's drag-and-drop and clipboard facilities use the MIME standard.
+ On X11, this maps trivially to the Xdnd protocol, but on Windows
+ although some applications use MIME types to describe clipboard
+ formats, others use arbitrary non-standardized naming conventions,
+ or unnamed built-in formats of Windows.
+
+ By instantiating subclasses of QWindowsMime that provide conversions
+ between Windows Clipboard and MIME formats, you can convert
+ proprietary clipboard formats to MIME formats.
+
+ Qt has predefined support for the following Windows Clipboard formats:
+
+ \table
+ \header \o Windows Format \o Equivalent MIME type
+ \row \o \c CF_UNICODETEXT \o \c text/plain
+ \row \o \c CF_TEXT \o \c text/plain
+ \row \o \c CF_DIB \o \c{image/xyz}, where \c xyz is
+ a \l{QImageWriter::supportedImageFormats()}{Qt image format}
+ \row \o \c CF_HDROP \o \c text/uri-list
+ \row \o \c CF_INETURL \o \c text/uri-list
+ \row \o \c CF_HTML \o \c text/html
+ \endtable
+
+ An example use of this class would be to map the Windows Metafile
+ clipboard format (\c CF_METAFILEPICT) to and from the MIME type
+ \c{image/x-wmf}. This conversion might simply be adding or removing
+ a header, or even just passing on the data. See \l{Drag and Drop}
+ for more information on choosing and definition MIME types.
+
+ You can check if a MIME type is convertible using canConvertFromMime() and
+ can perform conversions with convertToMime() and convertFromMime().
+
+ \sa QWindowsMimeConverter
+*/
+
+/*!
+Constructs a new conversion object, adding it to the globally accessed
+list of available converters.
+*/
+QWindowsMime::QWindowsMime()
+{
+}
+
+/*!
+Destroys a conversion object, removing it from the global
+list of available converters.
+*/
+QWindowsMime::~QWindowsMime()
+{
+}
+
+/*!
+ Registers the MIME type \a mime, and returns an ID number
+ identifying the format on Windows.
+*/
+int QWindowsMime::registerMimeType(const QString &mime)
+{
+ int f = RegisterClipboardFormat(reinterpret_cast<const wchar_t *> (mime.utf16()));
+ if (!f)
+ qErrnoWarning("QWindowsMime::registerMimeType: Failed to register clipboard format");
+
+ return f;
+}
+
+/*!
+\fn bool QWindowsMime::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
+
+ Returns true if the converter can convert from the \a mimeData to
+ the format specified in \a formatetc.
+
+ All subclasses must reimplement this pure virtual function.
+*/
+
+/*!
+ \fn bool QWindowsMime::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
+
+ Returns true if the converter can convert to the \a mimeType from
+ the available formats in \a pDataObj.
+
+ All subclasses must reimplement this pure virtual function.
+*/
+
+/*!
+\fn QString QWindowsMime::mimeForFormat(const FORMATETC &formatetc) const
+
+ Returns the mime type that will be created form the format specified
+ in \a formatetc, or an empty string if this converter does not support
+ \a formatetc.
+
+ All subclasses must reimplement this pure virtual function.
+*/
+
+/*!
+\fn QVector<FORMATETC> QWindowsMime::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
+
+ Returns a QVector of FORMATETC structures representing the different windows clipboard
+ formats that can be provided for the \a mimeType from the \a mimeData.
+
+ All subclasses must reimplement this pure virtual function.
+*/
+
+/*!
+ \fn QVariant QWindowsMime::convertToMime(const QString &mimeType, IDataObject *pDataObj,
+ QVariant::Type preferredType) const
+
+ Returns a QVariant containing the converted data for \a mimeType from \a pDataObj.
+ If possible the QVariant should be of the \a preferredType to avoid needless conversions.
+
+ All subclasses must reimplement this pure virtual function.
+*/
+
+/*!
+\fn bool QWindowsMime::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const
+
+ Convert the \a mimeData to the format specified in \a formatetc.
+ The converted data should then be placed in \a pmedium structure.
+
+ Return true if the conversion was successful.
+
+ All subclasses must reimplement this pure virtual function.
+*/
+
+class QWindowsMimeText : public QWindowsMime
+{
+public:
+ bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const;
+ QVariant convertToMime(const QString &mime, LPDATAOBJECT pDataObj, QVariant::Type preferredType) const;
+ QString mimeForFormat(const FORMATETC &formatetc) const;
+ bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const;
+ bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const;
+ QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const;
+};
+
+bool QWindowsMimeText::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
+{
+ int cf = getCf(formatetc);
+ return (cf == CF_UNICODETEXT || cf == CF_TEXT) && mimeData->hasText();
+}
+
+/*
+text/plain is defined as using CRLF, but so many programs don't,
+and programmers just look for '\n' in strings.
+Windows really needs CRLF, so we ensure it here.
+*/
+bool QWindowsMimeText::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const
+{
+ if (canConvertFromMime(formatetc, mimeData)) {
+ QByteArray data;
+ int cf = getCf(formatetc);
+ if (cf == CF_TEXT) {
+ data = mimeData->text().toLocal8Bit();
+ // Anticipate required space for CRLFs at 1/40
+ int maxsize=data.size()+data.size()/40+3;
+ QByteArray r(maxsize, '\0');
+ char* o = r.data();
+ const char* d = data.data();
+ const int s = data.size();
+ bool cr=false;
+ int j=0;
+ for (int i=0; i<s; i++) {
+ char c = d[i];
+ if (c=='\r')
+ cr=true;
+ else {
+ if (c=='\n') {
+ if (!cr)
+ o[j++]='\r';
+ }
+ cr=false;
+ }
+ o[j++]=c;
+ if (j+3 >= maxsize) {
+ maxsize += maxsize/4;
+ r.resize(maxsize);
+ o = r.data();
+ }
+ }
+ o[j]=0;
+ return setData(r, pmedium);
+ } else if (cf == CF_UNICODETEXT) {
+ QString str = mimeData->text();
+ const QChar *u = str.unicode();
+ QString res;
+ const int s = str.length();
+ int maxsize = s + s/40 + 3;
+ res.resize(maxsize);
+ int ri = 0;
+ bool cr = false;
+ for (int i=0; i < s; ++i) {
+ if (*u == QLatin1Char('\r'))
+ cr = true;
+ else {
+ if (*u == QLatin1Char('\n') && !cr)
+ res[ri++] = QLatin1Char('\r');
+ cr = false;
+ }
+ res[ri++] = *u;
+ if (ri+3 >= maxsize) {
+ maxsize += maxsize/4;
+ res.resize(maxsize);
+ }
+ ++u;
+ }
+ res.truncate(ri);
+ const int byteLength = res.length() * sizeof(ushort);
+ QByteArray r(byteLength + 2, '\0');
+ memcpy(r.data(), res.unicode(), byteLength);
+ r[byteLength] = 0;
+ r[byteLength+1] = 0;
+ return setData(r, pmedium);
+ }
+ }
+ return false;
+}
+
+bool QWindowsMimeText::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
+{
+ return mimeType.startsWith(QStringLiteral("text/plain"))
+ && (canGetData(CF_UNICODETEXT, pDataObj)
+ || canGetData(CF_TEXT, pDataObj));
+}
+
+QString QWindowsMimeText::mimeForFormat(const FORMATETC &formatetc) const
+{
+ int cf = getCf(formatetc);
+ if (cf == CF_UNICODETEXT || cf == CF_TEXT)
+ return QStringLiteral("text/plain");
+ return QString();
+}
+
+
+QVector<FORMATETC> QWindowsMimeText::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
+{
+ QVector<FORMATETC> formatics;
+ if (mimeType.startsWith(QStringLiteral("text/plain")) && mimeData->hasText()) {
+ formatics += setCf(CF_UNICODETEXT);
+ formatics += setCf(CF_TEXT);
+ }
+ return formatics;
+}
+
+QVariant QWindowsMimeText::convertToMime(const QString &mime, LPDATAOBJECT pDataObj, QVariant::Type preferredType) const
+{
+ QVariant ret;
+
+ if (canConvertToMime(mime, pDataObj)) {
+ QString str;
+ QByteArray data = getData(CF_UNICODETEXT, pDataObj);
+ if (!data.isEmpty()) {
+ str = QString::fromWCharArray((const wchar_t *)data.data());
+ str.replace(QStringLiteral("\r\n"), QStringLiteral("\n"));
+ } else {
+ data = getData(CF_TEXT, pDataObj);
+ if (!data.isEmpty()) {
+ const char* d = data.data();
+ const int s = qstrlen(d);
+ QByteArray r(data.size()+1, '\0');
+ char* o = r.data();
+ int j=0;
+ for (int i=0; i<s; i++) {
+ char c = d[i];
+ if (c!='\r')
+ o[j++]=c;
+ }
+ o[j]=0;
+ str = QString::fromLocal8Bit(r);
+ }
+ }
+ if (preferredType == QVariant::String)
+ ret = str;
+ else
+ ret = str.toUtf8();
+ }
+ if (QWindowsContext::verboseOLE)
+ qDebug() << __FUNCTION__ << ret;
+ return ret;
+}
+
+class QWindowsMimeURI : public QWindowsMime
+{
+public:
+ QWindowsMimeURI();
+ bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const;
+ QVariant convertToMime(const QString &mime, LPDATAOBJECT pDataObj, QVariant::Type preferredType) const;
+ QString mimeForFormat(const FORMATETC &formatetc) const;
+ bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const;
+ bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const;
+ QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const;
+private:
+ int CF_INETURL_W; // wide char version
+ int CF_INETURL;
+};
+
+QWindowsMimeURI::QWindowsMimeURI()
+{
+ CF_INETURL_W = QWindowsMime::registerMimeType(QStringLiteral("UniformResourceLocatorW"));
+ CF_INETURL = QWindowsMime::registerMimeType(QStringLiteral("UniformResourceLocator"));
+}
+
+bool QWindowsMimeURI::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
+{
+ if (getCf(formatetc) == CF_HDROP) {
+ QList<QUrl> urls = mimeData->urls();
+ for (int i=0; i<urls.size(); i++) {
+ if (!urls.at(i).toLocalFile().isEmpty())
+ return true;
+ }
+ }
+ return (getCf(formatetc) == CF_INETURL_W || getCf(formatetc) == CF_INETURL) && mimeData->hasFormat(QStringLiteral("text/uri-list"));
+}
+
+bool QWindowsMimeURI::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const
+{
+ if (canConvertFromMime(formatetc, mimeData)) {
+ if (getCf(formatetc) == CF_HDROP) {
+ QList<QUrl> urls = mimeData->urls();
+ QStringList fileNames;
+ int size = sizeof(DROPFILES)+2;
+ for (int i=0; i<urls.size(); i++) {
+ QString fn = QDir::toNativeSeparators(urls.at(i).toLocalFile());
+ if (!fn.isEmpty()) {
+ size += sizeof(ushort) * (fn.length() + 1);
+ fileNames.append(fn);
+ }
+ }
+
+ QByteArray result(size, '\0');
+ DROPFILES* d = (DROPFILES*)result.data();
+ d->pFiles = sizeof(DROPFILES);
+ GetCursorPos(&d->pt); // try
+ d->fNC = true;
+ char* files = ((char*)d) + d->pFiles;
+
+ d->fWide = true;
+ wchar_t* f = (wchar_t*)files;
+ for (int i=0; i<fileNames.size(); i++) {
+ int l = fileNames.at(i).length();
+ memcpy(f, fileNames.at(i).utf16(), l * sizeof(ushort));
+ f += l;
+ *f++ = 0;
+ }
+ *f = 0;
+
+ return setData(result, pmedium);
+ } else if (getCf(formatetc) == CF_INETURL_W) {
+ QList<QUrl> urls = mimeData->urls();
+ QByteArray result;
+ if (!urls.isEmpty()) {
+ QString url = urls.at(0).toString();
+ result = QByteArray((const char *)url.utf16(), url.length() * sizeof(ushort));
+ }
+ result.append('\0');
+ result.append('\0');
+ return setData(result, pmedium);
+ } else if (getCf(formatetc) == CF_INETURL) {
+ QList<QUrl> urls = mimeData->urls();
+ QByteArray result;
+ if (!urls.isEmpty())
+ result = urls.at(0).toString().toLocal8Bit();
+ return setData(result, pmedium);
+ }
+ }
+
+ return false;
+}
+
+bool QWindowsMimeURI::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
+{
+ return mimeType == QStringLiteral("text/uri-list")
+ && (canGetData(CF_HDROP, pDataObj) || canGetData(CF_INETURL_W, pDataObj) || canGetData(CF_INETURL, pDataObj));
+}
+
+QString QWindowsMimeURI::mimeForFormat(const FORMATETC &formatetc) const
+{
+ QString format;
+ if (getCf(formatetc) == CF_HDROP || getCf(formatetc) == CF_INETURL_W || getCf(formatetc) == CF_INETURL)
+ format = QStringLiteral("text/uri-list");
+ return format;
+}
+
+QVector<FORMATETC> QWindowsMimeURI::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
+{
+ QVector<FORMATETC> formatics;
+ if (mimeType == QStringLiteral("text/uri-list")) {
+ if (canConvertFromMime(setCf(CF_HDROP), mimeData))
+ formatics += setCf(CF_HDROP);
+ if (canConvertFromMime(setCf(CF_INETURL_W), mimeData))
+ formatics += setCf(CF_INETURL_W);
+ if (canConvertFromMime(setCf(CF_INETURL), mimeData))
+ formatics += setCf(CF_INETURL);
+ }
+ return formatics;
+}
+
+QVariant QWindowsMimeURI::convertToMime(const QString &mimeType, LPDATAOBJECT pDataObj, QVariant::Type preferredType) const
+{
+ if (mimeType == QStringLiteral("text/uri-list")) {
+ if (canGetData(CF_HDROP, pDataObj)) {
+ QByteArray texturi;
+ QList<QVariant> urls;
+
+ QByteArray data = getData(CF_HDROP, pDataObj);
+ if (data.isEmpty())
+ return QVariant();
+
+ LPDROPFILES hdrop = (LPDROPFILES)data.data();
+ if (hdrop->fWide) {
+ const wchar_t* filesw = (const wchar_t *)(data.data() + hdrop->pFiles);
+ int i = 0;
+ while (filesw[i]) {
+ QString fileurl = QString::fromWCharArray(filesw + i);
+ urls += QUrl::fromLocalFile(fileurl);
+ i += fileurl.length()+1;
+ }
+ } else {
+ const char* files = (const char *)data.data() + hdrop->pFiles;
+ int i=0;
+ while (files[i]) {
+ urls += QUrl::fromLocalFile(QString::fromLocal8Bit(files+i));
+ i += int(strlen(files+i))+1;
+ }
+ }
+
+ if (preferredType == QVariant::Url && urls.size() == 1)
+ return urls.at(0);
+ else if (!urls.isEmpty())
+ return urls;
+ } else if (canGetData(CF_INETURL_W, pDataObj)) {
+ QByteArray data = getData(CF_INETURL_W, pDataObj);
+ if (data.isEmpty())
+ return QVariant();
+ return QUrl(QString::fromWCharArray((const wchar_t *)data.constData()));
+ } else if (canGetData(CF_INETURL, pDataObj)) {
+ QByteArray data = getData(CF_INETURL, pDataObj);
+ if (data.isEmpty())
+ return QVariant();
+ return QUrl(QString::fromLocal8Bit(data.constData()));
+ }
+ }
+ return QVariant();
+}
+
+class QWindowsMimeHtml : public QWindowsMime
+{
+public:
+ QWindowsMimeHtml();
+
+ // for converting from Qt
+ bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const;
+ bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const;
+ QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const;
+
+ // for converting to Qt
+ bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const;
+ QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const;
+ QString mimeForFormat(const FORMATETC &formatetc) const;
+
+private:
+ int CF_HTML;
+};
+
+QWindowsMimeHtml::QWindowsMimeHtml()
+{
+ CF_HTML = QWindowsMime::registerMimeType(QStringLiteral("HTML Format"));
+}
+
+QVector<FORMATETC> QWindowsMimeHtml::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
+{
+ QVector<FORMATETC> formatetcs;
+ if (mimeType == QStringLiteral("text/html") && (!mimeData->html().isEmpty()))
+ formatetcs += setCf(CF_HTML);
+ return formatetcs;
+}
+
+QString QWindowsMimeHtml::mimeForFormat(const FORMATETC &formatetc) const
+{
+ if (getCf(formatetc) == CF_HTML)
+ return QStringLiteral("text/html");
+ return QString();
+}
+
+bool QWindowsMimeHtml::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
+{
+ return mimeType == QStringLiteral("text/html") && canGetData(CF_HTML, pDataObj);
+}
+
+
+bool QWindowsMimeHtml::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
+{
+ return getCf(formatetc) == CF_HTML && (!mimeData->html().isEmpty());
+}
+
+/*
+The windows HTML clipboard format is as follows (xxxxxxxxxx is a 10 integer number giving the positions
+in bytes). Charset used is mostly utf8, but can be different, ie. we have to look for the <meta> charset tag
+
+ Version: 1.0
+ StartHTML:xxxxxxxxxx
+ EndHTML:xxxxxxxxxx
+ StartFragment:xxxxxxxxxx
+ EndFragment:xxxxxxxxxx
+ ...html...
+
+*/
+QVariant QWindowsMimeHtml::convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const
+{
+ Q_UNUSED(preferredType);
+ QVariant result;
+ if (canConvertToMime(mime, pDataObj)) {
+ QByteArray html = getData(CF_HTML, pDataObj);
+#ifdef QMIME_DEBUG
+ qDebug("QWindowsMimeHtml::convertToMime");
+ qDebug("raw :");
+ qDebug(html);
+#endif
+ int start = html.indexOf("StartFragment:");
+ int end = html.indexOf("EndFragment:");
+
+ if (start != -1) {
+ int startOffset = start + 14;
+ int i = startOffset;
+ while (html.at(i) != '\r' && html.at(i) != '\n')
+ ++i;
+ QByteArray bytecount = html.mid(startOffset, i - startOffset);
+ start = bytecount.toInt();
+ }
+
+ if (end != -1) {
+ int endOffset = end + 12;
+ int i = endOffset ;
+ while (html.at(i) != '\r' && html.at(i) != '\n')
+ ++i;
+ QByteArray bytecount = html.mid(endOffset , i - endOffset);
+ end = bytecount.toInt();
+ }
+
+ if (end > start && start > 0) {
+ html = "<!--StartFragment-->" + html.mid(start, end - start);
+ html += "<!--EndFragment-->";
+ html.replace('\r', "");
+ result = QString::fromUtf8(html);
+ }
+ }
+ return result;
+}
+
+bool QWindowsMimeHtml::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const
+{
+ if (canConvertFromMime(formatetc, mimeData)) {
+ QByteArray data = mimeData->html().toUtf8();
+ QByteArray result =
+ "Version:1.0\r\n" // 0-12
+ "StartHTML:0000000105\r\n" // 13-35
+ "EndHTML:0000000000\r\n" // 36-55
+ "StartFragment:0000000000\r\n" // 58-86
+ "EndFragment:0000000000\r\n\r\n"; // 87-105
+
+ if (data.indexOf("<!--StartFragment-->") == -1)
+ result += "<!--StartFragment-->";
+ result += data;
+ if (data.indexOf("<!--EndFragment-->") == -1)
+ result += "<!--EndFragment-->";
+
+ // set the correct number for EndHTML
+ QByteArray pos = QString::number(result.size()).toLatin1();
+ memcpy((char *)(result.data() + 53 - pos.length()), pos.constData(), pos.length());
+
+ // set correct numbers for StartFragment and EndFragment
+ pos = QString::number(result.indexOf("<!--StartFragment-->") + 20).toLatin1();
+ memcpy((char *)(result.data() + 79 - pos.length()), pos.constData(), pos.length());
+ pos = QString::number(result.indexOf("<!--EndFragment-->")).toLatin1();
+ memcpy((char *)(result.data() + 103 - pos.length()), pos.constData(), pos.length());
+
+ return setData(result, pmedium);
+ }
+ return false;
+}
+
+
+#ifndef QT_NO_IMAGEFORMAT_BMP
+class QWindowsMimeImage : public QWindowsMime
+{
+public:
+ QWindowsMimeImage();
+ // for converting from Qt
+ bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const;
+ bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const;
+ QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const;
+
+ // for converting to Qt
+ bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const;
+ QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const;
+ QString mimeForFormat(const FORMATETC &formatetc) const;
+private:
+ bool hasOriginalDIBV5(IDataObject *pDataObj) const;
+ UINT CF_PNG;
+};
+
+QWindowsMimeImage::QWindowsMimeImage()
+{
+ CF_PNG = RegisterClipboardFormat(L"PNG");
+}
+
+QVector<FORMATETC> QWindowsMimeImage::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
+{
+ QVector<FORMATETC> formatetcs;
+ if (mimeData->hasImage() && mimeType == QStringLiteral("application/x-qt-image")) {
+ //add DIBV5 if image has alpha channel
+ QImage image = qvariant_cast<QImage>(mimeData->imageData());
+ if (!image.isNull() && image.hasAlphaChannel())
+ formatetcs += setCf(CF_DIBV5);
+ formatetcs += setCf(CF_DIB);
+ }
+ return formatetcs;
+}
+
+QString QWindowsMimeImage::mimeForFormat(const FORMATETC &formatetc) const
+{
+ int cf = getCf(formatetc);
+ if (cf == CF_DIB || cf == CF_DIBV5 || cf == int(CF_PNG))
+ return QStringLiteral("application/x-qt-image");
+ return QString();
+}
+
+bool QWindowsMimeImage::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
+{
+ if ((mimeType == QStringLiteral("application/x-qt-image")) &&
+ (canGetData(CF_DIB, pDataObj) || canGetData(CF_PNG, pDataObj)))
+ return true;
+ return false;
+}
+
+bool QWindowsMimeImage::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
+{
+ int cf = getCf(formatetc);
+ if (mimeData->hasImage()) {
+ if (cf == CF_DIB)
+ return true;
+ else if (cf == CF_DIBV5) {
+ //support DIBV5 conversion only if the image has alpha channel
+ QImage image = qvariant_cast<QImage>(mimeData->imageData());
+ if (!image.isNull() && image.hasAlphaChannel())
+ return true;
+ }
+ }
+ return false;
+}
+
+bool QWindowsMimeImage::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const
+{
+ int cf = getCf(formatetc);
+ if ((cf == CF_DIB || cf == CF_DIBV5) && mimeData->hasImage()) {
+ QImage img = qvariant_cast<QImage>(mimeData->imageData());
+ if (img.isNull())
+ return false;
+ QByteArray ba;
+ if (cf == CF_DIB) {
+ if (img.format() > QImage::Format_ARGB32)
+ img = img.convertToFormat(QImage::Format_RGB32);
+ const QByteArray ba = writeDib(img);
+ if (!ba.isEmpty())
+ return setData(ba, pmedium);
+ } else {
+ QDataStream s(&ba, QIODevice::WriteOnly);
+ s.setByteOrder(QDataStream::LittleEndian);// Intel byte order ####
+ if (qt_write_dibv5(s, img))
+ return setData(ba, pmedium);
+ }
+ }
+ return false;
+}
+
+bool QWindowsMimeImage::hasOriginalDIBV5(IDataObject *pDataObj) const
+{
+ bool isSynthesized = true;
+ IEnumFORMATETC *pEnum =NULL;
+ HRESULT res = pDataObj->EnumFormatEtc(1, &pEnum);
+ if (res == S_OK && pEnum) {
+ FORMATETC fc;
+ while ((res = pEnum->Next(1, &fc, 0)) == S_OK) {
+ if (fc.ptd)
+ CoTaskMemFree(fc.ptd);
+ if (fc.cfFormat == CF_DIB)
+ break;
+ else if (fc.cfFormat == CF_DIBV5) {
+ isSynthesized = false;
+ break;
+ }
+ }
+ pEnum->Release();
+ }
+ return !isSynthesized;
+}
+
+QVariant QWindowsMimeImage::convertToMime(const QString &mimeType, IDataObject *pDataObj, QVariant::Type preferredType) const
+{
+ Q_UNUSED(preferredType);
+ QVariant result;
+ if (mimeType != QStringLiteral("application/x-qt-image"))
+ return result;
+ //Try to convert from a format which has more data
+ //DIBV5, use only if its is not synthesized
+ if (canGetData(CF_DIBV5, pDataObj) && hasOriginalDIBV5(pDataObj)) {
+ QImage img;
+ QByteArray data = getData(CF_DIBV5, pDataObj);
+ QDataStream s(&data, QIODevice::ReadOnly);
+ s.setByteOrder(QDataStream::LittleEndian);
+ if (qt_read_dibv5(s, img)) { // #### supports only 32bit DIBV5
+ return img;
+ }
+ }
+ //PNG, MS Office place this (undocumented)
+ if (canGetData(CF_PNG, pDataObj)) {
+ QImage img;
+ QByteArray data = getData(CF_PNG, pDataObj);
+ if (img.loadFromData(data, "PNG")) {
+ return img;
+ }
+ }
+ //Fallback to DIB
+ if (canGetData(CF_DIB, pDataObj)) {
+ const QImage img = readDib(getData(CF_DIB, pDataObj));
+ if (!img.isNull())
+ return img;
+ }
+ // Failed
+ return result;
+}
+#endif
+
+class QBuiltInMimes : public QWindowsMime
+{
+public:
+ QBuiltInMimes();
+
+ // for converting from Qt
+ bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const;
+ bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const;
+ QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const;
+
+ // for converting to Qt
+ bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const;
+ QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const;
+ QString mimeForFormat(const FORMATETC &formatetc) const;
+
+private:
+ QMap<int, QString> outFormats;
+ QMap<int, QString> inFormats;
+};
+
+QBuiltInMimes::QBuiltInMimes()
+: QWindowsMime()
+{
+ outFormats.insert(QWindowsMime::registerMimeType(QStringLiteral("application/x-color")), QStringLiteral("application/x-color"));
+ inFormats.insert(QWindowsMime::registerMimeType(QStringLiteral("application/x-color")), QStringLiteral("application/x-color"));
+}
+
+bool QBuiltInMimes::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
+{
+ // really check
+ return formatetc.tymed & TYMED_HGLOBAL
+ && outFormats.contains(formatetc.cfFormat)
+ && mimeData->formats().contains(outFormats.value(formatetc.cfFormat));
+}
+
+bool QBuiltInMimes::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const
+{
+ if (canConvertFromMime(formatetc, mimeData)) {
+ QByteArray data;
+ if (outFormats.value(getCf(formatetc)) == QStringLiteral("text/html")) {
+ // text/html is in wide chars on windows (compatible with mozillia)
+ QString html = mimeData->html();
+ // same code as in the text converter up above
+ const QChar *u = html.unicode();
+ QString res;
+ const int s = html.length();
+ int maxsize = s + s/40 + 3;
+ res.resize(maxsize);
+ int ri = 0;
+ bool cr = false;
+ for (int i=0; i < s; ++i) {
+ if (*u == QLatin1Char('\r'))
+ cr = true;
+ else {
+ if (*u == QLatin1Char('\n') && !cr)
+ res[ri++] = QLatin1Char('\r');
+ cr = false;
+ }
+ res[ri++] = *u;
+ if (ri+3 >= maxsize) {
+ maxsize += maxsize/4;
+ res.resize(maxsize);
+ }
+ ++u;
+ }
+ res.truncate(ri);
+ const int byteLength = res.length() * sizeof(ushort);
+ QByteArray r(byteLength + 2, '\0');
+ memcpy(r.data(), res.unicode(), byteLength);
+ r[byteLength] = 0;
+ r[byteLength+1] = 0;
+ data = r;
+ } else {
+#ifndef QT_NO_DRAGANDDROP
+ data = QInternalMimeData::renderDataHelper(outFormats.value(getCf(formatetc)), mimeData);
+#endif //QT_NO_DRAGANDDROP
+ }
+ return setData(data, pmedium);
+ }
+ return false;
+}
+
+QVector<FORMATETC> QBuiltInMimes::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const
+{
+ QVector<FORMATETC> formatetcs;
+ if (!outFormats.keys(mimeType).isEmpty() && mimeData->formats().contains(mimeType))
+ formatetcs += setCf(outFormats.key(mimeType));
+ return formatetcs;
+}
+
+bool QBuiltInMimes::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
+{
+ return (!inFormats.keys(mimeType).isEmpty())
+ && canGetData(inFormats.key(mimeType), pDataObj);
+}
+
+QVariant QBuiltInMimes::convertToMime(const QString &mimeType, IDataObject *pDataObj, QVariant::Type preferredType) const
+{
+ QVariant val;
+ if (canConvertToMime(mimeType, pDataObj)) {
+ QByteArray data = getData(inFormats.key(mimeType), pDataObj);
+ if (!data.isEmpty()) {
+#ifdef QMIME_DEBUG
+ qDebug("QBuiltInMimes::convertToMime()");
+#endif
+ if (mimeType == QStringLiteral("text/html") && preferredType == QVariant::String) {
+ // text/html is in wide chars on windows (compatible with Mozilla)
+ val = QString::fromWCharArray((const wchar_t *)data.data());
+ } else {
+ val = data; // it should be enough to return the data and let QMimeData do the rest.
+ }
+ }
+ }
+ return val;
+}
+
+QString QBuiltInMimes::mimeForFormat(const FORMATETC &formatetc) const
+{
+ return inFormats.value(getCf(formatetc));
+}
+
+
+class QLastResortMimes : public QWindowsMime
+{
+public:
+
+ QLastResortMimes();
+ // for converting from Qt
+ bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const;
+ bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const;
+ QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const;
+
+ // for converting to Qt
+ bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const;
+ QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const;
+ QString mimeForFormat(const FORMATETC &formatetc) const;
+
+private:
+ QMap<int, QString> formats;
+ static QStringList ianaTypes;
+ static QStringList excludeList;
+};
+
+QStringList QLastResortMimes::ianaTypes;
+QStringList QLastResortMimes::excludeList;
+
+QLastResortMimes::QLastResortMimes()
+{
+ //MIME Media-Types
+ if (!ianaTypes.size()) {
+ ianaTypes.append(QStringLiteral("application/"));
+ ianaTypes.append(QStringLiteral("audio/"));
+ ianaTypes.append(QStringLiteral("example/"));
+ ianaTypes.append(QStringLiteral("image/"));
+ ianaTypes.append(QStringLiteral("message/"));
+ ianaTypes.append(QStringLiteral("model/"));
+ ianaTypes.append(QStringLiteral("multipart/"));
+ ianaTypes.append(QStringLiteral("text/"));
+ ianaTypes.append(QStringLiteral("video/"));
+ }
+ //Types handled by other classes
+ if (!excludeList.size()) {
+ excludeList.append(QStringLiteral("HTML Format"));
+ excludeList.append(QStringLiteral("UniformResourceLocator"));
+ excludeList.append(QStringLiteral("text/html"));
+ excludeList.append(QStringLiteral("text/plain"));
+ excludeList.append(QStringLiteral("text/uri-list"));
+ excludeList.append(QStringLiteral("application/x-qt-image"));
+ excludeList.append(QStringLiteral("application/x-color"));
+ }
+}
+
+bool QLastResortMimes::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
+{
+ // really check
+#ifndef QT_NO_DRAGANDDROP
+ return formatetc.tymed & TYMED_HGLOBAL
+ && (formats.contains(formatetc.cfFormat)
+ && QInternalMimeData::hasFormatHelper(formats.value(formatetc.cfFormat), mimeData));
+#else
+ Q_UNUSED(mimeData);
+ Q_UNUSED(formatetc);
+ return formatetc.tymed & TYMED_HGLOBAL
+ && formats.contains(formatetc.cfFormat);
+#endif //QT_NO_DRAGANDDROP
+}
+
+bool QLastResortMimes::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const
+{
+#ifndef QT_NO_DRAGANDDROP
+ return canConvertFromMime(formatetc, mimeData)
+ && setData(QInternalMimeData::renderDataHelper(formats.value(getCf(formatetc)), mimeData), pmedium);
+#else
+ Q_UNUSED(mimeData);
+ Q_UNUSED(formatetc);
+ Q_UNUSED(pmedium);
+ return false;
+#endif //QT_NO_DRAGANDDROP
+}
+
+QVector<FORMATETC> QLastResortMimes::formatsForMime(const QString &mimeType, const QMimeData * /*mimeData*/) const
+{
+ QVector<FORMATETC> formatetcs;
+ if (!formats.keys(mimeType).isEmpty()) {
+ formatetcs += setCf(formats.key(mimeType));
+ } else if (!excludeList.contains(mimeType, Qt::CaseInsensitive)){
+ // register any other available formats
+ int cf = QWindowsMime::registerMimeType(mimeType);
+ QLastResortMimes *that = const_cast<QLastResortMimes *>(this);
+ that->formats.insert(cf, mimeType);
+ formatetcs += setCf(cf);
+ }
+ return formatetcs;
+}
+static const char x_qt_windows_mime[] = "application/x-qt-windows-mime;value=\"";
+
+static bool isCustomMimeType(const QString &mimeType)
+{
+ return mimeType.startsWith(QLatin1String(x_qt_windows_mime), Qt::CaseInsensitive);
+}
+
+static QString customMimeType(const QString &mimeType)
+{
+ int len = sizeof(x_qt_windows_mime) - 1;
+ int n = mimeType.lastIndexOf(QLatin1Char('\"'))-len;
+ return mimeType.mid(len, n);
+}
+
+bool QLastResortMimes::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
+{
+ if (isCustomMimeType(mimeType)) {
+ QString clipFormat = customMimeType(mimeType);
+ int cf = RegisterClipboardFormat(reinterpret_cast<const wchar_t *> (clipFormat.utf16()));
+ return canGetData(cf, pDataObj);
+ } else if (formats.keys(mimeType).isEmpty()) {
+ // if it is not in there then register it an see if we can get it
+ int cf = QWindowsMime::registerMimeType(mimeType);
+ return canGetData(cf, pDataObj);
+ } else {
+ return canGetData(formats.key(mimeType), pDataObj);
+ }
+ return false;
+}
+
+QVariant QLastResortMimes::convertToMime(const QString &mimeType, IDataObject *pDataObj, QVariant::Type preferredType) const
+{
+ Q_UNUSED(preferredType);
+ QVariant val;
+ if (canConvertToMime(mimeType, pDataObj)) {
+ QByteArray data;
+ if (isCustomMimeType(mimeType)) {
+ QString clipFormat = customMimeType(mimeType);
+ int cf = RegisterClipboardFormat(reinterpret_cast<const wchar_t *> (clipFormat.utf16()));
+ data = getData(cf, pDataObj);
+ } else if (formats.keys(mimeType).isEmpty()) {
+ int cf = QWindowsMime::registerMimeType(mimeType);
+ data = getData(cf, pDataObj);
+ } else {
+ data = getData(formats.key(mimeType), pDataObj);
+ }
+ if (!data.isEmpty())
+ val = data; // it should be enough to return the data and let QMimeData do the rest.
+ }
+ return val;
+}
+
+QString QLastResortMimes::mimeForFormat(const FORMATETC &formatetc) const
+{
+ QString format = formats.value(getCf(formatetc));
+ if (!format.isEmpty())
+ return format;
+
+ wchar_t buffer[256];
+ int len = GetClipboardFormatName(getCf(formatetc), buffer, 256);
+
+ if (len) {
+ QString clipFormat = QString::fromWCharArray(buffer, len);
+#ifndef QT_NO_DRAGANDDROP
+ if (QInternalMimeData::canReadData(clipFormat))
+ format = clipFormat;
+ else if((formatetc.cfFormat >= 0xC000)){
+ //create the mime as custom. not registered.
+ if (!excludeList.contains(clipFormat, Qt::CaseInsensitive)) {
+ //check if this is a mime type
+ bool ianaType = false;
+ int sz = ianaTypes.size();
+ for (int i = 0; i < sz; i++) {
+ if (clipFormat.startsWith(ianaTypes[i], Qt::CaseInsensitive)) {
+ ianaType = true;
+ break;
+ }
+ }
+ if (!ianaType)
+ format = QLatin1String(x_qt_windows_mime) + clipFormat + QLatin1Char('\"');
+ else
+ format = clipFormat;
+ }
+ }
+#endif //QT_NO_DRAGANDDROP
+ }
+
+ return format;
+}
+
+/*!
+ \class QWindowsMimeConverter
+ \brief Manages the list of QWindowsMime instances.
+ \ingroup qt-lighthouse-win
+ \sa QWindowsMime
+*/
+
+QWindowsMimeConverter::QWindowsMimeConverter()
+{
+}
+
+QWindowsMimeConverter::~QWindowsMimeConverter()
+{
+ qDeleteAll(m_mimes);
+}
+
+QWindowsMime * QWindowsMimeConverter::converterToMime(const QString &mimeType, IDataObject *pDataObj) const
+{
+ ensureInitialized();
+ for (int i = m_mimes.size()-1; i >= 0; --i) {
+ if (m_mimes.at(i)->canConvertToMime(mimeType, pDataObj))
+ return m_mimes.at(i);
+ }
+ return 0;
+}
+
+QStringList QWindowsMimeConverter::allMimesForFormats(IDataObject *pDataObj) const
+{
+ ensureInitialized();
+ QStringList formats;
+ LPENUMFORMATETC FAR fmtenum;
+ HRESULT hr = pDataObj->EnumFormatEtc(DATADIR_GET, &fmtenum);
+
+ if (hr == NOERROR) {
+ FORMATETC fmtetc;
+ while (S_OK == fmtenum->Next(1, &fmtetc, 0)) {
+#if defined(QMIME_DEBUG)
+ qDebug("QWindowsMime::allMimesForFormats()");
+ wchar_t buf[256] = {0};
+ GetClipboardFormatName(fmtetc.cfFormat, buf, 255);
+ qDebug("CF = %d : %s", fmtetc.cfFormat, QString::fromWCharArray(buf));
+#endif
+ for (int i= m_mimes.size() - 1; i >= 0; --i) {
+ QString format = m_mimes.at(i)->mimeForFormat(fmtetc);
+ if (!format.isEmpty() && !formats.contains(format)) {
+ formats += format;
+ }
+ }
+ // as documented in MSDN to avoid possible memleak
+ if (fmtetc.ptd)
+ CoTaskMemFree(fmtetc.ptd);
+ }
+ fmtenum->Release();
+ }
+ if (QWindowsContext::verboseOLE)
+ qDebug() << __FUNCTION__ << pDataObj << formats;
+ return formats;
+}
+
+QWindowsMime * QWindowsMimeConverter::converterFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
+{
+ ensureInitialized();
+ for (int i = m_mimes.size()-1; i >= 0; --i) {
+ if (m_mimes.at(i)->canConvertFromMime(formatetc, mimeData))
+ return m_mimes.at(i);
+ }
+ return 0;
+}
+
+QVector<FORMATETC> QWindowsMimeConverter::allFormatsForMime(const QMimeData *mimeData) const
+{
+ ensureInitialized();
+ QVector<FORMATETC> formatics;
+#ifdef QT_NO_DRAGANDDROP
+ Q_UNUSED(mimeData);
+#else
+ formatics.reserve(20);
+ const QStringList formats = QInternalMimeData::formatsHelper(mimeData);
+ for (int f = 0; f < formats.size(); ++f) {
+ for (int i = m_mimes.size() - 1; i >= 0; --i)
+ formatics += m_mimes.at(i)->formatsForMime(formats.at(f), mimeData);
+ }
+#endif //QT_NO_DRAGANDDROP
+ return formatics;
+}
+
+void QWindowsMimeConverter::ensureInitialized() const
+{
+ if (m_mimes.isEmpty()) {
+ m_mimes << new QWindowsMimeImage << new QLastResortMimes
+ << new QWindowsMimeText << new QWindowsMimeURI
+ << new QWindowsMimeHtml << new QBuiltInMimes;
+ }
+}
+
+QVariant QWindowsMimeConverter::convertToMime(const QStringList &mimeTypes,
+ IDataObject *pDataObj,
+ QVariant::Type preferredType,
+ QString *formatIn /* = 0 */) const
+{
+ foreach (const QString &format, mimeTypes) {
+ if (const QWindowsMime *converter = converterToMime(format, pDataObj)) {
+ if (converter->canConvertToMime(format, pDataObj)) {
+ const QVariant dataV = converter->convertToMime(format, pDataObj, preferredType);
+ if (dataV.isValid()) {
+ if (QWindowsContext::verboseOLE)
+ qDebug() << __FUNCTION__ << mimeTypes << "\nFormat: "
+ << format << pDataObj << " returns " << dataV;
+ if (formatIn)
+ *formatIn = format;
+ return dataV;
+ }
+ }
+ }
+ }
+ if (QWindowsContext::verboseOLE)
+ qDebug() << __FUNCTION__ << "fails" << mimeTypes << pDataObj << preferredType;
+ return QVariant();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsmime.h b/src/plugins/platforms/windows/qwindowsmime.h
new file mode 100644
index 0000000000..85f61a91e2
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsmime.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSMIME_H
+#define QWINDOWSMIME_H
+
+#include "qtwindows_additional.h"
+
+#include <QtCore/QVector>
+#include <QtCore/QList>
+#include <QtCore/QVariant>
+#include <QtCore/QSharedPointer>
+
+QT_BEGIN_NAMESPACE
+
+class QMimeData;
+
+class QWindowsMime
+{
+ Q_DISABLE_COPY(QWindowsMime)
+public:
+ QWindowsMime();
+ virtual ~QWindowsMime();
+
+ // for converting from Qt
+ virtual bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const = 0;
+ virtual bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const = 0;
+ virtual QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const = 0;
+
+ // for converting to Qt
+ virtual bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const = 0;
+ virtual QVariant convertToMime(const QString &mimeType, IDataObject *pDataObj, QVariant::Type preferredType) const = 0;
+ virtual QString mimeForFormat(const FORMATETC &formatetc) const = 0;
+
+ static int registerMimeType(const QString &mime);
+};
+
+class QWindowsMimeConverter
+{
+ Q_DISABLE_COPY(QWindowsMimeConverter)
+public:
+ QWindowsMimeConverter();
+ ~QWindowsMimeConverter();
+
+ QWindowsMime *converterToMime(const QString &mimeType, IDataObject *pDataObj) const;
+ QStringList allMimesForFormats(IDataObject *pDataObj) const;
+ QWindowsMime *converterFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const;
+ QVector<FORMATETC> allFormatsForMime(const QMimeData *mimeData) const;
+
+ // Convenience.
+ QVariant convertToMime(const QStringList &mimeTypes, IDataObject *pDataObj, QVariant::Type preferredType,
+ QString *format = 0) const;
+
+private:
+ typedef QSharedPointer<QWindowsMime> MimePtr;
+
+ void ensureInitialized() const;
+
+ mutable QList<QWindowsMime *> m_mimes;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSMIME_H
diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp
new file mode 100644
index 0000000000..dea965b439
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp
@@ -0,0 +1,288 @@
+/****************************************************************************
+**
+** 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 "qwindowsmousehandler.h"
+#include "qwindowscontext.h"
+#include "qwindowswindow.h"
+#include "qwindowsintegration.h"
+
+#include <QtGui/QWindowSystemInterface>
+#include <QtGui/QGuiApplication>
+#include <QtGui/QScreen>
+
+#include <QtCore/QDebug>
+#include <QtCore/QScopedArrayPointer>
+
+#include <windowsx.h>
+
+QT_BEGIN_NAMESPACE
+
+static inline void compressMouseMove(MSG *msg)
+{
+ // Compress mouse move events
+ if (msg->message == WM_MOUSEMOVE) {
+ MSG mouseMsg;
+ while (PeekMessage(&mouseMsg, msg->hwnd, WM_MOUSEFIRST,
+ WM_MOUSELAST, PM_NOREMOVE)) {
+ if (mouseMsg.message == WM_MOUSEMOVE) {
+#define PEEKMESSAGE_IS_BROKEN 1
+#ifdef PEEKMESSAGE_IS_BROKEN
+ // Since the Windows PeekMessage() function doesn't
+ // correctly return the wParam for WM_MOUSEMOVE events
+ // if there is a key release event in the queue
+ // _before_ the mouse event, we have to also consider
+ // key release events (kls 2003-05-13):
+ MSG keyMsg;
+ bool done = false;
+ while (PeekMessage(&keyMsg, 0, WM_KEYFIRST, WM_KEYLAST,
+ PM_NOREMOVE)) {
+ if (keyMsg.time < mouseMsg.time) {
+ if ((keyMsg.lParam & 0xC0000000) == 0x40000000) {
+ PeekMessage(&keyMsg, 0, keyMsg.message,
+ keyMsg.message, PM_REMOVE);
+ } else {
+ done = true;
+ break;
+ }
+ } else {
+ break; // no key event before the WM_MOUSEMOVE event
+ }
+ }
+ if (done)
+ break;
+#else
+ // Actually the following 'if' should work instead of
+ // the above key event checking, but apparently
+ // PeekMessage() is broken :-(
+ if (mouseMsg.wParam != msg.wParam)
+ break; // leave the message in the queue because
+ // the key state has changed
+#endif
+ // Update the passed in MSG structure with the
+ // most recent one.
+ msg->lParam = mouseMsg.lParam;
+ msg->wParam = mouseMsg.wParam;
+ // Extract the x,y coordinates from the lParam as we do in the WndProc
+ msg->pt.x = GET_X_LPARAM(mouseMsg.lParam);
+ msg->pt.y = GET_Y_LPARAM(mouseMsg.lParam);
+ ClientToScreen(msg->hwnd, &(msg->pt));
+ // Remove the mouse move message
+ PeekMessage(&mouseMsg, msg->hwnd, WM_MOUSEMOVE,
+ WM_MOUSEMOVE, PM_REMOVE);
+ } else {
+ break; // there was no more WM_MOUSEMOVE event
+ }
+ }
+ }
+}
+
+/*!
+ \class QWindowsMouseHandler
+ \brief Windows mouse handler
+
+ Dispatches mouse and touch events. Separate for code cleanliness.
+
+ \ingroup qt-lighthouse-win
+*/
+
+QWindowsMouseHandler::QWindowsMouseHandler() :
+ m_windowUnderMouse(0)
+{
+}
+
+bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
+ QtWindows::WindowsEventType et,
+ MSG msg, LRESULT *result)
+{
+ if (et & QtWindows::NonClientEventFlag)
+ return false;
+ if (et == QtWindows::MouseWheelEvent)
+ return translateMouseWheelEvent(window, hwnd, msg, result);
+ *result = 0;
+ if (msg.message == WM_MOUSELEAVE) {
+ // When moving out of a child, MouseMove within parent is received first
+ // (see below)
+ if (QWindowsContext::verboseEvents)
+ qDebug() << "WM_MOUSELEAVE for " << window << " current= " << m_windowUnderMouse;
+ if (window == m_windowUnderMouse) {
+ QWindowSystemInterface::handleLeaveEvent(window);
+ m_windowUnderMouse = 0;
+ }
+ return true;
+ }
+ compressMouseMove(&msg);
+ const QPoint client(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
+ // Enter new window: track to generate leave event.
+ if (m_windowUnderMouse != window) {
+ // The tracking on m_windowUnderMouse might still be active and
+ // trigger later on.
+ if (m_windowUnderMouse) {
+ if (QWindowsContext::verboseEvents)
+ qDebug() << "Synthetic leave for " << m_windowUnderMouse;
+ QWindowSystemInterface::handleLeaveEvent(m_windowUnderMouse);
+ }
+ m_windowUnderMouse = window;
+ if (QWindowsContext::verboseEvents)
+ qDebug() << "Entering " << window;
+ QWindowsWindow::baseWindowOf(window)->applyCursor();
+ QWindowSystemInterface::handleEnterEvent(window);
+ TRACKMOUSEEVENT tme;
+ tme.cbSize = sizeof(TRACKMOUSEEVENT);
+ tme.dwFlags = TME_LEAVE;
+ tme.hwndTrack = hwnd;
+ tme.dwHoverTime = HOVER_DEFAULT; //
+ if (!TrackMouseEvent(&tme))
+ qWarning("TrackMouseEvent failed.");
+ }
+ QWindowSystemInterface::handleMouseEvent(window, client,
+ QWindowsGeometryHint::mapToGlobal(hwnd, client),
+ keyStateToMouseButtons((int)msg.wParam));
+ return true;
+}
+
+bool QWindowsMouseHandler::translateMouseWheelEvent(QWindow *window, HWND,
+ MSG msg, LRESULT *)
+{
+ const Qt::MouseButtons buttons = keyStateToMouseButtons((int)msg.wParam);
+ int delta;
+ if (msg.message == WM_MOUSEWHEEL || msg.message == WM_MOUSEHWHEEL)
+ delta = (short) HIWORD (msg.wParam);
+ else
+ delta = (int) msg.wParam;
+
+ Qt::Orientation orientation = (msg.message == WM_MOUSEHWHEEL
+ || (buttons & Qt::AltModifier)) ?
+ Qt::Horizontal : Qt::Vertical;
+
+ // according to the MSDN documentation on WM_MOUSEHWHEEL:
+ // a positive value indicates that the wheel was rotated to the right;
+ // a negative value indicates that the wheel was rotated to the left.
+ // Qt defines this value as the exact opposite, so we have to flip the value!
+ if (msg.message == WM_MOUSEHWHEEL)
+ delta = -delta;
+
+ const QPoint globalPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
+ // TODO: if there is a widget under the mouse and it is not shadowed
+ // QWindow *receiver = windowAt(pos);
+ // by modality, we send the event to it first.
+ //synaptics touchpad shows its own widget at this position
+ //so widgetAt() will fail with that HWND, try child of this widget
+ // if (!receiver) receiver = window->childAt(pos);
+ QWindow *receiver = window;
+ QWindowSystemInterface::handleWheelEvent(receiver,
+ QWindowsGeometryHint::mapFromGlobal(receiver, globalPos),
+ globalPos,
+ delta, orientation);
+ return true;
+}
+
+// from bool QApplicationPrivate::translateTouchEvent()
+bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, HWND,
+ QtWindows::WindowsEventType,
+ MSG msg, LRESULT *)
+{
+ typedef QWindowSystemInterface::TouchPoint QTouchPoint;
+ typedef QList<QWindowSystemInterface::TouchPoint> QTouchPointList;
+
+ const QRect screenGeometry = window->screen()->geometry();
+
+ const int winTouchPointCount = msg.wParam;
+ QScopedArrayPointer<TOUCHINPUT> winTouchInputs(new TOUCHINPUT[winTouchPointCount]);
+ memset(winTouchInputs.data(), 0, sizeof(TOUCHINPUT) * winTouchPointCount);
+
+ QTouchPointList touchPoints;
+ touchPoints.reserve(winTouchPointCount);
+ Qt::TouchPointStates allStates = 0;
+
+ Q_ASSERT(QWindowsContext::user32dll.getTouchInputInfo);
+
+ QWindowsContext::user32dll.getTouchInputInfo((HANDLE) msg.lParam, msg.wParam, winTouchInputs.data(), sizeof(TOUCHINPUT));
+ for (int i = 0; i < winTouchPointCount; ++i) {
+ const TOUCHINPUT &winTouchInput = winTouchInputs[i];
+ QTouchPoint touchPoint;
+ touchPoint.pressure = 1.0;
+ touchPoint.isPrimary = (winTouchInput.dwFlags & TOUCHEVENTF_PRIMARY) != 0;
+ touchPoint.id = m_touchInputIDToTouchPointID.value(winTouchInput.dwID, -1);
+ if (touchPoint.id == -1) {
+ touchPoint.id = m_touchInputIDToTouchPointID.size();
+ m_touchInputIDToTouchPointID.insert(winTouchInput.dwID, touchPoint.id);
+ }
+
+ QPointF screenPos = QPointF(qreal(winTouchInput.x) / qreal(100.), qreal(winTouchInput.y) / qreal(100.));
+ if (winTouchInput.dwMask & TOUCHINPUTMASKF_CONTACTAREA)
+ touchPoint.area.setSize(QSizeF(qreal(winTouchInput.cxContact) / qreal(100.),
+ qreal(winTouchInput.cyContact) / qreal(100.)));
+ touchPoint.area.moveCenter(screenPos);
+
+ if (winTouchInput.dwFlags & TOUCHEVENTF_DOWN) {
+ touchPoint.state = Qt::TouchPointPressed;
+ } else if (winTouchInput.dwFlags & TOUCHEVENTF_UP) {
+ touchPoint.state = Qt::TouchPointReleased;
+ } else {
+ // TODO: Previous code checked"
+ // screenPos == touchPoint.normalPosition -> Qt::TouchPointStationary, but
+ // but touchPoint.normalPosition was never initialized?
+ touchPoint.state = touchPoint.state;
+ }
+
+ touchPoint.normalPosition = QPointF(screenPos.x() / screenGeometry.width(),
+ screenPos.y() / screenGeometry.height());
+
+ allStates |= touchPoint.state;
+
+ touchPoints.append(touchPoint);
+ }
+
+ QWindowsContext::user32dll.closeTouchInputHandle((HANDLE) msg.lParam);
+
+ // all touch points released, forget the ids we've seen, they may not be reused
+ if ((allStates & Qt::TouchPointStateMask) == Qt::TouchPointReleased)
+ m_touchInputIDToTouchPointID.clear();
+
+ // TODO: Device used to be hardcoded to screen in previous code.
+ // What is the correct event type? Which parts of translateRawTouchEvent() are required?
+ QWindowSystemInterface::handleTouchEvent(window, QEvent::TouchBegin,
+ QTouchEvent::TouchScreen,
+ touchPoints);
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.h b/src/plugins/platforms/windows/qwindowsmousehandler.h
new file mode 100644
index 0000000000..227a66babf
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsmousehandler.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSMOUSEHANDLER_H
+#define QWINDOWSMOUSEHANDLER_H
+
+#include "qtwindowsglobal.h"
+#include "qtwindows_additional.h"
+
+#include <QtCore/QPointer>
+#include <QtCore/QHash>
+
+QT_BEGIN_NAMESPACE
+
+class QWindow;
+
+class QWindowsMouseHandler
+{
+ Q_DISABLE_COPY(QWindowsMouseHandler)
+public:
+ QWindowsMouseHandler();
+
+ bool translateMouseEvent(QWindow *widget, HWND hwnd,
+ QtWindows::WindowsEventType t, MSG msg,
+ LRESULT *result);
+ bool translateTouchEvent(QWindow *widget, HWND hwnd,
+ QtWindows::WindowsEventType t, MSG msg,
+ LRESULT *result);
+
+ static inline Qt::MouseButtons keyStateToMouseButtons(int);
+
+ QWindow *windowUnderMouse() const { return m_windowUnderMouse.data(); }
+
+private:
+ inline bool translateMouseWheelEvent(QWindow *window, HWND hwnd,
+ MSG msg, LRESULT *result);
+
+ QPointer<QWindow> m_windowUnderMouse;
+ QHash<DWORD, int> m_touchInputIDToTouchPointID;
+};
+
+Qt::MouseButtons QWindowsMouseHandler::keyStateToMouseButtons(int wParam)
+{
+ Qt::MouseButtons mb(Qt::NoButton);
+ if (wParam & MK_LBUTTON)
+ mb |= Qt::LeftButton;
+ if (wParam & MK_MBUTTON)
+ mb |= Qt::MiddleButton;
+ if (wParam & MK_RBUTTON)
+ mb |= Qt::RightButton;
+ if (wParam & MK_XBUTTON1)
+ mb |= Qt::XButton1;
+ if (wParam & MK_XBUTTON2)
+ mb |= Qt::XButton2;
+ return mb;
+}
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSMOUSEHANDLER_H
diff --git a/src/plugins/platforms/windows/qwindowsnativeimage.cpp b/src/plugins/platforms/windows/qwindowsnativeimage.cpp
new file mode 100644
index 0000000000..53311c5fd7
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsnativeimage.cpp
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** 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 "qwindowsnativeimage.h"
+#include "qwindowscontext.h"
+
+#include <QtGui/QColorMap>
+#include <QtGui/private/qpaintengine_p.h>
+#include <QtGui/private/qpaintengine_raster_p.h>
+
+QT_BEGIN_NAMESPACE
+
+typedef struct {
+ BITMAPINFOHEADER bmiHeader;
+ DWORD redMask;
+ DWORD greenMask;
+ DWORD blueMask;
+} BITMAPINFO_MASK;
+
+/*!
+ \class QWindowsNativeImage
+ \brief Windows Native image
+
+ Note that size can be 0 (widget autotests with zero size), which
+ causes CreateDIBSection() to fail.
+
+ \sa QWindowsBackingStore
+ \ingroup qt-lighthouse-win
+*/
+
+static inline HDC createDC()
+{
+ HDC display_dc = GetDC(0);
+ HDC hdc = CreateCompatibleDC(display_dc);
+ ReleaseDC(0, display_dc);
+ Q_ASSERT(hdc);
+ return hdc;
+}
+
+static inline HBITMAP createDIB(HDC hdc, int width, int height,
+ QImage::Format format,
+ uchar **bitsIn)
+{
+ BITMAPINFO_MASK bmi;
+ memset(&bmi, 0, sizeof(bmi));
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = width;
+ bmi.bmiHeader.biHeight = -height; // top-down.
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biSizeImage = 0;
+
+ if (format == QImage::Format_RGB16) {
+ bmi.bmiHeader.biBitCount = 16;
+ bmi.bmiHeader.biCompression = BI_BITFIELDS;
+ bmi.redMask = 0xF800;
+ bmi.greenMask = 0x07E0;
+ bmi.blueMask = 0x001F;
+ } else {
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ bmi.redMask = 0;
+ bmi.greenMask = 0;
+ bmi.blueMask = 0;
+ }
+
+ void *bits = 0;
+ HBITMAP bitmap = CreateDIBSection(hdc, reinterpret_cast<BITMAPINFO *>(&bmi),
+ DIB_RGB_COLORS, &bits, 0, 0);
+ if (!bitmap || !bits)
+ qFatal("%s: CreateDIBSection failed.", __FUNCTION__);
+
+ *bitsIn = (uchar*)bits;
+ return bitmap;
+}
+
+QWindowsNativeImage::QWindowsNativeImage(int width, int height,
+ QImage::Format format) :
+ m_hdc(createDC()),
+ m_bitmap(0),
+ m_null_bitmap(0)
+{
+ if (width != 0 && height != 0) {
+ uchar *bits;
+ m_bitmap = createDIB(m_hdc, width, height, format, &bits);
+ m_null_bitmap = (HBITMAP)SelectObject(m_hdc, m_bitmap);
+ m_image = QImage(bits, width, height, format);
+ Q_ASSERT(m_image.paintEngine()->type() == QPaintEngine::Raster);
+ static_cast<QRasterPaintEngine *>(m_image.paintEngine())->setDC(m_hdc);
+ } else {
+ m_image = QImage(width, height, format);
+ }
+
+ GdiFlush();
+}
+
+QWindowsNativeImage::~QWindowsNativeImage()
+{
+ if (m_hdc) {
+ if (m_bitmap) {
+ if (m_null_bitmap)
+ SelectObject(m_hdc, m_null_bitmap);
+ DeleteObject(m_bitmap);
+ }
+ DeleteDC(m_hdc);
+ }
+}
+
+QImage::Format QWindowsNativeImage::systemFormat()
+{
+ static const int depth = QWindowsContext::instance()->screenDepth();
+ return depth == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsnativeimage.h b/src/plugins/platforms/windows/qwindowsnativeimage.h
new file mode 100644
index 0000000000..c77805a10a
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsnativeimage.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSNATIVEIMAGE_H
+#define QWINDOWSNATIVEIMAGE_H
+
+#include "qtwindows_additional.h"
+
+#include <QtGui/QImage>
+
+#include <QtCore/QtGlobal>
+
+QT_BEGIN_NAMESPACE
+
+class QWindowsNativeImage
+{
+ Q_DISABLE_COPY(QWindowsNativeImage)
+public:
+ QWindowsNativeImage(int width, int height,
+ QImage::Format format);
+
+ ~QWindowsNativeImage();
+
+ inline int width() const { return m_image.width(); }
+ inline int height() const { return m_image.height(); }
+
+ QImage &image() { return m_image; }
+ const QImage &image() const { return m_image; }
+
+ HDC hdc() const { return m_hdc; }
+
+ static QImage::Format systemFormat();
+
+private:
+ const HDC m_hdc;
+ QImage m_image;
+
+ HBITMAP m_bitmap;
+ HBITMAP m_null_bitmap;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSNATIVEIMAGE_H
diff --git a/src/plugins/platforms/windows/qwindowsole.cpp b/src/plugins/platforms/windows/qwindowsole.cpp
new file mode 100644
index 0000000000..864dc3dbb7
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsole.cpp
@@ -0,0 +1,476 @@
+/****************************************************************************
+**
+** 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 "qwindowsole.h"
+#include "qwindowsmime.h"
+#include "qwindowscontext.h"
+\
+#include <QtGui/QMouseEvent>
+#include <QtGui/QWindow>
+#include <QtGui/QPainter>
+#include <QtGui/QCursor>
+#include <QtGui/QGuiApplication>
+
+#include <QtCore/QMimeData>
+#include <QtCore/QDebug>
+
+#include <shlobj.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QWindowsOleDataObject
+ \brief OLE data container
+
+ The following methods are NOT supported for data transfer using the
+ clipboard or drag-drop:
+ \list
+ \o IDataObject::SetData -- return E_NOTIMPL
+ \o IDataObject::DAdvise -- return OLE_E_ADVISENOTSUPPORTED
+ \o ::DUnadvise
+ \o ::EnumDAdvise
+ \o IDataObject::GetCanonicalFormatEtc -- return E_NOTIMPL
+ (NOTE: must set pformatetcOut->ptd = NULL)
+ \endlist
+
+ \ingroup qt-lighthouse-win
+*/
+
+QWindowsOleDataObject::QWindowsOleDataObject(QMimeData *mimeData) :
+ m_refs(1), data(mimeData),
+ CF_PERFORMEDDROPEFFECT(RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT)),
+ performedEffect(DROPEFFECT_NONE)
+{
+ if (QWindowsContext::verboseOLE)
+ qDebug("%s '%s'", __FUNCTION__, qPrintable(mimeData->formats().join(QStringLiteral(", "))));
+}
+
+QWindowsOleDataObject::~QWindowsOleDataObject()
+{
+ if (QWindowsContext::verboseOLE)
+ qDebug("%s", __FUNCTION__);
+}
+
+void QWindowsOleDataObject::releaseQt()
+{
+ data = 0;
+}
+
+QMimeData *QWindowsOleDataObject::mimeData() const
+{
+ return data.data();
+}
+
+DWORD QWindowsOleDataObject::reportedPerformedEffect() const
+{
+ return performedEffect;
+}
+
+//---------------------------------------------------------------------
+// IUnknown Methods
+//---------------------------------------------------------------------
+
+STDMETHODIMP
+QWindowsOleDataObject::QueryInterface(REFIID iid, void FAR* FAR* ppv)
+{
+ if (iid == IID_IUnknown || iid == IID_IDataObject) {
+ *ppv = this;
+ AddRef();
+ return NOERROR;
+ }
+ *ppv = NULL;
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+STDMETHODIMP_(ULONG)
+QWindowsOleDataObject::AddRef(void)
+{
+ return ++m_refs;
+}
+
+STDMETHODIMP_(ULONG)
+QWindowsOleDataObject::Release(void)
+{
+ if (--m_refs == 0) {
+ releaseQt();
+ delete this;
+ return 0;
+ }
+ return m_refs;
+}
+
+STDMETHODIMP
+QWindowsOleDataObject::GetData(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium)
+{
+ HRESULT hr = ResultFromScode(DATA_E_FORMATETC);
+
+ if (QWindowsContext::verboseOLE) {
+ wchar_t buf[256] = {0};
+ GetClipboardFormatName(pformatetc->cfFormat, buf, 255);
+ qDebug("%s CF = %d : %s", __FUNCTION__, pformatetc->cfFormat, qPrintable(QString::fromWCharArray(buf)));
+ }
+
+ if (data) {
+ const QWindowsMimeConverter &mc = QWindowsContext::instance()->mimeConverter();
+ if (QWindowsMime *converter = mc.converterFromMime(*pformatetc, data))
+ if (converter->convertFromMime(*pformatetc, data, pmedium))
+ hr = ResultFromScode(S_OK);
+ }
+
+ if (QWindowsContext::verboseOLE) {
+ wchar_t buf[256] = {0};
+ GetClipboardFormatName(pformatetc->cfFormat, buf, 255);
+ qDebug("%s CF = %d : %s returns 0x%x", __FUNCTION__, pformatetc->cfFormat,
+ qPrintable(QString::fromWCharArray(buf)), int(hr));
+ }
+
+ return hr;
+}
+
+STDMETHODIMP
+QWindowsOleDataObject::GetDataHere(LPFORMATETC, LPSTGMEDIUM)
+{
+ return ResultFromScode(DATA_E_FORMATETC);
+}
+
+STDMETHODIMP
+QWindowsOleDataObject::QueryGetData(LPFORMATETC pformatetc)
+{
+ HRESULT hr = ResultFromScode(DATA_E_FORMATETC);
+
+ if (QWindowsContext::verboseOLE > 1)
+ qDebug("%s", __FUNCTION__);
+
+ if (data) {
+ const QWindowsMimeConverter &mc = QWindowsContext::instance()->mimeConverter();
+ hr = mc.converterFromMime(*pformatetc, data) ?
+ ResultFromScode(S_OK) : ResultFromScode(S_FALSE);
+ }
+ if (QWindowsContext::verboseOLE > 1)
+ qDebug("%s returns 0x%x", __FUNCTION__, int(hr));
+ return hr;
+}
+
+STDMETHODIMP
+QWindowsOleDataObject::GetCanonicalFormatEtc(LPFORMATETC, LPFORMATETC pformatetcOut)
+{
+ pformatetcOut->ptd = NULL;
+ return ResultFromScode(E_NOTIMPL);
+}
+
+STDMETHODIMP
+QWindowsOleDataObject::SetData(LPFORMATETC pFormatetc, STGMEDIUM *pMedium, BOOL fRelease)
+{
+ if (QWindowsContext::verboseOLE > 1)
+ qDebug("%s", __FUNCTION__);
+
+ HRESULT hr = ResultFromScode(E_NOTIMPL);
+
+ if (pFormatetc->cfFormat == CF_PERFORMEDDROPEFFECT && pMedium->tymed == TYMED_HGLOBAL) {
+ DWORD * val = (DWORD*)GlobalLock(pMedium->hGlobal);
+ performedEffect = *val;
+ GlobalUnlock(pMedium->hGlobal);
+ if (fRelease)
+ ReleaseStgMedium(pMedium);
+ hr = ResultFromScode(S_OK);
+ }
+ if (QWindowsContext::verboseOLE > 1)
+ qDebug("%s returns 0x%x", __FUNCTION__, int(hr));
+ return hr;
+}
+
+
+STDMETHODIMP
+QWindowsOleDataObject::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC FAR* ppenumFormatEtc)
+{
+ if (QWindowsContext::verboseOLE > 1)
+ qDebug("%s", __FUNCTION__);
+
+ if (!data)
+ return ResultFromScode(DATA_E_FORMATETC);
+
+ SCODE sc = S_OK;
+
+ QVector<FORMATETC> fmtetcs;
+ if (dwDirection == DATADIR_GET) {
+ QWindowsMimeConverter &mc = QWindowsContext::instance()->mimeConverter();
+ fmtetcs = mc.allFormatsForMime(data);
+ } else {
+ FORMATETC formatetc;
+ formatetc.cfFormat = CF_PERFORMEDDROPEFFECT;
+ formatetc.dwAspect = DVASPECT_CONTENT;
+ formatetc.lindex = -1;
+ formatetc.ptd = NULL;
+ formatetc.tymed = TYMED_HGLOBAL;
+ fmtetcs.append(formatetc);
+ }
+
+ QWindowsOleEnumFmtEtc *enumFmtEtc = new QWindowsOleEnumFmtEtc(fmtetcs);
+ *ppenumFormatEtc = enumFmtEtc;
+ if (enumFmtEtc->isNull()) {
+ delete enumFmtEtc;
+ *ppenumFormatEtc = NULL;
+ sc = E_OUTOFMEMORY;
+ }
+
+ return ResultFromScode(sc);
+}
+
+STDMETHODIMP
+QWindowsOleDataObject::DAdvise(FORMATETC FAR*, DWORD,
+ LPADVISESINK, DWORD FAR*)
+{
+ return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
+}
+
+
+STDMETHODIMP
+QWindowsOleDataObject::DUnadvise(DWORD)
+{
+ return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
+}
+
+STDMETHODIMP
+QWindowsOleDataObject::EnumDAdvise(LPENUMSTATDATA FAR*)
+{
+ return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
+}
+
+/*!
+ \class QWindowsOleEnumFmtEtc
+ \brief Enumerates the FORMATETC structures supported by QWindowsOleDataObject.
+ \ingroup qt-lighthouse-win
+*/
+
+QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QVector<FORMATETC> &fmtetcs) :
+ m_dwRefs(1), m_nIndex(0), m_isNull(false)
+{
+ if (QWindowsContext::verboseOLE > 1)
+ qDebug("%s", __FUNCTION__);
+ m_lpfmtetcs.reserve(fmtetcs.count());
+ for (int idx = 0; idx < fmtetcs.count(); ++idx) {
+ LPFORMATETC destetc = new FORMATETC();
+ if (copyFormatEtc(destetc, (LPFORMATETC)&(fmtetcs.at(idx)))) {
+ m_lpfmtetcs.append(destetc);
+ } else {
+ m_isNull = true;
+ delete destetc;
+ break;
+ }
+ }
+}
+
+QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QVector<LPFORMATETC> &lpfmtetcs) :
+ m_dwRefs(1), m_nIndex(0), m_isNull(false)
+{
+ if (QWindowsContext::verboseOLE > 1)
+ qDebug("%s", __FUNCTION__);
+ m_lpfmtetcs.reserve(lpfmtetcs.count());
+ for (int idx = 0; idx < lpfmtetcs.count(); ++idx) {
+ LPFORMATETC srcetc = lpfmtetcs.at(idx);
+ LPFORMATETC destetc = new FORMATETC();
+ if (copyFormatEtc(destetc, srcetc)) {
+ m_lpfmtetcs.append(destetc);
+ } else {
+ m_isNull = true;
+ delete destetc;
+ break;
+ }
+ }
+}
+
+QWindowsOleEnumFmtEtc::~QWindowsOleEnumFmtEtc()
+{
+ LPMALLOC pmalloc;
+
+ if (CoGetMalloc(MEMCTX_TASK, &pmalloc) == NOERROR) {
+ for (int idx = 0; idx < m_lpfmtetcs.count(); ++idx) {
+ LPFORMATETC tmpetc = m_lpfmtetcs.at(idx);
+ if (tmpetc->ptd)
+ pmalloc->Free(tmpetc->ptd);
+ delete tmpetc;
+ }
+
+ pmalloc->Release();
+ }
+ m_lpfmtetcs.clear();
+}
+
+bool QWindowsOleEnumFmtEtc::isNull() const
+{
+ return m_isNull;
+}
+
+// IUnknown methods
+STDMETHODIMP
+QWindowsOleEnumFmtEtc::QueryInterface(REFIID riid, void FAR* FAR* ppvObj)
+{
+ if (riid == IID_IUnknown || riid == IID_IEnumFORMATETC) {
+ *ppvObj = this;
+ AddRef();
+ return NOERROR;
+ }
+ *ppvObj = NULL;
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+STDMETHODIMP_(ULONG)
+QWindowsOleEnumFmtEtc::AddRef(void)
+{
+ return ++m_dwRefs;
+}
+
+STDMETHODIMP_(ULONG)
+QWindowsOleEnumFmtEtc::Release(void)
+{
+ if (--m_dwRefs == 0) {
+ delete this;
+ return 0;
+ }
+ return m_dwRefs;
+}
+
+// IEnumFORMATETC methods
+STDMETHODIMP
+QWindowsOleEnumFmtEtc::Next(ULONG celt, LPFORMATETC rgelt, ULONG FAR* pceltFetched)
+{
+ ULONG i=0;
+ ULONG nOffset;
+
+ if (rgelt == NULL)
+ return ResultFromScode(E_INVALIDARG);
+
+ while (i < celt) {
+ nOffset = m_nIndex + i;
+
+ if (nOffset < ULONG(m_lpfmtetcs.count())) {
+ copyFormatEtc((LPFORMATETC)&(rgelt[i]), m_lpfmtetcs.at(nOffset));
+ i++;
+ } else {
+ break;
+ }
+ }
+
+ m_nIndex += (WORD)i;
+
+ if (pceltFetched != NULL)
+ *pceltFetched = i;
+
+ if (i != celt)
+ return ResultFromScode(S_FALSE);
+
+ return NOERROR;
+}
+
+STDMETHODIMP
+QWindowsOleEnumFmtEtc::Skip(ULONG celt)
+{
+ ULONG i=0;
+ ULONG nOffset;
+
+ while (i < celt) {
+ nOffset = m_nIndex + i;
+
+ if (nOffset < ULONG(m_lpfmtetcs.count())) {
+ i++;
+ } else {
+ break;
+ }
+ }
+
+ m_nIndex += (WORD)i;
+
+ if (i != celt)
+ return ResultFromScode(S_FALSE);
+
+ return NOERROR;
+}
+
+STDMETHODIMP
+QWindowsOleEnumFmtEtc::Reset()
+{
+ m_nIndex = 0;
+ return NOERROR;
+}
+
+STDMETHODIMP
+QWindowsOleEnumFmtEtc::Clone(LPENUMFORMATETC FAR* newEnum)
+{
+ if (newEnum == NULL)
+ return ResultFromScode(E_INVALIDARG);
+
+ QWindowsOleEnumFmtEtc *result = new QWindowsOleEnumFmtEtc(m_lpfmtetcs);
+ result->m_nIndex = m_nIndex;
+
+ if (result->isNull()) {
+ delete result;
+ return ResultFromScode(E_OUTOFMEMORY);
+ } else {
+ *newEnum = result;
+ }
+
+ return NOERROR;
+}
+
+bool QWindowsOleEnumFmtEtc::copyFormatEtc(LPFORMATETC dest, LPFORMATETC src) const
+{
+ if (dest == NULL || src == NULL)
+ return false;
+
+ *dest = *src;
+
+ if (src->ptd) {
+ LPVOID pout;
+ LPMALLOC pmalloc;
+
+ if (CoGetMalloc(MEMCTX_TASK, &pmalloc) != NOERROR)
+ return false;
+
+ pout = (LPVOID)pmalloc->Alloc(src->ptd->tdSize);
+ memcpy(dest->ptd, src->ptd, size_t(src->ptd->tdSize));
+
+ pmalloc->Release();
+ }
+
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsole.h b/src/plugins/platforms/windows/qwindowsole.h
new file mode 100644
index 0000000000..d979af3b31
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsole.h
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSOLE_H
+#define QWINDOWSOLE_H
+
+#include "qtwindows_additional.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QMap>
+#include <QtCore/QPoint>
+#include <QtCore/QPointer>
+#include <QtCore/QVector>
+#include <QtCore/QRect>
+
+#include <objidl.h>
+
+QT_BEGIN_NAMESPACE
+
+class QMimeData;
+class QWindow;
+
+class QWindowsOleDataObject : public IDataObject
+{
+public:
+ explicit QWindowsOleDataObject(QMimeData *mimeData);
+ virtual ~QWindowsOleDataObject();
+
+ void releaseQt();
+ QMimeData *mimeData() const;
+ DWORD reportedPerformedEffect() const;
+
+ // IUnknown methods
+ STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppvObj);
+ STDMETHOD_(ULONG,AddRef)(void);
+ STDMETHOD_(ULONG,Release)(void);
+
+ // IDataObject methods
+ STDMETHOD(GetData)(LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium);
+ STDMETHOD(GetDataHere)(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium);
+ STDMETHOD(QueryGetData)(LPFORMATETC pformatetc);
+ STDMETHOD(GetCanonicalFormatEtc)(LPFORMATETC pformatetc, LPFORMATETC pformatetcOut);
+ STDMETHOD(SetData)(LPFORMATETC pformatetc, STGMEDIUM FAR * pmedium,
+ BOOL fRelease);
+ STDMETHOD(EnumFormatEtc)(DWORD dwDirection, LPENUMFORMATETC FAR* ppenumFormatEtc);
+ STDMETHOD(DAdvise)(FORMATETC FAR* pFormatetc, DWORD advf,
+ LPADVISESINK pAdvSink, DWORD FAR* pdwConnection);
+ STDMETHOD(DUnadvise)(DWORD dwConnection);
+ STDMETHOD(EnumDAdvise)(LPENUMSTATDATA FAR* ppenumAdvise);
+
+private:
+ ULONG m_refs;
+ QPointer<QMimeData> data;
+ int CF_PERFORMEDDROPEFFECT;
+ DWORD performedEffect;
+};
+
+class QWindowsOleEnumFmtEtc : public IEnumFORMATETC
+{
+public:
+ explicit QWindowsOleEnumFmtEtc(const QVector<FORMATETC> &fmtetcs);
+ explicit QWindowsOleEnumFmtEtc(const QVector<LPFORMATETC> &lpfmtetcs);
+ virtual ~QWindowsOleEnumFmtEtc();
+
+ bool isNull() const;
+
+ // IUnknown methods
+ STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppvObj);
+ STDMETHOD_(ULONG,AddRef)(void);
+ STDMETHOD_(ULONG,Release)(void);
+
+ // IEnumFORMATETC methods
+ STDMETHOD(Next)(ULONG celt, LPFORMATETC rgelt, ULONG FAR* pceltFetched);
+ STDMETHOD(Skip)(ULONG celt);
+ STDMETHOD(Reset)(void);
+ STDMETHOD(Clone)(LPENUMFORMATETC FAR* newEnum);
+
+private:
+ bool copyFormatEtc(LPFORMATETC dest, LPFORMATETC src) const;
+
+ ULONG m_dwRefs;
+ ULONG m_nIndex;
+ QVector<LPFORMATETC> m_lpfmtetcs;
+ bool m_isNull;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSOLE_H
diff --git a/src/plugins/platforms/windows/qwindowsprintersupport.cpp b/src/plugins/platforms/windows/qwindowsprintersupport.cpp
new file mode 100644
index 0000000000..3d43c61e10
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsprintersupport.cpp
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** 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 "qwindowsprintersupport.h"
+
+#ifdef HAS_PRINTENGINE
+# include <qprintengine_win_p.h>
+#endif
+
+#include <QtGui/QPrinterInfo>
+
+#include <QtCore/QStringList>
+#include <QtCore/qt_windows.h>
+
+QT_BEGIN_NAMESPACE
+
+QPrintEngine *QWindowsPrinterSupport::createNativePrintEngine(QPrinter::PrinterMode mode)
+{
+#ifdef HAS_PRINTENGINE
+ return new QWin32PrintEngine(mode);
+#else
+ Q_UNUSED(mode);
+ Q_UNIMPLEMENTED();
+ return 0;
+#endif
+}
+
+QPaintEngine *QWindowsPrinterSupport::createPaintEngine(QPrintEngine *engine, QPrinter::PrinterMode)
+{
+#ifdef HAS_PRINTENGINE
+ return static_cast<QWin32PrintEngine *>(engine);
+#else
+ Q_UNIMPLEMENTED();
+ Q_UNUSED(engine);
+ return 0;
+#endif
+}
+
+QList<QPrinter::PaperSize> QWindowsPrinterSupport::supportedPaperSizes(const QPrinterInfo &printerInfo) const
+{
+ QList<QPrinter::PaperSize> paperSizes;
+ const QString printerName = printerInfo.printerName();
+ const wchar_t *nameUtf16 = reinterpret_cast<const wchar_t*>(printerName.utf16());
+ DWORD size = DeviceCapabilities(nameUtf16, NULL, DC_PAPERS, NULL, NULL);
+ if ((int)size != -1) {
+ wchar_t *papers = new wchar_t[size];
+ size = DeviceCapabilities(nameUtf16, NULL, DC_PAPERS, papers, NULL);
+#ifdef HAS_PRINTENGINE
+ for (int c = 0; c < (int)size; ++c)
+ paperSizes.append(mapDevmodePaperSize(papers[c]));
+#endif
+ delete [] papers;
+ }
+ return paperSizes;
+}
+
+QList<QPrinterInfo> QWindowsPrinterSupport::availablePrinters()
+{
+ QList<QPrinterInfo> printers;
+
+ DWORD needed = 0;
+ DWORD returned = 0;
+ if (!EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 4, 0, 0, &needed, &returned)) {
+ LPBYTE buffer = new BYTE[needed];
+ if (EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 4, buffer, needed, &needed, &returned)) {
+ PPRINTER_INFO_4 infoList = reinterpret_cast<PPRINTER_INFO_4>(buffer);
+ QPrinterInfo defPrn = defaultPrinter();
+ for (uint i = 0; i < returned; ++i) {
+ const QString printerName(QString::fromWCharArray(infoList[i].pPrinterName));
+ const bool isDefault = printerName == defPrn.printerName();
+ printers.append(QPlatformPrinterSupport::printerInfo(printerName,
+ isDefault));
+ }
+ }
+ delete [] buffer;
+ }
+
+ return printers;
+}
+
+QPrinterInfo QWindowsPrinterSupport::defaultPrinter()
+{
+ QString noPrinters(QStringLiteral("qt_no_printers"));
+ wchar_t buffer[256];
+ GetProfileString(L"windows", L"device", (wchar_t*)noPrinters.utf16(), buffer, 256);
+ QString output = QString::fromWCharArray(buffer);
+ if (output != noPrinters) {
+ // Filter out the name of the printer, which should be everything before a comma.
+ const QString printerName = output.split(QLatin1Char(',')).value(0);
+ return QPlatformPrinterSupport::printerInfo(printerName, true);
+ }
+
+ return QPrinterInfo();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsprintersupport.h b/src/plugins/platforms/windows/qwindowsprintersupport.h
new file mode 100644
index 0000000000..c0a8190599
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsprintersupport.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSPRINTERSUPPORT_H
+#define QWINDOWSPRINTERSUPPORT_H
+
+#include <QtGui/QPlatformPrinterSupport>
+
+QT_BEGIN_NAMESPACE
+
+class QWindowsPrinterSupport : public QPlatformPrinterSupport
+{
+public:
+ virtual QPrintEngine *createNativePrintEngine(QPrinter::PrinterMode);
+ virtual QPaintEngine *createPaintEngine(QPrintEngine *, QPrinter::PrinterMode);
+
+ virtual QList<QPrinter::PaperSize> supportedPaperSizes(const QPrinterInfo &) const;
+ virtual QPrinterInfo defaultPrinter();
+ virtual QList<QPrinterInfo> availablePrinters();
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSPRINTERSUPPORT_H
diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp
new file mode 100644
index 0000000000..3de508a1c7
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsscreen.cpp
@@ -0,0 +1,230 @@
+/****************************************************************************
+**
+** 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 "qwindowsscreen.h"
+#include "qwindowscontext.h"
+#include "qwindowswindow.h"
+#include "pixmaputils.h"
+#include "qwindowscursor.h"
+
+#include "qtwindows_additional.h"
+
+#include <QtGui/QPixmap>
+#include <QtGui/QGuiApplication>
+#include <QtGui/QScreen>
+
+#include <QtCore/QDebug>
+
+QT_BEGIN_NAMESPACE
+
+typedef QPair<int, int> DPI;
+
+QWindowsScreenData::QWindowsScreenData() :
+ dpi(96, 96),
+ depth(32),
+ format(QImage::Format_ARGB32_Premultiplied), primary(false)
+{
+}
+
+static inline DPI deviceDPI(HDC hdc)
+{
+ return DPI(GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY));
+}
+
+static inline QSize deviceSizeMM(const QSize &pixels, const DPI &dpi)
+{
+ const qreal inchToMM = 25.4;
+ const qreal h = qreal(pixels.width()) / qreal(dpi.first) * inchToMM;
+ const qreal v = qreal(pixels.height()) / qreal(dpi.second) * inchToMM;
+ return QSize(qRound(h), qRound(v));
+}
+
+static inline DPI deviceDPI(const QSize &pixels, const QSize &physicalSizeMM)
+{
+ const qreal inchToMM = 25.4;
+ const qreal h = qreal(pixels.width()) / (qreal(physicalSizeMM.width()) / inchToMM);
+ const qreal v = qreal(pixels.height()) / (qreal(physicalSizeMM.height()) / inchToMM);
+ return DPI(qRound(v), qRound(h));
+}
+
+typedef QList<QWindowsScreenData> WindowsScreenDataList;
+
+// from QDesktopWidget, taking WindowsScreenDataList as LPARAM
+BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM p)
+{
+ MONITORINFOEX info;
+ memset(&info, 0, sizeof(MONITORINFOEX));
+ info.cbSize = sizeof(MONITORINFOEX);
+ if (GetMonitorInfo(hMonitor, &info) == FALSE)
+ return TRUE;
+
+ WindowsScreenDataList *result = reinterpret_cast<WindowsScreenDataList *>(p);
+ QWindowsScreenData data;
+ data.geometry = QRect(QPoint(info.rcMonitor.left, info.rcMonitor.top), QPoint(info.rcMonitor.right - 1, info.rcMonitor.bottom - 1));
+ if (HDC hdc = CreateDC(info.szDevice, NULL, NULL, NULL)) {
+ data.dpi = deviceDPI(hdc);
+ DeleteDC(hdc);
+ } else {
+ qWarning("%s: Unable to obtain handle for monitor '%s', defaulting to %d DPI.",
+ __FUNCTION__, qPrintable(QString::fromWCharArray(info.szDevice)),
+ data.dpi.first);
+ }
+ data.physicalSizeMM = deviceSizeMM(data.geometry.size(), data.dpi);
+ data.geometry = QRect(QPoint(info.rcMonitor.left, info.rcMonitor.top), QPoint(info.rcMonitor.right - 1, info.rcMonitor.bottom - 1));
+ data.availableGeometry = QRect(QPoint(info.rcWork.left, info.rcWork.top), QPoint(info.rcWork.right - 1, info.rcWork.bottom - 1));
+ data.primary = (info.dwFlags & MONITORINFOF_PRIMARY) != 0;
+ result->append(data);
+ return TRUE;
+}
+
+/*!
+ \class QWindowsScreen
+ \brief Windows screen.
+ \ingroup qt-lighthouse-win
+*/
+
+QWindowsScreen::QWindowsScreen(const QWindowsScreenData &data) :
+ m_data(data), m_cursor(this)
+{
+}
+
+QList<QPlatformScreen *> QWindowsScreen::screens()
+{
+ // Retrieve monitors and add static depth information to each.
+ WindowsScreenDataList data;
+ EnumDisplayMonitors(0, 0, monitorEnumCallback, (LPARAM)&data);
+
+ const int depth = QWindowsContext::instance()->screenDepth();
+ const QImage::Format format = depth == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32;
+ QList<QPlatformScreen *> result;
+
+ const WindowsScreenDataList::const_iterator scend = data.constEnd();
+ for (WindowsScreenDataList::const_iterator it = data.constBegin(); it != scend; ++it) {
+ QWindowsScreenData d = *it;
+ d.depth = depth;
+ d.format = format;
+ if (QWindowsContext::verboseIntegration)
+ qDebug() << "Screen" << d.geometry << d.availableGeometry << d.primary
+ << " physical " << d.physicalSizeMM << " DPI" << d.dpi
+ << "Depth: " << d.depth << " Format: " << d.format;
+ result.append(new QWindowsScreen(d));
+ }
+ return result;
+}
+
+QPixmap QWindowsScreen::grabWindow(WId window, int x, int y, int width, int height) const
+{
+ if (QWindowsContext::verboseIntegration)
+ qDebug() << __FUNCTION__ << window << x << y << width << height;
+ RECT r;
+ HWND hwnd = (HWND)window;
+ GetClientRect(hwnd, &r);
+
+ if (width < 0) width = r.right - r.left;
+ if (height < 0) height = r.bottom - r.top;
+
+ // Create and setup bitmap
+ HDC display_dc = GetDC(0);
+ HDC bitmap_dc = CreateCompatibleDC(display_dc);
+ HBITMAP bitmap = CreateCompatibleBitmap(display_dc, width, height);
+ HGDIOBJ null_bitmap = SelectObject(bitmap_dc, bitmap);
+
+ // copy data
+ HDC window_dc = GetDC(hwnd);
+ BitBlt(bitmap_dc, 0, 0, width, height, window_dc, x, y, SRCCOPY | CAPTUREBLT);
+
+ // clean up all but bitmap
+ ReleaseDC(hwnd, window_dc);
+ SelectObject(bitmap_dc, null_bitmap);
+ DeleteDC(bitmap_dc);
+
+ const QPixmap pixmap = qPixmapFromWinHBITMAP(bitmap, HBitmapNoAlpha);
+
+ DeleteObject(bitmap);
+ ReleaseDC(0, display_dc);
+
+ return pixmap;
+}
+
+/*!
+ \brief Find a top level window taking the flags of ChildWindowFromPointEx.
+*/
+
+QWindow *QWindowsScreen::findTopLevelAt(const QPoint &point, unsigned flags)
+{
+ QWindow* result = 0;
+ if (QPlatformWindow *bw = QWindowsContext::instance()->
+ findPlatformWindowAt(GetDesktopWindow(), point, flags))
+ result = QWindowsWindow::topLevelOf(bw->window());
+ if (QWindowsContext::verboseWindows)
+ qDebug() << __FUNCTION__ << point << flags << result;
+ return result;
+}
+
+QWindow *QWindowsScreen::windowAt(const QPoint &screenPoint, unsigned flags)
+{
+ QWindow* result = 0;
+ if (QPlatformWindow *bw = QWindowsContext::instance()->
+ findPlatformWindowAt(GetDesktopWindow(), screenPoint, flags))
+ result = bw->window();
+ if (QWindowsContext::verboseWindows)
+ qDebug() << __FUNCTION__ << screenPoint << " returns " << result;
+ return result;
+}
+
+QWindow *QWindowsScreen::windowUnderMouse(unsigned flags)
+{
+ return QWindowsScreen::windowAt(QWindowsCursor::mousePosition(), flags);
+}
+
+QWindowsScreen *QWindowsScreen::screenOf(const QWindow *w)
+{
+ if (w)
+ if (const QScreen *s = w->screen())
+ if (QPlatformScreen *pscr = s->handle())
+ return static_cast<QWindowsScreen *>(pscr);
+ if (const QScreen *ps = QGuiApplication::primaryScreen())
+ if (QPlatformScreen *ppscr = ps->handle())
+ return static_cast<QWindowsScreen *>(ppscr);
+ return 0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h
new file mode 100644
index 0000000000..e24af7af09
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsscreen.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSSCREEN_H
+#define QWINDOWSSCREEN_H
+
+#include "qwindowscursor.h"
+
+#include <QtCore/QList>
+#include <QtCore/QPair>
+#include <QtGui/QPlatformScreen>
+
+QT_BEGIN_NAMESPACE
+
+struct QWindowsScreenData
+{
+ QWindowsScreenData();
+
+ QRect geometry;
+ QRect availableGeometry;
+ QPair<int, int> dpi;
+ QSize physicalSizeMM;
+ int depth;
+ QImage::Format format;
+ bool primary;
+};
+
+class QWindowsScreen : public QPlatformScreen
+{
+public:
+ explicit QWindowsScreen(const QWindowsScreenData &data);
+
+ static QWindowsScreen *screenOf(const QWindow *w = 0);
+
+ virtual QRect geometry() const { return m_data.geometry; }
+ virtual QRect availableGeometry() const { return m_data.availableGeometry; }
+ virtual int depth() const { return m_data.depth; }
+ virtual QImage::Format format() const { return m_data.format; }
+ virtual QSize physicalSize() const { return m_data.physicalSizeMM; }
+
+ virtual QWindow *topLevelAt(const QPoint &point) const
+ { return QWindowsScreen::findTopLevelAt(point, CWP_SKIPINVISIBLE); }
+
+ static QWindow *findTopLevelAt(const QPoint &point, unsigned flags);
+ static QWindow *windowAt(const QPoint &point, unsigned flags = CWP_SKIPINVISIBLE);
+ static QWindow *windowUnderMouse(unsigned flags = CWP_SKIPINVISIBLE);
+
+ static QList<QPlatformScreen *> screens();
+
+ virtual QPixmap grabWindow(WId window, int x, int y, int width, int height) const;
+
+ const QWindowsCursor &cursor() const { return m_cursor; }
+ QWindowsCursor &cursor() { return m_cursor; }
+
+private:
+ const QWindowsScreenData m_data;
+ QWindowsCursor m_cursor;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSSCREEN_H
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
new file mode 100644
index 0000000000..95b770f043
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -0,0 +1,1317 @@
+/****************************************************************************
+**
+** 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 "qwindowswindow.h"
+#include "qwindowsnativeimage.h"
+#include "qwindowscontext.h"
+#include "qwindowsdrag.h"
+#include "qwindowsscreen.h"
+#include "qwindowscursor.h"
+
+#include <QtGui/QGuiApplication>
+#include <QtGui/QScreen>
+#include <QtGui/QWindow>
+#include <QtGui/QWindowSystemInterface>
+
+#include <QtCore/QDebug>
+
+QT_BEGIN_NAMESPACE
+
+static QByteArray debugWinStyle(DWORD style)
+{
+
+ QByteArray rc = "0x";
+ rc += QByteArray::number(qulonglong(style), 16);
+ if (style & WS_POPUP)
+ rc += " WS_POPUP";
+ if (style & WS_CHILD)
+ rc += " WS_CHILD";
+ if (style & WS_OVERLAPPED)
+ rc += " WS_OVERLAPPED";
+ if (style & WS_CLIPSIBLINGS)
+ rc += " WS_CLIPSIBLINGS";
+ if (style & WS_CLIPCHILDREN)
+ rc += " WS_CLIPCHILDREN";
+ if (style & WS_THICKFRAME)
+ rc += " WS_THICKFRAME";
+ if (style & WS_DLGFRAME)
+ rc += " WS_DLGFRAME";
+ if (style & WS_SYSMENU)
+ rc += " WS_SYSMENU";
+ if (style & WS_MINIMIZEBOX)
+ rc += " WS_MINIMIZEBOX";
+ if (style & WS_MAXIMIZEBOX)
+ rc += " WS_MAXIMIZEBOX";
+ return rc;
+}
+
+static QByteArray debugWindowStates(Qt::WindowStates s)
+{
+
+ QByteArray rc = "0x";
+ rc += QByteArray::number(int(s), 16);
+ if (s & Qt::WindowMinimized)
+ rc += " WindowMinimized";
+ if (s & Qt::WindowMaximized)
+ rc += " WindowMaximized";
+ if (s & Qt::WindowFullScreen)
+ rc += " WindowFullScreen";
+ if (s & Qt::WindowActive)
+ rc += " WindowActive";
+ return rc;
+}
+
+QDebug operator<<(QDebug d, const MINMAXINFO &i)
+{
+ d.nospace() << "MINMAXINFO maxSize=" << i.ptMaxSize.x << ','
+ << i.ptMaxSize.y << " maxpos=" << i.ptMaxPosition.x
+ << ',' << i.ptMaxPosition.y << " mintrack="
+ << i.ptMinTrackSize.x << ',' << i.ptMinTrackSize.y
+ << " maxtrack=" << i.ptMaxTrackSize.x << ','
+ << i.ptMaxTrackSize.y;
+ return d;
+}
+
+static inline QSize qSizeOfRect(const RECT &rect)
+{
+ return QSize(rect.right -rect.left, rect.bottom - rect.top);
+}
+
+static inline QRect qrectFromRECT(const RECT &rect)
+{
+ return QRect(QPoint(rect.left, rect.top), qSizeOfRect(rect));
+}
+
+QDebug operator<<(QDebug d, const RECT &r)
+{
+ d.nospace() << "RECT: left/top=" << r.left << ',' << r.top
+ << " right/bottom=" << r.right << ',' << r.bottom;
+ return d;
+}
+
+QDebug operator<<(QDebug d, const NCCALCSIZE_PARAMS &p)
+{
+ qDebug().nospace() << "NCCALCSIZE_PARAMS "
+ << qrectFromRECT(p.rgrc[0])
+ << ' ' << qrectFromRECT(p.rgrc[1]) << ' '
+ << qrectFromRECT(p.rgrc[2]);
+ return d;
+}
+
+static inline QRect frameGeometry(HWND hwnd)
+{
+ RECT rect = { 0, 0, 0, 0 };
+ GetWindowRect(hwnd, &rect);
+ return qrectFromRECT(rect);
+}
+
+QSize clientSize(HWND hwnd)
+{
+ RECT rect = { 0, 0, 0, 0 };
+ GetClientRect(hwnd, &rect); // Always returns point 0,0, thus unusable for geometry.
+ return qSizeOfRect(rect);
+}
+
+// from qwidget_win.cpp/maximum layout size check removed.
+static bool shouldShowMaximizeButton(Qt::WindowFlags flags)
+{
+ if (flags & Qt::MSWindowsFixedSizeDialogHint)
+ return false;
+ // if the user explicitly asked for the maximize button, we try to add
+ // it even if the window has fixed size.
+ if (flags & Qt::CustomizeWindowHint &&
+ flags & Qt::WindowMaximizeButtonHint)
+ return true;
+ return flags & Qt::WindowMaximizeButtonHint;
+}
+
+/*!
+ \class WindowCreationData
+ \brief Window creation code.
+
+ This struct gathers all information required to create a window.
+ Window creation is split in 3 steps:
+
+ \list
+ \o fromWindow() Gather all required information
+ \o create() Create the system handle.
+ \o initialize() Post creation initialization steps.
+ \endlist
+
+ The reason for this split is to also enable changing the QWindowFlags
+ by calling:
+
+ \list
+ \o fromWindow() Gather information and determine new system styles
+ \o applyWindowFlags() to apply the new window system styles.
+ \o initialize() Post creation initialization steps.
+ \endlist
+
+ Contains the window creation code formerly in qwidget_win.cpp.
+
+ \sa QWindowCreationContext
+ \ingroup qt-lighthouse-win
+*/
+
+struct WindowCreationData
+{
+ typedef QWindowsWindow::WindowData WindowData;
+
+ WindowCreationData() : parentHandle(0), type(Qt::Widget), style(0), exStyle(0),
+ topLevel(false), popup(false), dialog(false), desktop(false),
+ tool(false) {}
+
+ void fromWindow(const QWindow *w, const Qt::WindowFlags flags, bool isGL);
+ inline WindowData create(const QWindow *w, const QRect &geometry, QString title) const;
+ inline void applyWindowFlags(HWND hwnd) const;
+ void initialize(HWND h, bool frameChange) const;
+
+ Qt::WindowFlags flags;
+ HWND parentHandle;
+ Qt::WindowType type;
+ unsigned style;
+ unsigned exStyle;
+ bool isGL;
+ bool topLevel;
+ bool popup;
+ bool dialog;
+ bool desktop;
+ bool tool;
+};
+
+QDebug operator<<(QDebug debug, const WindowCreationData &d)
+{
+ debug.nospace() << QWindowsWindow::debugWindowFlags(d.flags)
+ << " gs=" << d.isGL << " topLevel=" << d.topLevel << " popup="
+ << d.popup << " dialog=" << d.dialog << " desktop=" << d.desktop
+ << " tool=" << d.tool << " style=" << debugWinStyle(d.style)
+ << " exStyle=0x" << QString::number(d.exStyle, 16)
+ << " parent=" << d.parentHandle;
+ return debug;
+}
+
+void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flagsIn,
+ bool isGLin)
+{
+ isGL = isGLin;
+ flags = flagsIn;
+ topLevel = w->isTopLevel();
+
+ if (topLevel && flags == 1) {
+ qWarning("Remove me: fixing toplevel window flags");
+ flags |= Qt::WindowTitleHint|Qt::WindowSystemMenuHint|Qt::WindowMinimizeButtonHint
+ |Qt::WindowMaximizeButtonHint|Qt::WindowCloseButtonHint;
+ }
+
+ type = static_cast<Qt::WindowType>(int(flags) & Qt::WindowType_Mask);
+ switch (type) {
+ case Qt::Dialog:
+ case Qt::Sheet:
+ dialog = true;
+ break;
+ case Qt::Drawer:
+ case Qt::Tool:
+ tool = true;
+ break;
+ case Qt::Popup:
+ popup = true;
+ break;
+ case Qt::Desktop:
+ desktop = true;
+ break;
+ default:
+ break;
+ }
+ if ((flags & Qt::MSWindowsFixedSizeDialogHint))
+ dialog = true;
+
+ // Parent: Use transient parent for top levels.
+ if (popup) {
+ flags |= Qt::WindowStaysOnTopHint; // a popup stays on top, no parent.
+ } else {
+ if (const QWindow *parentWindow = topLevel ? w->transientParent() : w->parent())
+ parentHandle = QWindowsWindow::handleOf(parentWindow);
+ }
+
+ if (popup || (type == Qt::ToolTip) || (type == Qt::SplashScreen)) {
+ style = WS_POPUP;
+ } else if (topLevel && !desktop) {
+ if (flags & Qt::FramelessWindowHint)
+ style = WS_POPUP; // no border
+ else if (flags & Qt::WindowTitleHint)
+ style = WS_OVERLAPPED;
+ else
+ style = 0;
+ } else {
+ style = WS_CHILD;
+ }
+
+ if (!desktop) {
+ // if (!testAttribute(Qt::WA_PaintUnclipped))
+ // ### Commented out for now as it causes some problems, but
+ // this should be correct anyway, so dig some more into this
+#ifdef Q_FLATTEN_EXPOSE
+ if (isGL)
+ style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN; // see SetPixelFormat
+#else
+ style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN ;
+#endif
+ if (topLevel) {
+ if ((type == Qt::Window || dialog || tool)) {
+ if (!(flags & Qt::FramelessWindowHint)) {
+ style |= WS_POPUP;
+ if (flags & Qt::MSWindowsFixedSizeDialogHint) {
+ style |= WS_DLGFRAME;
+ } else {
+ style |= WS_THICKFRAME;
+ }
+ }
+ if (flags & Qt::WindowTitleHint)
+ style |= WS_CAPTION;
+ if (flags & Qt::WindowSystemMenuHint)
+ style |= WS_SYSMENU;
+ if (flags & Qt::WindowMinimizeButtonHint)
+ style |= WS_MINIMIZEBOX;
+ if (shouldShowMaximizeButton(flags))
+ style |= WS_MAXIMIZEBOX;
+ if (tool)
+ exStyle |= WS_EX_TOOLWINDOW;
+ if (flags & Qt::WindowContextHelpButtonHint)
+ exStyle |= WS_EX_CONTEXTHELP;
+ } else {
+ exStyle |= WS_EX_TOOLWINDOW;
+ }
+ }
+ }
+}
+
+QWindowsWindow::WindowData
+ WindowCreationData::create(const QWindow *w, const QRect &geometry, QString title) const
+{
+ typedef QSharedPointer<QWindowCreationContext> QWindowCreationContextPtr;
+
+ WindowData result;
+ result.flags = flags;
+
+ if (desktop) { // desktop widget. No frame, hopefully?
+ result.hwnd = GetDesktopWindow();
+ result.geometry = frameGeometry(result.hwnd);
+ if (QWindowsContext::verboseWindows)
+ qDebug().nospace() << "Created desktop window " << w << result.hwnd;
+ return result;
+ }
+
+ const HINSTANCE appinst = (HINSTANCE)GetModuleHandle(0);
+
+ const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w, isGL);
+
+ if (title.isEmpty() && (result.flags & Qt::WindowTitleHint))
+ title = topLevel ? qAppName() : w->objectName();
+
+ const wchar_t *titleUtf16 = reinterpret_cast<const wchar_t *>(title.utf16());
+ const wchar_t *classNameUtf16 = reinterpret_cast<const wchar_t *>(windowClassName.utf16());
+
+ // Capture events before CreateWindowEx() returns.
+ const QWindowCreationContextPtr context(new QWindowCreationContext(w, geometry, style, exStyle));
+ QWindowsContext::instance()->setWindowCreationContext(context);
+
+ if (QWindowsContext::verboseWindows)
+ qDebug().nospace()
+ << "CreateWindowEx: " << w << *this
+ << " class=" <<windowClassName << " title=" << title
+ << "\nrequested: " << geometry << ": "
+ << context->frameWidth << 'x' << context->frameHeight
+ << '+' << context->frameX << '+' << context->frameY;
+
+ result.hwnd = CreateWindowEx(exStyle, classNameUtf16, titleUtf16,
+ style,
+ context->frameX, context->frameY,
+ context->frameWidth, context->frameHeight,
+ parentHandle, NULL, appinst, NULL);
+ QWindowsContext::instance()->setWindowCreationContext(QWindowCreationContextPtr());
+ if (QWindowsContext::verboseWindows)
+ qDebug().nospace()
+ << "CreateWindowEx: returns " << w << ' ' << result.hwnd << " obtained geometry: "
+ << context->obtainedGeometry << context->margins;
+
+ if (!result.hwnd) {
+ qErrnoWarning("%s: CreateWindowEx failed", __FUNCTION__);
+ return result;
+ }
+
+ result.geometry = context->obtainedGeometry;
+ result.frame = context->margins;
+ return result;
+}
+
+void WindowCreationData::applyWindowFlags(HWND hwnd) const
+{
+ // Keep enabled and visible from the current style.
+ const LONG_PTR oldStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
+ const LONG_PTR oldExStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
+
+ const LONG_PTR newStyle = style | (oldStyle & (WS_DISABLED|WS_VISIBLE));
+ if (oldStyle != newStyle)
+ SetWindowLongPtr(hwnd, GWL_STYLE, newStyle);
+ const LONG_PTR newExStyle = exStyle;
+ if (newExStyle != oldExStyle)
+ SetWindowLongPtr(hwnd, GWL_EXSTYLE, newExStyle);
+ if (QWindowsContext::verboseWindows)
+ qDebug().nospace() << __FUNCTION__ << hwnd << *this
+ << "\n Style from " << debugWinStyle(oldStyle) << "\n to "
+ << debugWinStyle(newStyle) << "\n ExStyle from 0x"
+ << QByteArray::number(qulonglong(oldExStyle), 16) << " to 0x"
+ << QByteArray::number(qulonglong(newExStyle), 16);
+}
+
+void WindowCreationData::initialize(HWND hwnd, bool frameChange) const
+{
+ if (desktop || !hwnd)
+ return;
+ UINT flags = SWP_NOMOVE | SWP_NOSIZE;
+ if (frameChange)
+ flags |= SWP_FRAMECHANGED;
+ if (topLevel) {
+ flags |= SWP_NOACTIVATE;
+ if ((flags & Qt::WindowStaysOnTopHint) || (type == Qt::ToolTip)) {
+ SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, flags);
+ if (flags & Qt::WindowStaysOnBottomHint)
+ qWarning() << "QWidget: Incompatible window flags: the window can't be on top and on bottom at the same time";
+ } else if (flags & Qt::WindowStaysOnBottomHint) {
+ SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, flags);
+ }
+ if (flags & (Qt::CustomizeWindowHint|Qt::WindowTitleHint)) {
+ HMENU systemMenu = GetSystemMenu(hwnd, FALSE);
+ if (flags & Qt::WindowCloseButtonHint)
+ EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_ENABLED);
+ else
+ EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_GRAYED);
+ }
+ } else { // child.
+ SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, flags);
+ }
+}
+
+/*!
+ \class QWindowsGeometryHint
+ \brief Stores geometry constraints and provides utility functions.
+
+ Geometry constraints ready to apply to a MINMAXINFO taking frame
+ into account.
+
+ \ingroup qt-lighthouse-win
+*/
+
+#define QWINDOWSIZE_MAX ((1<<24)-1)
+
+QWindowsGeometryHint::QWindowsGeometryHint(const QWindow *w) :
+ minimumSize(w->minimumSize()),
+ maximumSize(w->maximumSize())
+{
+}
+
+bool QWindowsGeometryHint::validSize(const QSize &s) const
+{
+ const int width = s.width();
+ const int height = s.height();
+ return width >= minimumSize.width() && width <= maximumSize.width()
+ && height >= minimumSize.height() && height <= maximumSize.height();
+}
+
+QMargins QWindowsGeometryHint::frame(DWORD style, DWORD exStyle)
+{
+ RECT rect = {0,0,0,0};
+ style &= ~(WS_OVERLAPPED); // Not permitted, see docs.
+ if (!AdjustWindowRectEx(&rect, style, FALSE, exStyle))
+ qErrnoWarning("%s: AdjustWindowRectEx failed", __FUNCTION__);
+ const QMargins result(qAbs(rect.left), qAbs(rect.top),
+ qAbs(rect.right), qAbs(rect.bottom));
+ if (QWindowsContext::verboseWindows)
+ qDebug().nospace() << __FUNCTION__ << " style= 0x"
+ << QString::number(style, 16)
+ << " exStyle=0x" << QString::number(exStyle, 16) << ' ' << rect << ' ' << result;
+
+ return result;
+}
+
+void QWindowsGeometryHint::applyToMinMaxInfo(HWND hwnd, MINMAXINFO *mmi) const
+{
+ return applyToMinMaxInfo(GetWindowLong(hwnd, GWL_STYLE),
+ GetWindowLong(hwnd, GWL_EXSTYLE), mmi);
+}
+
+void QWindowsGeometryHint::applyToMinMaxInfo(DWORD style, DWORD exStyle, MINMAXINFO *mmi) const
+{
+ if (QWindowsContext::verboseWindows)
+ qDebug().nospace() << '>' << __FUNCTION__ << '<' << " min="
+ << minimumSize.width() << ',' << minimumSize.height()
+ << " max=" << maximumSize.width() << ',' << maximumSize.height()
+ << " in " << *mmi;
+
+ const QMargins margins = QWindowsGeometryHint::frame(style, exStyle);
+ const int frameWidth = margins.left() + margins.right();
+ const int frameHeight = margins.top() + margins.bottom();
+ if (minimumSize.width() > 0)
+ mmi->ptMinTrackSize.x = minimumSize.width() + frameWidth;
+ if (minimumSize.height() > 0)
+ mmi->ptMinTrackSize.y = minimumSize.height() + frameHeight;
+
+ const int maximumWidth = qMax(maximumSize.width(), minimumSize.width());
+ const int maximumHeight = qMax(maximumSize.height(), minimumSize.height());
+ if (maximumWidth < QWINDOWSIZE_MAX)
+ mmi->ptMaxTrackSize.x = maximumWidth + frameWidth;
+ // windows with title bar have an implicit size limit of 112 pixels
+ if (maximumHeight < QWINDOWSIZE_MAX)
+ mmi->ptMaxTrackSize.y = qMax(maximumHeight + frameHeight, 112);
+ if (QWindowsContext::verboseWindows)
+ qDebug().nospace() << '<' << __FUNCTION__
+ << " frame=" << margins << ' ' << frameWidth << ',' << frameHeight
+ << " out " << *mmi;
+}
+
+/*!
+ \class QWindowCreationContext
+ \brief Active Context for creating windows.
+
+ There is a phase in window creation (WindowCreationData::create())
+ in which events are sent before the system API CreateWindowEx() returns
+ the handle. These cannot be handled by the platform window as the association
+ of the unknown handle value to the window does not exist yet and as not
+ to trigger recursive handle creation, etc.
+
+ In that phase, an instance of QWindowCreationContext is set on
+ QWindowsContext.
+
+ QWindowCreationContext stores the information to answer the initial
+ WM_GETMINMAXINFO and obtains the corrected size/position.
+
+ \sa WindowCreationData, QWindowsContext
+ \ingroup qt-lighthouse-win
+*/
+
+QWindowCreationContext::QWindowCreationContext(const QWindow *w,
+ const QRect &geometry,
+ DWORD style_, DWORD exStyle_) :
+ geometryHint(w), style(style_), exStyle(exStyle_),
+ requestedGeometry(geometry), obtainedGeometry(geometry),
+ margins(QWindowsGeometryHint::frame(style, exStyle)),
+ frameX(CW_USEDEFAULT), frameY(CW_USEDEFAULT),
+ frameWidth(CW_USEDEFAULT), frameHeight(CW_USEDEFAULT)
+{
+ // Geometry of toplevels does not consider window frames.
+ // TODO: No concept of WA_wasMoved yet that would indicate a
+ // CW_USEDEFAULT unless set. For now, assume that 0,0 means 'default'
+ // for toplevels.
+ if (geometry.isValid()) {
+ if (!w->isTopLevel() || geometry.y() >= margins.top()) {
+ frameX = geometry.x() - margins.left();
+ frameY = geometry.y() - margins.top();
+ }
+ frameWidth = geometry.width() + margins.left() + margins.right();
+ frameHeight = geometry.height() + margins.top() + margins.bottom();
+ }
+ if (QWindowsContext::verboseWindows)
+ qDebug().nospace()
+ << __FUNCTION__ << ' ' << w << " min" << geometryHint.minimumSize
+ << " min" << geometryHint.maximumSize;
+}
+
+/*!
+ \class QWindowsBaseWindow
+ \brief Raster or OpenGL Window.
+
+ \list
+ \o Raster type: handleWmPaint() is implemented to
+ to bitblt the image. The DC can be accessed
+ via getDC/Relase DC, which has a special handling
+ when within a paint event (in that case, the DC obtained
+ from BeginPaint() is returned).
+
+ \o Open GL: The first time QWindowsGLContext accesses
+ the handle, it sets up the pixelformat on the DC
+ which in turn sets it on the window (see flag
+ PixelFormatInitialized).
+ handleWmPaint() is empty (although required).
+ \endlist
+
+ \ingroup qt-lighthouse-win
+*/
+
+QWindowsWindow::QWindowsWindow(QWindow *aWindow, const WindowData &data) :
+ QPlatformWindow(aWindow),
+ m_data(data),
+ m_flags(0),
+ m_hdc(0),
+ m_windowState(aWindow->windowState()),
+ m_opacity(1.0),
+ m_mouseGrab(false),
+ m_cursor(QWindowsScreen::screenOf(aWindow)->cursor().standardWindowCursor()),
+ m_dropTarget(0)
+{
+ if (aWindow->surfaceType() == QWindow::OpenGLSurface)
+ setFlag(OpenGL_Surface);
+ QWindowsContext::instance()->addWindow(m_data.hwnd, this);
+ if (aWindow->isTopLevel()) {
+ switch (aWindow->windowType()) {
+ case Qt::Window:
+ case Qt::Dialog:
+ case Qt::Sheet:
+ case Qt::Drawer:
+ case Qt::Popup:
+ case Qt::Tool:
+ registerDropSite();
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+QWindowsWindow::~QWindowsWindow()
+{
+ destroyWindow();
+}
+
+void QWindowsWindow::destroyWindow()
+{
+ if (QWindowsContext::verboseIntegration || QWindowsContext::verboseWindows)
+ qDebug() << __FUNCTION__ << this << window() << m_data.hwnd;
+ if (m_data.hwnd) {
+ unregisterDropSite();
+ if (m_data.hwnd != GetDesktopWindow())
+ DestroyWindow(m_data.hwnd);
+ QWindowsContext::instance()->removeWindow(m_data.hwnd);
+ m_data.hwnd = 0;
+ }
+}
+
+void QWindowsWindow::registerDropSite()
+{
+ if (m_data.hwnd && !m_dropTarget) {
+ m_dropTarget = new QWindowsOleDropTarget(window());
+ RegisterDragDrop(m_data.hwnd, m_dropTarget);
+ CoLockObjectExternal(m_dropTarget, true, true);
+ }
+}
+
+void QWindowsWindow::unregisterDropSite()
+{
+ if (m_data.hwnd && m_dropTarget) {
+ m_dropTarget->Release();
+ CoLockObjectExternal(m_dropTarget, false, true);
+ RevokeDragDrop(m_data.hwnd);
+ m_dropTarget = 0;
+ }
+}
+
+QWindow *QWindowsWindow::topLevelOf(QWindow *w)
+{
+ while (QWindow *parent = w->parent())
+ w = parent;
+ return w;
+}
+
+QWindowsWindow::WindowData
+ QWindowsWindow::WindowData::create(const QWindow *w,
+ const WindowData &parameters,
+ const QString &title,
+ bool isGL)
+{
+ WindowCreationData creationData;
+ creationData.fromWindow(w, parameters.flags, isGL);
+ WindowData result = creationData.create(w, parameters.geometry, title);
+ creationData.initialize(result.hwnd, false);
+ return result;
+}
+
+void QWindowsWindow::setVisible(bool visible)
+{
+ if (QWindowsContext::verboseWindows)
+ qDebug() << __FUNCTION__ << this << window() << m_data.hwnd << visible;
+ if (m_data.hwnd) {
+ if (visible) {
+ show_sys();
+ } else {
+ hide_sys();
+ }
+ }
+}
+
+bool QWindowsWindow::isVisible() const
+{
+ return m_data.hwnd && IsWindowVisible(m_data.hwnd);
+}
+
+// partially from QWidgetPrivate::show_sys()
+void QWindowsWindow::show_sys() const
+{
+ int sm = SW_SHOWNORMAL;
+ bool fakedMaximize = false;
+ const QWindow *w = window();
+ const Qt::WindowFlags flags = w->windowFlags();
+ const Qt::WindowType type = w->windowType();
+ if (w->isTopLevel()) {
+ const Qt::WindowState state = w->windowState();
+ if (state & Qt::WindowMinimized) {
+ sm = SW_SHOWMINIMIZED;
+ if (!isVisible())
+ sm = SW_SHOWMINNOACTIVE;
+ } else if (state & Qt::WindowMaximized) {
+ sm = SW_SHOWMAXIMIZED;
+ // Windows will not behave correctly when we try to maximize a window which does not
+ // have minimize nor maximize buttons in the window frame. Windows would then ignore
+ // non-available geometry, and rather maximize the widget to the full screen, minus the
+ // window frame (caption). So, we do a trick here, by adding a maximize button before
+ // maximizing the widget, and then remove the maximize button afterwards.
+ if (flags & Qt::WindowTitleHint &&
+ !(flags & (Qt::WindowMinMaxButtonsHint | Qt::FramelessWindowHint))) {
+ fakedMaximize = TRUE;
+ setStyle(style() | WS_MAXIMIZEBOX);
+ }
+ }
+ }
+ if (type == Qt::Popup || type == Qt::ToolTip || type == Qt::Tool)
+ sm = SW_SHOWNOACTIVATE;
+
+ ShowWindow(m_data.hwnd, sm);
+
+ if (fakedMaximize) {
+ setStyle(style() & ~WS_MAXIMIZEBOX);
+ SetWindowPos(m_data.hwnd, 0, 0, 0, 0, 0,
+ SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER
+ | SWP_FRAMECHANGED);
+ }
+}
+
+// partially from QWidgetPrivate::hide_sys()
+void QWindowsWindow::hide_sys() const
+{
+ const Qt::WindowFlags flags = window()->windowFlags();
+ if (flags != Qt::Desktop) {
+ if (flags & Qt::Popup)
+ ShowWindow(m_data.hwnd, SW_HIDE);
+ else
+ SetWindowPos(m_data.hwnd,0, 0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER);
+ }
+}
+
+void QWindowsWindow::setParent(const QPlatformWindow *newParent)
+{
+ if (QWindowsContext::verboseWindows)
+ qDebug() << __FUNCTION__ << window() << newParent;
+
+ if (newParent != parent() && m_data.hwnd)
+ setParent_sys(newParent);
+}
+
+void QWindowsWindow::setParent_sys(const QPlatformWindow *parent) const
+{
+ HWND parentHWND = 0;
+ if (parent) {
+ const QWindowsWindow *parentW = static_cast<const QWindowsWindow *>(parent);
+ parentHWND = parentW->handle();
+ }
+ SetParent(m_data.hwnd, parentHWND);
+}
+
+void QWindowsWindow::handleShown()
+{
+ QWindowSystemInterface::handleMapEvent(window());
+}
+
+void QWindowsWindow::handleHidden()
+{
+ QWindowSystemInterface::handleUnmapEvent(window());
+}
+
+void QWindowsWindow::setGeometry(const QRect &rect)
+{
+ const QSize oldSize = m_data.geometry.size();
+ m_data.geometry = rect;
+ const QSize newSize = rect.size();
+ // Check on hint.
+ if (newSize != oldSize) {
+ const QWindowsGeometryHint hint(window());
+ if (!hint.validSize(newSize)) {
+ qWarning("%s: Attempt to set a size (%dx%d) violating the constraints"
+ "(%dx%d - %dx%d) on window '%s'.", __FUNCTION__,
+ newSize.width(), newSize.height(),
+ hint.minimumSize.width(), hint.minimumSize.height(),
+ hint.maximumSize.width(), hint.maximumSize.height(),
+ qPrintable(window()->objectName()));
+ }
+ }
+ if (m_data.hwnd) {
+ // A ResizeEvent with resulting geometry will be sent. If we cannot
+ // achieve that size (for example, window title minimal constraint),
+ // notify and warn.
+ setGeometry_sys(rect);
+ if (m_data.geometry != rect) {
+ qWarning("%s: Unable to set geometry %dx%d+%d+%d on '%s'."
+ " Resulting geometry: %dx%d+%d+%d.",
+ __FUNCTION__,
+ rect.width(), rect.height(), rect.x(), rect.y(),
+ qPrintable(window()->objectName()),
+ m_data.geometry.width(), m_data.geometry.height(),
+ m_data.geometry.x(), m_data.geometry.y());
+ }
+ } else {
+ QPlatformWindow::setGeometry(rect);
+ }
+}
+
+void QWindowsWindow::handleMoved()
+{
+ if (!IsIconic(m_data.hwnd)) // Minimize can send nonsensical move events.
+ handleGeometryChange();
+}
+
+void QWindowsWindow::handleResized(int wParam)
+{
+ switch (wParam) {
+ case SIZE_MAXHIDE: // Some other window affected.
+ case SIZE_MAXSHOW:
+ return;
+ case SIZE_MINIMIZED:
+ handleWindowStateChange(Qt::WindowMinimized);
+ return;
+ case SIZE_MAXIMIZED:
+ handleWindowStateChange(Qt::WindowMaximized);
+ handleGeometryChange();
+ break;
+ case SIZE_RESTORED:
+ if (m_windowState != Qt::WindowNoState)
+ handleWindowStateChange(Qt::WindowNoState);
+ handleGeometryChange();
+ break;
+ }
+}
+
+void QWindowsWindow::handleGeometryChange()
+{
+ m_data.geometry = geometry_sys();
+ QPlatformWindow::setGeometry(m_data.geometry);
+ QWindowSystemInterface::handleGeometryChange(window(), m_data.geometry);
+
+ if (QWindowsContext::verboseEvents || QWindowsContext::verboseWindows)
+ qDebug() << __FUNCTION__ << this << window() << m_data.geometry;
+}
+
+void QWindowsWindow::setGeometry_sys(const QRect &rect) const
+{
+ const QRect frameGeometry = rect + frameMargins();
+
+ if (QWindowsContext::verboseWindows)
+ qDebug() << '>' << __FUNCTION__ << this << window()
+ << " \n from " << geometry_sys() << " to " <<rect
+ << " new frame: " << frameGeometry;
+
+ const bool rc = MoveWindow(m_data.hwnd, frameGeometry.x(), frameGeometry.y(),
+ frameGeometry.width(), frameGeometry.height(), true);
+ if (QWindowsContext::verboseWindows)
+ qDebug() << '<' << __FUNCTION__ << this << window()
+ << " \n resulting " << rc << geometry_sys();
+}
+
+QRect QWindowsWindow::geometry_sys() const
+{
+ // Warning: Returns bogus values when minimized.
+ return frameGeometry(m_data.hwnd) - frameMargins();
+}
+
+/*!
+ Allocates a HDC for the window or returns the temporary one
+ obtained from WinAPI BeginPaint within a WM_PAINT event.
+
+ \sa releaseDC()
+*/
+
+HDC QWindowsWindow::getDC()
+{
+ if (!m_hdc)
+ m_hdc = GetDC(handle());
+ return m_hdc;
+}
+
+/*!
+ Relases the HDC for the window or does nothing in
+ case it was obtained from WinAPI BeginPaint within a WM_PAINT event.
+
+ \sa getDC()
+*/
+
+void QWindowsWindow::releaseDC()
+{
+ if (m_hdc && !testFlag(WithinWmPaint)) {
+ ReleaseDC(handle(), m_hdc);
+ m_hdc = 0;
+ }
+}
+
+void QWindowsWindow::handleWmPaint(HWND hwnd, UINT,
+ WPARAM, LPARAM)
+{
+ PAINTSTRUCT ps;
+ if (testFlag(OpenGL_Surface)) {
+ BeginPaint(hwnd, &ps); // WM_ERASEBKGND needs to be handled.
+ EndPaint(hwnd, &ps);
+ } else {
+ releaseDC();
+ m_hdc = BeginPaint(hwnd, &ps);
+ setFlag(WithinWmPaint);
+
+ const QRect updateRect = qrectFromRECT(ps.rcPaint);
+ if (QWindowsContext::verboseIntegration)
+ qDebug() << __FUNCTION__ << this << window() << updateRect;
+
+ QWindowSystemInterface::handleExposeEvent(window(), QRegion(updateRect));
+ clearFlag(WithinWmPaint);
+ m_hdc = 0;
+ EndPaint(hwnd, &ps);
+ }
+}
+
+void QWindowsWindow::setWindowTitle(const QString &title)
+{
+ if (QWindowsContext::verboseWindows)
+ qDebug() << __FUNCTION__ << this << window() <<title;
+ if (m_data.hwnd)
+ SetWindowText(m_data.hwnd, (const wchar_t*)title.utf16());
+}
+
+Qt::WindowFlags QWindowsWindow::setWindowFlags(Qt::WindowFlags flags)
+{
+ if (QWindowsContext::verboseWindows)
+ qDebug() << '>' << __FUNCTION__ << this << window() << "\n from: "
+ << QWindowsWindow::debugWindowFlags(m_data.flags)
+ << "\n to: " << QWindowsWindow::debugWindowFlags(flags);
+ if (m_data.flags != flags) {
+ m_data.flags = flags;
+ if (m_data.hwnd)
+ m_data = setWindowFlags_sys(flags);
+ }
+ if (QWindowsContext::verboseWindows)
+ qDebug() << '<' << __FUNCTION__ << "\n returns: "
+ << QWindowsWindow::debugWindowFlags(m_data.flags);
+ return m_data.flags;
+}
+
+QWindowsWindow::WindowData QWindowsWindow::setWindowFlags_sys(Qt::WindowFlags wt) const
+{
+ // Geometry changes have not been observed here. Frames change, though.
+ WindowCreationData creationData;
+ creationData.fromWindow(window(), wt, window()->surfaceType() == QWindow::OpenGLSurface);
+ creationData.applyWindowFlags(m_data.hwnd);
+ creationData.initialize(m_data.hwnd, true);
+ WindowData result = m_data;
+ result.flags = creationData.flags;
+ setFlag(FrameDirty);
+ return result;
+}
+
+void QWindowsWindow::handleWindowStateChange(Qt::WindowState state)
+{
+ if (QWindowsContext::verboseWindows)
+ qDebug() << __FUNCTION__ << this << window()
+ << "\n from " << debugWindowStates(m_windowState)
+ << " to " << debugWindowStates(state);
+ setFlag(FrameDirty);
+ m_windowState = state;
+ QWindowSystemInterface::handleWindowStateChanged(window(), state);
+}
+
+Qt::WindowState QWindowsWindow::setWindowState(Qt::WindowState state)
+{
+ if (m_data.hwnd) {
+ setWindowState_sys(state);
+ m_windowState = state;
+ }
+ return state;
+}
+
+Qt::WindowState QWindowsWindow::windowState_sys() const
+{
+ if (IsIconic(m_data.hwnd))
+ return Qt::WindowMinimized;
+ if (IsZoomed(m_data.hwnd))
+ return Qt::WindowMaximized;
+ if (geometry_sys() == window()->screen()->geometry())
+ return Qt::WindowFullScreen;
+ return Qt::WindowNoState;
+}
+
+Qt::WindowStates QWindowsWindow::windowStates_sys() const
+{
+ Qt::WindowStates result = windowState_sys();
+ if (GetActiveWindow() == m_data.hwnd)
+ result |= Qt::WindowActive;
+ return result;
+}
+
+/*!
+ \brief Change the window state.
+
+ \note Window frames change when maximized;
+ the top margin shrinks somewhat but that cannot be obtained using
+ AdjustWindowRectEx().
+
+ \note Some calls to SetWindowLong require a subsequent call
+ to ShowWindow.
+*/
+
+void QWindowsWindow::setWindowState_sys(Qt::WindowState newState)
+{
+ const Qt::WindowStates oldStates = windowStates_sys();
+ // Maintain the active flag as the platform window API does not
+ // use it.
+ Qt::WindowStates newStates = newState;
+ if (oldStates & Qt::WindowActive)
+ newStates |= Qt::WindowActive;
+ if (oldStates == newStates)
+ return;
+ if (QWindowsContext::verboseWindows)
+ qDebug() << '>' << __FUNCTION__ << this << window()
+ << " from " << debugWindowStates(oldStates)
+ << " to " << debugWindowStates(newStates);
+
+ const bool isActive = newStates & Qt::WindowActive;
+ const int max = isActive ? SW_SHOWMAXIMIZED : SW_MAXIMIZE;
+ const int normal = isActive ? SW_SHOWNORMAL : SW_SHOWNOACTIVATE;
+ const int min = isActive ? SW_SHOWMINIMIZED : SW_MINIMIZE;
+ const bool visible = isVisible();
+
+ setFlag(FrameDirty);
+
+ if ((oldStates & Qt::WindowMaximized) != (newStates & Qt::WindowMaximized)) {
+ if (visible && !(newStates & Qt::WindowMinimized))
+ ShowWindow(m_data.hwnd, (newStates & Qt::WindowMaximized) ? max : normal);
+ }
+
+ if ((oldStates & Qt::WindowFullScreen) != (newStates & Qt::WindowFullScreen)) {
+ if (newStates & Qt::WindowFullScreen) {
+#ifndef Q_FLATTEN_EXPOSE
+ UINT newStyle = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP;
+#else
+ UINT newStyle = WS_POPUP;
+#endif
+ if (style() & WS_SYSMENU)
+ newStyle |= WS_SYSMENU;
+ if (visible)
+ newStyle |= WS_VISIBLE;
+ setStyle(newStyle);
+
+ const QRect r = window()->screen()->geometry();
+ UINT swpf = SWP_FRAMECHANGED;
+ if (newStates & Qt::WindowActive)
+ swpf |= SWP_NOACTIVATE;
+
+ SetWindowPos(m_data.hwnd, HWND_TOP, r.left(), r.top(), r.width(), r.height(), swpf);
+ } else {
+ if (visible)
+ setStyle(style() | WS_VISIBLE);
+ UINT swpf = SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE;
+ if (newStates & Qt::WindowActive)
+ swpf |= SWP_NOACTIVATE;
+ SetWindowPos(m_data.hwnd, 0, 0, 0, 0, 0, swpf);
+
+ // preserve maximized state
+ if (visible)
+ ShowWindow(m_data.hwnd, (newStates & Qt::WindowMaximized) ? max : normal);
+ }
+ }
+
+ if ((oldStates & Qt::WindowMinimized) != (newStates & Qt::WindowMinimized)) {
+ if (visible)
+ ShowWindow(m_data.hwnd, (newStates & Qt::WindowMinimized) ? min :
+ (newStates & Qt::WindowMaximized) ? max : normal);
+ }
+ if (QWindowsContext::verboseWindows)
+ qDebug() << '<' << __FUNCTION__ << this << window()
+ << debugWindowStates(newStates);
+}
+
+void QWindowsWindow::setStyle(unsigned s) const
+{
+ if (QWindowsContext::verboseWindows)
+ qDebug() << __FUNCTION__ << this << window() << debugWinStyle(s);
+ setFlag(FrameDirty);
+ SetWindowLongPtr(m_data.hwnd, GWL_STYLE, s);
+}
+
+void QWindowsWindow::setExStyle(unsigned s) const
+{
+ if (QWindowsContext::verboseWindows)
+ qDebug().nospace() << __FUNCTION__ << ' ' << this << ' ' << window()
+ << " 0x" << QByteArray::number(s, 16);
+ setFlag(FrameDirty);
+ SetWindowLongPtr(m_data.hwnd, GWL_EXSTYLE, s);
+}
+
+void QWindowsWindow::raise()
+{
+ if (QWindowsContext::verboseWindows)
+ qDebug() << __FUNCTION__ << this << window();
+ SetWindowPos(m_data.hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
+}
+
+void QWindowsWindow::lower()
+{
+ if (QWindowsContext::verboseWindows)
+ qDebug() << __FUNCTION__ << this << window();
+ if (m_data.hwnd)
+ SetWindowPos(m_data.hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
+}
+
+void QWindowsWindow::propagateSizeHints()
+{
+ if (QWindowsContext::verboseWindows)
+ qDebug() << __FUNCTION__ << this << window();
+}
+
+QMargins QWindowsWindow::frameMargins() const
+{
+ // Frames are invalidated by style changes (window state, flags).
+ // As they are also required for geometry calculations in resize
+ // event sequences, introduce a dirty flag mechanism to be able
+ // to cache results.
+ if (testFlag(FrameDirty)) {
+ m_data.frame = QWindowsGeometryHint::frame(style(), exStyle());
+ clearFlag(FrameDirty);
+ }
+ return m_data.frame;
+}
+
+void QWindowsWindow::setOpacity(qreal level)
+{
+ if (QWindowsContext::verboseWindows)
+ qDebug() << __FUNCTION__ << level;
+ if (m_opacity != level) {
+ m_opacity = level;
+ if (m_data.hwnd)
+ setOpacity_sys(level);
+ }
+}
+
+void QWindowsWindow::setOpacity_sys(qreal level) const
+{
+ const long wl = GetWindowLong(m_data.hwnd, GWL_EXSTYLE);
+ const bool isOpaque = level == 1.0;
+
+ if (isOpaque) {
+ if (wl & WS_EX_LAYERED)
+ SetWindowLong(m_data.hwnd, GWL_EXSTYLE, wl & ~WS_EX_LAYERED);
+ } else {
+ if ((wl & WS_EX_LAYERED) == 0)
+ SetWindowLong(m_data.hwnd, GWL_EXSTYLE, wl | WS_EX_LAYERED);
+ if (m_data.flags & Qt::FramelessWindowHint) {
+ BLENDFUNCTION blend = {AC_SRC_OVER, 0, (int)(255.0 * level), AC_SRC_ALPHA};
+ QWindowsContext::user32dll.updateLayeredWindow(m_data.hwnd, NULL, NULL, NULL, NULL, NULL, 0, &blend, ULW_ALPHA);
+ } else {
+ QWindowsContext::user32dll.setLayeredWindowAttributes(m_data.hwnd, 0, (int)(level * 255), LWA_ALPHA);
+ }
+ }
+}
+
+void QWindowsWindow::requestActivateWindow()
+{
+ if (QWindowsContext::verboseWindows)
+ qDebug() << __FUNCTION__ << this << window();
+ if (m_data.hwnd)
+ SetForegroundWindow(m_data.hwnd);
+}
+
+bool QWindowsWindow::setKeyboardGrabEnabled(bool grab)
+{
+ if (!m_data.hwnd) {
+ qWarning("%s: No handle", __FUNCTION__);
+ return false;
+ }
+ if (QWindowsContext::verboseWindows)
+ qDebug() << __FUNCTION__ << this << window() << grab;
+
+ QWindowsContext *context = QWindowsContext::instance();
+ if (grab) {
+ context->setKeyGrabber(window());
+ } else {
+ if (context->keyGrabber() == window())
+ context->setKeyGrabber(0);
+ }
+ return true;
+}
+
+bool QWindowsWindow::setMouseGrabEnabled(bool grab)
+{
+ bool result = false;
+ if (!m_data.hwnd) {
+ qWarning("%s: No handle", __FUNCTION__);
+ return result;
+ }
+ if (QWindowsContext::verboseWindows)
+ qDebug() << __FUNCTION__ << window() << grab;
+
+ if (m_mouseGrab != grab) {
+ m_mouseGrab = grab;
+ if (isVisible())
+ setMouseGrabEnabled_sys(grab);
+ }
+ return grab;
+}
+
+void QWindowsWindow::setMouseGrabEnabled_sys(bool grab)
+{
+ if (grab) {
+ SetCapture(m_data.hwnd);
+ } else {
+ ReleaseCapture();
+ }
+}
+
+void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const
+{
+ const QWindowsGeometryHint hint(window());
+ hint.applyToMinMaxInfo(m_data.hwnd, mmi);
+ if (QWindowsContext::verboseWindows)
+ qDebug() << __FUNCTION__ << window() << *mmi;
+}
+
+/*!
+ \brief Applies to cursor property set on the window to the global cursor
+ unless there is an override cursor.
+
+ \sa QWindowsCursor
+*/
+
+void QWindowsWindow::applyCursor()
+{
+ if (!QGuiApplication::overrideCursor())
+ SetCursor(m_cursor.handle());
+}
+
+void QWindowsWindow::setCursor(const QWindowsWindowCursor &c)
+{
+ if (c.handle() != m_cursor.handle()) {
+ const bool underMouse = QWindowsContext::instance()->windowUnderMouse() == window();
+ if (QWindowsContext::verboseWindows)
+ qDebug() << window() << __FUNCTION__ << "Shape=" << c.cursor().shape()
+ << " isWUM=" << underMouse;
+ m_cursor = c;
+ if (underMouse)
+ applyCursor();
+ }
+}
+
+/*!
+ \brief Find a child window using flags from ChildWindowFromPointEx.
+*/
+
+QWindowsWindow *QWindowsWindow::childAtScreenPoint(const QPoint &screenPoint,
+ unsigned cwexflags) const
+{
+ if (m_data.hwnd)
+ return QWindowsContext::instance()->findPlatformWindowAt(m_data.hwnd, screenPoint, cwexflags);
+ return 0;
+}
+
+QWindowsWindow *QWindowsWindow::childAt(const QPoint &clientPoint, unsigned cwexflags) const
+{
+ if (m_data.hwnd)
+ return childAtScreenPoint(QWindowsGeometryHint::mapToGlobal(m_data.hwnd, clientPoint),
+ cwexflags);
+ return 0;
+}
+
+QByteArray QWindowsWindow::debugWindowFlags(Qt::WindowFlags wf)
+{
+ const int iwf = int(wf);
+ QByteArray rc = "0x";
+ rc += QByteArray::number(iwf, 16);
+ rc += " [";
+
+ switch ((iwf & Qt::WindowType_Mask)) {
+ case Qt::Widget:
+ rc += " Widget";
+ break;
+ case Qt::Window:
+ rc += " Window";
+ break;
+ case Qt::Dialog:
+ rc += " Dialog";
+ break;
+ case Qt::Sheet:
+ rc += " Sheet";
+ break;
+ case Qt::Popup:
+ rc += " Popup";
+ break;
+ case Qt::Tool:
+ rc += " Tool";
+ break;
+ case Qt::ToolTip:
+ rc += " ToolTip";
+ break;
+ case Qt::SplashScreen:
+ rc += " SplashScreen";
+ break;
+ case Qt::Desktop:
+ rc += " Desktop";
+ break;
+ case Qt::SubWindow:
+ rc += " SubWindow";
+ break;
+ }
+ if (iwf & Qt::MSWindowsFixedSizeDialogHint) rc += " MSWindowsFixedSizeDialogHint";
+ if (iwf & Qt::MSWindowsOwnDC) rc += " MSWindowsOwnDC";
+ if (iwf & Qt::FramelessWindowHint) rc += " FramelessWindowHint";
+ if (iwf & Qt::WindowTitleHint) rc += " WindowTitleHint";
+ if (iwf & Qt::WindowSystemMenuHint) rc += " WindowSystemMenuHint";
+ if (iwf & Qt::WindowMinimizeButtonHint) rc += " WindowMinimizeButtonHint";
+ if (iwf & Qt::WindowMaximizeButtonHint) rc += " WindowMaximizeButtonHint";
+ if (iwf & Qt::WindowContextHelpButtonHint) rc += " WindowContextHelpButtonHint";
+ if (iwf & Qt::WindowShadeButtonHint) rc += " WindowShadeButtonHint";
+ if (iwf & Qt::WindowStaysOnTopHint) rc += " WindowStaysOnTopHint";
+ if (iwf & Qt::CustomizeWindowHint) rc += " CustomizeWindowHint";
+ if (iwf & Qt::WindowStaysOnBottomHint) rc += " WindowStaysOnBottomHint";
+ if (iwf & Qt::WindowCloseButtonHint) rc += " WindowCloseButtonHint";
+ rc += ']';
+ return rc;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h
new file mode 100644
index 0000000000..dfaeb2a86d
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowswindow.h
@@ -0,0 +1,284 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSWINDOW_H
+#define QWINDOWSWINDOW_H
+
+#include "qtwindows_additional.h"
+#include "qwindowscursor.h"
+
+#include <QtGui/QPlatformWindow>
+
+QT_BEGIN_NAMESPACE
+
+class QWindowsOleDropTarget;
+class QDebug;
+
+struct QWindowsGeometryHint
+{
+ QWindowsGeometryHint() {}
+ explicit QWindowsGeometryHint(const QWindow *w);
+ static QMargins frame(DWORD style, DWORD exStyle);
+ void applyToMinMaxInfo(DWORD style, DWORD exStyle, MINMAXINFO *mmi) const;
+ void applyToMinMaxInfo(HWND hwnd, MINMAXINFO *mmi) const;
+ bool validSize(const QSize &s) const;
+
+ static inline QPoint mapToGlobal(HWND hwnd, const QPoint &);
+ static inline QPoint mapToGlobal(const QWindow *w, const QPoint &);
+ static inline QPoint mapFromGlobal(const HWND hwnd, const QPoint &);
+ static inline QPoint mapFromGlobal(const QWindow *w, const QPoint &);
+
+ QSize minimumSize;
+ QSize maximumSize;
+};
+
+struct QWindowCreationContext
+{
+ QWindowCreationContext(const QWindow *w, const QRect &r,
+ DWORD style, DWORD exStyle);
+
+ void applyToMinMaxInfo(MINMAXINFO *mmi) const
+ { geometryHint.applyToMinMaxInfo(style, exStyle, mmi); }
+
+ QWindowsGeometryHint geometryHint;
+ DWORD style;
+ DWORD exStyle;
+ QRect requestedGeometry;
+ QRect obtainedGeometry;
+ QMargins margins;
+ int frameX; // Passed on to CreateWindowEx(), including frame.
+ int frameY;
+ int frameWidth;
+ int frameHeight;
+};
+
+class QWindowsWindow : public QPlatformWindow
+{
+public:
+ enum Flags
+ {
+ OpenGL_Surface = 0x1,
+ WithinWmPaint = 0x2,
+ PixelFormatInitialized = 0x4,
+ FrameDirty = 0x8 //! Frame outdated by setStyle, recalculate in next query.
+ };
+
+ struct WindowData
+ {
+ WindowData() : hwnd(0) {}
+
+ Qt::WindowFlags flags;
+ QRect geometry;
+ QMargins frame; // Do not use directly for windows, see FrameDirty.
+ HWND hwnd;
+
+ static WindowData create(const QWindow *w,
+ const WindowData &parameters,
+ const QString &title,
+ bool isGL);
+ };
+
+ QWindowsWindow(QWindow *window, const WindowData &data);
+ ~QWindowsWindow();
+
+ virtual void setGeometry(const QRect &rect);
+ virtual QRect geometry() const { return m_data.geometry; }
+
+ virtual void setVisible(bool visible);
+ bool isVisible() const;
+ virtual Qt::WindowFlags setWindowFlags(Qt::WindowFlags flags);
+ virtual Qt::WindowState setWindowState(Qt::WindowState state);
+
+ HWND handle() const { return m_data.hwnd; }
+
+ virtual WId winId() const { return WId(m_data.hwnd); }
+ virtual void setParent(const QPlatformWindow *window);
+
+ virtual void setWindowTitle(const QString &title);
+ virtual void raise();
+ virtual void lower();
+
+ virtual void propagateSizeHints();
+ virtual QMargins frameMargins() const;
+
+ virtual void setOpacity(qreal level);
+ virtual void requestActivateWindow();
+
+ virtual bool setKeyboardGrabEnabled(bool grab);
+ virtual bool setMouseGrabEnabled(bool grab);
+
+ Qt::WindowState windowState_sys() const;
+ Qt::WindowStates windowStates_sys() const;
+
+ inline unsigned style() const
+ { return GetWindowLongPtr(m_data.hwnd, GWL_STYLE); }
+ void setStyle(unsigned s) const;
+ inline unsigned exStyle() const
+ { return GetWindowLongPtr(m_data.hwnd, GWL_EXSTYLE); }
+ void setExStyle(unsigned s) const;
+
+ void handleWmPaint(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+
+ void handleMoved();
+ void handleResized(int wParam);
+ void handleShown();
+ void handleHidden();
+
+ static inline HWND handleOf(const QWindow *w);
+ static inline QWindowsWindow *baseWindowOf(const QWindow *w);
+ static QWindow *topLevelOf(QWindow *w);
+ static inline void *userDataOf(HWND hwnd);
+ static inline void setUserDataOf(HWND hwnd, void *ud);
+
+ HDC getDC();
+ void releaseDC();
+
+ void getSizeHints(MINMAXINFO *mmi) const;
+
+ QWindowsWindowCursor cursor() const { return m_cursor; }
+ void setCursor(const QWindowsWindowCursor &c);
+ void applyCursor();
+
+ QWindowsWindow *childAt(const QPoint &clientPoint,
+ unsigned cwexflags = CWP_SKIPINVISIBLE) const;
+ QWindowsWindow *childAtScreenPoint(const QPoint &screenPoint,
+ unsigned cwexflags = CWP_SKIPINVISIBLE) const;
+
+ static QByteArray debugWindowFlags(Qt::WindowFlags wf);
+
+ inline bool testFlag(unsigned f) const { return (m_flags & f) != 0; }
+ inline void setFlag(unsigned f) const { m_flags |= f; }
+ inline void clearFlag(unsigned f) const { m_flags &= ~f; }
+
+private:
+ inline void show_sys() const;
+ inline void hide_sys() const;
+ inline void setGeometry_sys(const QRect &rect) const;
+ inline QRect geometry_sys() const;
+ inline WindowData setWindowFlags_sys(Qt::WindowFlags wt) const;
+ inline void setWindowState_sys(Qt::WindowState newState);
+ inline void setParent_sys(const QPlatformWindow *parent) const;
+ inline void setOpacity_sys(qreal level) const;
+ inline void setMouseGrabEnabled_sys(bool grab);
+ void destroyWindow();
+ void registerDropSite();
+ void unregisterDropSite();
+ void handleGeometryChange();
+ void handleWindowStateChange(Qt::WindowState state);
+
+ mutable WindowData m_data;
+ mutable unsigned m_flags;
+ HDC m_hdc;
+ Qt::WindowState m_windowState;
+ qreal m_opacity;
+ bool m_mouseGrab;
+ QWindowsWindowCursor m_cursor;
+ QWindowsOleDropTarget *m_dropTarget;
+};
+
+// Conveniences for window frames.
+inline QRect operator+(const QRect &r, const QMargins &m)
+{
+ return r.adjusted(-m.left(), -m.top(), m.right(), m.bottom());
+}
+
+inline QRect operator-(const QRect &r, const QMargins &m)
+{
+ return r.adjusted(m.left(), m.top(), -m.right(), -m.bottom());
+}
+
+// Debug
+QDebug operator<<(QDebug d, const RECT &r);
+QDebug operator<<(QDebug d, const MINMAXINFO &i);
+QDebug operator<<(QDebug d, const NCCALCSIZE_PARAMS &p);
+
+// ---------- QWindowsGeometryHint inline functions.
+QPoint QWindowsGeometryHint::mapToGlobal(HWND hwnd, const QPoint &qp)
+{
+ POINT p = { qp.x(), qp.y() };
+ ClientToScreen(hwnd, &p);
+ return QPoint(p.x, p.y);
+}
+
+QPoint QWindowsGeometryHint::mapFromGlobal(const HWND hwnd, const QPoint &qp)
+{
+ POINT p = { qp.x(), qp.y() };
+ ScreenToClient(hwnd, &p);
+ return QPoint(p.x, p.y);
+}
+
+QPoint QWindowsGeometryHint::mapToGlobal(const QWindow *w, const QPoint &p)
+ { return QWindowsGeometryHint::mapToGlobal(QWindowsWindow::handleOf(w), p); }
+
+QPoint QWindowsGeometryHint::mapFromGlobal(const QWindow *w, const QPoint &p)
+ { return QWindowsGeometryHint::mapFromGlobal(QWindowsWindow::handleOf(w), p); }
+
+
+// ---------- QWindowsBaseWindow inline functions.
+
+QWindowsWindow *QWindowsWindow::baseWindowOf(const QWindow *w)
+{
+ if (w)
+ if (QPlatformWindow *pw = w->handle())
+ return static_cast<QWindowsWindow *>(pw);
+ return 0;
+}
+
+HWND QWindowsWindow::handleOf(const QWindow *w)
+{
+ if (const QWindowsWindow *bw = QWindowsWindow::baseWindowOf(w))
+ return bw->handle();
+ return 0;
+}
+
+void *QWindowsWindow::userDataOf(HWND hwnd)
+{
+ return (void *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+}
+
+void QWindowsWindow::setUserDataOf(HWND hwnd, void *ud)
+{
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, LONG_PTR(ud));
+}
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSWINDOW_H
diff --git a/src/plugins/platforms/windows/windows.pro b/src/plugins/platforms/windows/windows.pro
new file mode 100644
index 0000000000..c9be003984
--- /dev/null
+++ b/src/plugins/platforms/windows/windows.pro
@@ -0,0 +1,70 @@
+TARGET = windows
+load(qt_plugin)
+
+QT *= core-private
+QT *= gui-private
+
+INCLUDEPATH += ../../../3rdparty/harfbuzz/src
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/platforms
+
+# Note: OpenGL32 must precede Gdi32 as it overwrites some functions.
+LIBS *= -lOpenGL32 -lGdi32 -lUser32 -lOle32 -lWinspool
+win32-g++: LIBS *= -luuid
+
+contains(QT_CONFIG, directwrite) {
+ LIBS *= -ldwrite
+ SOURCES += qwindowsfontenginedirectwrite.cpp
+ HEADERS += qwindowsfontenginedirectwrite.h
+} else {
+ DEFINES *= QT_NO_DIRECTWRITE
+}
+
+SOURCES += \
+ main.cpp \
+ qwindowsnativeimage.cpp \
+ qwindowswindow.cpp \
+ qwindowsintegration.cpp \
+ qwindowscontext.cpp \
+ qwindowsbackingstore.cpp \
+ qwindowsscreen.cpp \
+ qwindowsprintersupport.cpp \
+ qwindowskeymapper.cpp \
+ qwindowsfontengine.cpp \
+ qwindowsfontdatabase.cpp \
+ qwindowsmousehandler.cpp \
+ qwindowsguieventdispatcher.cpp \
+ qwindowsglcontext.cpp \
+ qwindowsclipboard.cpp \
+ qwindowsole.cpp \
+ qwindowsmime.cpp \
+ qwindowsdrag.cpp \
+ qwindowscursor.cpp \
+ pixmaputils.cpp
+
+HEADERS += \
+ qwindowsnativeimage.h \
+ qwindowswindow.h \
+ qwindowsintegration.h \
+ qwindowscontext.h \
+ qwindowsbackingstore.h \
+ qwindowsscreen.h \
+ qwindowsprintersupport.h \
+ qwindowskeymapper.h \
+ qwindowsfontengine.h \
+ qwindowsfontdatabase.h \
+ qwindowsmousehandler.h \
+ qwindowsguieventdispatcher.h \
+ qtwindowsglobal.h \
+ qtwindows_additional.h \
+ qwindowsglcontext.h \
+ qwindowsclipboard.h \
+ qwindowsole.h \
+ qwindowsmime.h \
+ qwindowsdrag.h \
+ qwindowsinternalmimedata.h \
+ qwindowscursor.h \
+ pixmaputils.h \
+ array.h
+
+target.path += $$[QT_INSTALL_PLUGINS]/platforms
+INSTALLS += target