Add Windows to the Lighthouse.
authorFriedemann Kleint <Friedemann.Kleint@nokia.com>
Wed, 17 Aug 2011 13:58:39 +0000 (15:58 +0200)
committerFriedemann Kleint <Friedemann.Kleint@nokia.com>
Thu, 18 Aug 2011 10:00:46 +0000 (12:00 +0200)
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>
48 files changed:
src/plugins/platforms/platforms.pro
src/plugins/platforms/windows/array.h [new file with mode: 0644]
src/plugins/platforms/windows/main.cpp [new file with mode: 0644]
src/plugins/platforms/windows/pixmaputils.cpp [new file with mode: 0644]
src/plugins/platforms/windows/pixmaputils.h [new file with mode: 0644]
src/plugins/platforms/windows/qtwindows_additional.h [new file with mode: 0644]
src/plugins/platforms/windows/qtwindowsglobal.h [new file with mode: 0644]
src/plugins/platforms/windows/qwindows.qdocconf [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsbackingstore.cpp [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsbackingstore.h [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsclipboard.cpp [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsclipboard.h [new file with mode: 0644]
src/plugins/platforms/windows/qwindowscontext.cpp [new file with mode: 0644]
src/plugins/platforms/windows/qwindowscontext.h [new file with mode: 0644]
src/plugins/platforms/windows/qwindowscursor.cpp [new file with mode: 0644]
src/plugins/platforms/windows/qwindowscursor.h [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsdrag.cpp [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsdrag.h [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsfontdatabase.cpp [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsfontdatabase.h [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsfontengine.cpp [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsfontengine.h [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsglcontext.cpp [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsglcontext.h [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsguieventdispatcher.h [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsintegration.cpp [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsintegration.h [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsinternalmimedata.h [new file with mode: 0644]
src/plugins/platforms/windows/qwindowskeymapper.cpp [new file with mode: 0644]
src/plugins/platforms/windows/qwindowskeymapper.h [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsmime.cpp [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsmime.h [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsmousehandler.cpp [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsmousehandler.h [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsnativeimage.cpp [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsnativeimage.h [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsole.cpp [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsole.h [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsprintersupport.cpp [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsprintersupport.h [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsscreen.cpp [new file with mode: 0644]
src/plugins/platforms/windows/qwindowsscreen.h [new file with mode: 0644]
src/plugins/platforms/windows/qwindowswindow.cpp [new file with mode: 0644]
src/plugins/platforms/windows/qwindowswindow.h [new file with mode: 0644]
src/plugins/platforms/windows/windows.pro [new file with mode: 0644]

index 9d7ae29..ac001b6 100644 (file)
@@ -13,3 +13,5 @@ contains(QT_CONFIG, xcb) {
 mac {
     SUBDIRS += cocoa
 }
+
+win32: SUBDIRS += windows
diff --git a/src/plugins/platforms/windows/array.h b/src/plugins/platforms/windows/array.h
new file mode 100644 (file)
index 0000000..216f1e8
--- /dev/null
@@ -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 (file)
index 0000000..933aa76
--- /dev/null
@@ -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 (file)
index 0000000..111df5a
--- /dev/null
@@ -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 (file)
index 0000000..bf94a26
--- /dev/null
@@ -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 (file)
index 0000000..707d285
--- /dev/null
@@ -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 (file)
index 0000000..792792a
--- /dev/null
@@ -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 (file)
index 0000000..c5a1ee9
--- /dev/null
@@ -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 (file)
index 0000000..a3698c4
--- /dev/null
@@ -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 (file)
index 0000000..53f033d
--- /dev/null
@@ -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 (file)
index 0000000..9306344
--- /dev/null
@@ -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 (file)
index 0000000..fab6871
--- /dev/null
@@ -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 (file)
index 0000000..d62cbfb
--- /dev/null
@@ -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 (file)
index 0000000..8985c7f
--- /dev/null
@@ -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 (file)
index 0000000..1ad2079
--- /dev/null
@@ -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 (file)
index 0000000..bf8cb83
--- /dev/null
@@ -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 (file)
index 0000000..1535437
--- /dev/null
@@ -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 (file)
index 0000000..6e6ebe0
--- /dev/null
@@ -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 (file)
index 0000000..ea35ab5
--- /dev/null
@@ -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 (file)
index 0000000..a80482f
--- /dev/null
@@ -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 (file)
index 0000000..80d9ed4
--- /dev/null
@@ -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 (file)
index 0000000..bed5ecf
--- /dev/null
@@ -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 (file)
index 0000000..46f0b0c
--- /dev/null
@@ -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 (file)
index 0000000..1333720
--- /dev/null
@@ -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 (file)
index 0000000..e67f61a
--- /dev/null
@@ -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 (file)
index 0000000..c5edd89
--- /dev/null
@@ -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 (file)
index 0000000..fcfdd4f
--- /dev/null
@@ -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 (file)
index 0000000..00fd234
--- /dev/null
@@ -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 (file)
index 0000000..a0fada2
--- /dev/null
@@ -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 (file)
index 0000000..a2d3d3a
--- /dev/null
@@ -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 (file)
index 0000000..49fc690
--- /dev/null
@@ -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 (file)
index 0000000..3ec32b2
--- /dev/null
@@ -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 (file)
index 0000000..0d50193
--- /dev/null
@@ -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 (file)
index 0000000..09104a4
--- /dev/null
@@ -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 (file)
index 0000000..85f61a9
--- /dev/null
@@ -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 (file)
index 0000000..dea965b
--- /dev/null
@@ -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 (file)
index 0000000..227a66b
--- /dev/null
@@ -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 (file)
index 0000000..53311c5
--- /dev/null
@@ -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 (file)
index 0000000..c77805a
--- /dev/null
@@ -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 (file)
index 0000000..864dc3d
--- /dev/null
@@ -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 (file)
index 0000000..d979af3
--- /dev/null
@@ -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 (file)
index 0000000..3d43c61
--- /dev/null
@@ -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 (file)
index 0000000..c0a8190
--- /dev/null
@@ -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 (file)
index 0000000..3de508a
--- /dev/null
@@ -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 (file)
index 0000000..e24af7a
--- /dev/null
@@ -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 (file)
index 0000000..95b770f
--- /dev/null
@@ -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 (file)
index 0000000..dfaeb2a
--- /dev/null
@@ -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 (file)
index 0000000..c9be003
--- /dev/null
@@ -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