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
parent
6136a792bc
commit
0b8d080421
|
|
@ -13,3 +13,5 @@ contains(QT_CONFIG, xcb) {
|
|||
mac {
|
||||
SUBDIRS += cocoa
|
||||
}
|
||||
|
||||
win32: SUBDIRS += windows
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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"
|
||||
|
|
@ -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 ®ion,
|
||||
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 ®ion)
|
||||
{
|
||||
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 ®ion)
|
||||
{
|
||||
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
|
||||
|
|
@ -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 ®ion, 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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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, ¶ms);
|
||||
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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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 ¶meters,
|
||||
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
|
||||
|
|
@ -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
|
||||
Loading…
Reference in New Issue