Add Windows to the Lighthouse.

Add an initial Lighthouse plugin for the Windows operating system.

Change-Id: I6934562266e1aa0ac270bf6107df05a9e56ef82c
Reviewed-on: http://codereview.qt.nokia.com/3107
Reviewed-by: Oliver Wolff <oliver.wolff@nokia.com>
Reviewed-by: Samuel Rødal <samuel.rodal@nokia.com>
bb10
Friedemann Kleint 2011-08-17 15:58:39 +02:00
parent 6136a792bc
commit 0b8d080421
48 changed files with 15324 additions and 0 deletions

View File

@ -13,3 +13,5 @@ contains(QT_CONFIG, xcb) {
mac {
SUBDIRS += cocoa
}
win32: SUBDIRS += windows

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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