blob: 47ac41a791426c800581aa88758c54c015ce7547 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtWidgets module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtWidgets/private/qtwidgetsglobal_p.h>
#if QT_CONFIG(style_windowsvista)
#include "qwizard_win_p.h"
#include <private/qapplication_p.h>
#include <qpa/qplatformnativeinterface.h>
#include "qwizard.h"
#include "qpaintengine.h"
#include "qapplication.h"
#include <QtCore/QOperatingSystemVersion>
#include <QtCore/QVariant>
#include <QtCore/QDebug>
#include <QtGui/QMouseEvent>
#include <QtGui/QWindow>
#include <QtWidgets/QDesktopWidget>
#include <uxtheme.h>
#include <vssym32.h>
#include <dwmapi.h>
Q_DECLARE_METATYPE(QMargins)
#ifndef WM_DWMCOMPOSITIONCHANGED
# define WM_DWMCOMPOSITIONCHANGED 0x031E
#endif
QT_BEGIN_NAMESPACE
int QVistaHelper::instanceCount = 0;
int QVistaHelper::m_devicePixelRatio = 1;
QVistaHelper::VistaState QVistaHelper::cachedVistaState = QVistaHelper::Dirty;
/******************************************************************************
** QVistaBackButton
*/
QVistaBackButton::QVistaBackButton(QWidget *widget)
: QAbstractButton(widget)
{
setFocusPolicy(Qt::NoFocus);
// Native dialogs use ALT-Left even in RTL mode, so do the same, even if it might be counter-intuitive.
#if QT_CONFIG(shortcut)
setShortcut(QKeySequence(Qt::ALT | Qt::Key_Left));
#endif
}
QSize QVistaBackButton::sizeHint() const
{
ensurePolished();
int size = int(QStyleHelper::dpiScaled(32, this));
int width = size, height = size;
return QSize(width, height);
}
void QVistaBackButton::enterEvent(QEvent *event)
{
if (isEnabled())
update();
QAbstractButton::enterEvent(event);
}
void QVistaBackButton::leaveEvent(QEvent *event)
{
if (isEnabled())
update();
QAbstractButton::leaveEvent(event);
}
void QVistaBackButton::paintEvent(QPaintEvent *)
{
QPainter p(this);
QRect r = rect();
const HANDLE theme = OpenThemeData(0, L"Navigation");
//RECT rect;
QPoint origin;
const HDC hdc = QVistaHelper::backingStoreDC(parentWidget(), &origin);
RECT clipRect;
int xoffset = origin.x() + QWidget::mapToParent(r.topLeft()).x() - 1;
int yoffset = origin.y() + QWidget::mapToParent(r.topLeft()).y() - 1;
const int dpr = devicePixelRatio();
const QRect rDp = QRect(r.topLeft() * dpr, r.size() * dpr);
const int xoffsetDp = xoffset * dpr;
const int yoffsetDp = yoffset * dpr;
clipRect.top = rDp.top() + yoffsetDp;
clipRect.bottom = rDp.bottom() + yoffsetDp;
clipRect.left = rDp.left() + xoffsetDp;
clipRect.right = rDp.right() + xoffsetDp;
int state = NAV_BB_NORMAL;
if (!isEnabled())
state = NAV_BB_DISABLED;
else if (isDown())
state = NAV_BB_PRESSED;
else if (underMouse())
state = NAV_BB_HOT;
DrawThemeBackground(theme, hdc,
layoutDirection() == Qt::LeftToRight ? NAV_BACKBUTTON : NAV_FORWARDBUTTON,
state, &clipRect, &clipRect);
}
/******************************************************************************
** QVistaHelper
*/
QVistaHelper::QVistaHelper(QWizard *wizard)
: QObject(wizard)
, pressed(false)
, wizard(wizard)
, backButton_(0)
{
QVistaHelper::m_devicePixelRatio = wizard->devicePixelRatio();
if (instanceCount++ == 0)
cachedVistaState = Dirty;
backButton_ = new QVistaBackButton(wizard);
backButton_->hide();
iconSpacing = QStyleHelper::dpiScaled(7, wizard);
}
QVistaHelper::~QVistaHelper()
{
--instanceCount;
}
void QVistaHelper::updateCustomMargins(bool vistaMargins)
{
if (QWindow *window = wizard->windowHandle()) {
// Reduce top frame to zero since we paint it ourselves. Use
// device pixel to avoid rounding errors.
const QMargins customMarginsDp = vistaMargins
? QMargins(0, -titleBarSizeDp(), 0, 0)
: QMargins();
const QVariant customMarginsV = QVariant::fromValue(customMarginsDp);
// The dynamic property takes effect when creating the platform window.
window->setProperty("_q_windowsCustomMargins", customMarginsV);
// If a platform window exists, change via native interface.
if (QPlatformWindow *platformWindow = window->handle()) {
QGuiApplication::platformNativeInterface()->
setWindowProperty(platformWindow, QStringLiteral("WindowsCustomMargins"),
customMarginsV);
}
}
}
bool QVistaHelper::isCompositionEnabled()
{
BOOL bEnabled;
return SUCCEEDED(DwmIsCompositionEnabled(&bEnabled)) && bEnabled;
}
bool QVistaHelper::isThemeActive()
{
return IsThemeActive();
}
QVistaHelper::VistaState QVistaHelper::vistaState()
{
if (instanceCount == 0 || cachedVistaState == Dirty)
cachedVistaState =
isCompositionEnabled() ? VistaAero : isThemeActive() ? VistaBasic : Classic;
return cachedVistaState;
}
void QVistaHelper::disconnectBackButton()
{
if (backButton_) // Leave QStyleSheetStyle's connections on destroyed() intact.
backButton_->disconnect(SIGNAL(clicked()));
}
QColor QVistaHelper::basicWindowFrameColor()
{
DWORD rgb;
const HANDLE hTheme = OpenThemeData(GetDesktopWindow(), L"WINDOW");
GetThemeColor(hTheme, WP_CAPTION, CS_ACTIVE,
wizard->isActiveWindow() ? TMT_FILLCOLORHINT : TMT_BORDERCOLORHINT, &rgb);
BYTE r = GetRValue(rgb);
BYTE g = GetGValue(rgb);
BYTE b = GetBValue(rgb);
return QColor(r, g, b);
}
bool QVistaHelper::setDWMTitleBar(TitleBarChangeType type)
{
bool value = false;
if (vistaState() == VistaAero) {
MARGINS mar = {0, 0, 0, 0};
if (type == NormalTitleBar)
mar.cyTopHeight = 0;
else
mar.cyTopHeight = (titleBarSize() + topOffset(wizard)) * QVistaHelper::m_devicePixelRatio;
if (const HWND wizardHandle = wizardHWND())
if (SUCCEEDED(DwmExtendFrameIntoClientArea(wizardHandle, &mar)))
value = true;
}
return value;
}
Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &);
static LOGFONT getCaptionLogFont(HANDLE hTheme)
{
LOGFONT result = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, { 0 } };
if (!hTheme || FAILED(GetThemeSysFont(hTheme, TMT_CAPTIONFONT, &result))) {
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(NONCLIENTMETRICS);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, false);
result = ncm.lfMessageFont;
}
return result;
}
static bool getCaptionQFont(int dpi, QFont *result)
{
const HANDLE hTheme = OpenThemeData(GetDesktopWindow(), L"WINDOW");
if (!hTheme)
return false;
// Call into QWindowsNativeInterface to convert the LOGFONT into a QFont.
const LOGFONT logFont = getCaptionLogFont(hTheme);
QPlatformNativeInterface *ni = QGuiApplication::platformNativeInterface();
return ni && QMetaObject::invokeMethod(ni, "logFontToQFont", Qt::DirectConnection,
Q_RETURN_ARG(QFont, *result),
Q_ARG(const void*, &logFont),
Q_ARG(int, dpi));
}
void QVistaHelper::drawTitleBar(QPainter *painter)
{
Q_ASSERT(backButton_);
QPoint origin;
const bool isWindow = wizard->isWindow();
const HDC hdc = QVistaHelper::backingStoreDC(wizard, &origin);
if (vistaState() == VistaAero && isWindow)
drawBlackRect(QRect(0, 0, wizard->width(),
titleBarSize() + topOffset(wizard)), hdc);
// The button is positioned in QWizardPrivate::handleAeroStyleChange(),
// all calculation is relative to it.
const int btnTop = backButton_->mapToParent(QPoint()).y();
const int btnHeight = backButton_->size().height();
const int verticalCenter = (btnTop + btnHeight / 2) - 1;
const QString text = wizard->window()->windowTitle();
QFont font;
if (!isWindow || !getCaptionQFont(wizard->logicalDpiY() * wizard->devicePixelRatio(), &font))
font = QApplication::font("QMdiSubWindowTitleBar");
const QFontMetrics fontMetrics(font);
const QRect brect = fontMetrics.boundingRect(text);
int textHeight = brect.height();
int textWidth = brect.width();
int glowOffset = 0;
if (vistaState() == VistaAero) {
glowOffset = glowSize(wizard);
textHeight += 2 * glowOffset;
textWidth += 2 * glowOffset;
}
const int titleLeft = (wizard->layoutDirection() == Qt::LeftToRight
? titleOffset() - glowOffset
: wizard->width() - titleOffset() - textWidth + glowOffset);
const QRect textRectangle(titleLeft, verticalCenter - textHeight / 2, textWidth, textHeight);
if (isWindow) {
drawTitleText(painter, text, textRectangle, hdc);
} else {
painter->save();
painter->setFont(font);
painter->drawText(textRectangle, Qt::AlignVCenter | Qt::AlignHCenter, text);
painter->restore();
}
const QIcon windowIcon = wizard->windowIcon();
if (!windowIcon.isNull()) {
const int size = QVistaHelper::iconSize(wizard);
const int iconLeft = (wizard->layoutDirection() == Qt::LeftToRight
? leftMargin(wizard)
: wizard->width() - leftMargin(wizard) - size);
const QPoint pos(origin.x() + iconLeft, origin.y() + verticalCenter - size / 2);
const QPoint posDp = pos * QVistaHelper::m_devicePixelRatio;
const HICON hIcon = qt_pixmapToWinHICON(windowIcon.pixmap(size * QVistaHelper::m_devicePixelRatio));
DrawIconEx(hdc, posDp.x(), posDp.y(), hIcon, 0, 0, 0, NULL, DI_NORMAL | DI_COMPAT);
DestroyIcon(hIcon);
}
}
void QVistaHelper::setTitleBarIconAndCaptionVisible(bool visible)
{
WTA_OPTIONS opt;
opt.dwFlags = WTNCA_NODRAWICON | WTNCA_NODRAWCAPTION;
if (visible)
opt.dwMask = 0;
else
opt.dwMask = WTNCA_NODRAWICON | WTNCA_NODRAWCAPTION;
if (const HWND handle = wizardHWND())
SetWindowThemeAttribute(handle, WTA_NONCLIENT, &opt, sizeof(WTA_OPTIONS));
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
bool QVistaHelper::winEvent(MSG* msg, qintptr *result)
#else
bool QVistaHelper::winEvent(MSG* msg, long* result)
#endif
{
switch (msg->message) {
case WM_NCHITTEST: {
LRESULT lResult;
// Perform hit testing using DWM
if (DwmDefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam, &lResult)) {
// DWM returned a hit, no further processing necessary
*result = lResult;
} else {
// DWM didn't return a hit, process using DefWindowProc
lResult = DefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam);
// If DefWindowProc returns a window caption button, just return HTCLIENT (client area).
// This avoid unnecessary hits to Windows NT style caption buttons which aren't visible but are
// located just under the Aero style window close button.
if (lResult == HTCLOSE || lResult == HTMAXBUTTON || lResult == HTMINBUTTON || lResult == HTHELP)
*result = HTCLIENT;
else
*result = lResult;
}
break;
}
default:
LRESULT lResult;
// Pass to DWM to handle
if (DwmDefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam, &lResult))
*result = lResult;
// If the message wasn't handled by DWM, continue processing it as normal
else
return false;
}
return true;
}
void QVistaHelper::setMouseCursor(QPoint pos)
{
#ifndef QT_NO_CURSOR
if (rtTop.contains(pos))
wizard->setCursor(Qt::SizeVerCursor);
else
wizard->setCursor(Qt::ArrowCursor);
#endif
}
void QVistaHelper::mouseEvent(QEvent *event)
{
switch (event->type()) {
case QEvent::MouseMove:
mouseMoveEvent(static_cast<QMouseEvent *>(event));
break;
case QEvent::MouseButtonPress:
mousePressEvent(static_cast<QMouseEvent *>(event));
break;
case QEvent::MouseButtonRelease:
mouseReleaseEvent(static_cast<QMouseEvent *>(event));
break;
default:
break;
}
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
bool QVistaHelper::handleWinEvent(MSG *message, qintptr *result)
#else
bool QVistaHelper::handleWinEvent(MSG *message, long *result)
#endif
{
if (message->message == WM_THEMECHANGED || message->message == WM_DWMCOMPOSITIONCHANGED)
cachedVistaState = Dirty;
bool status = false;
if (wizard->wizardStyle() == QWizard::AeroStyle && vistaState() == VistaAero) {
status = winEvent(message, result);
if (message->message == WM_NCPAINT)
wizard->update();
}
return status;
}
void QVistaHelper::resizeEvent(QResizeEvent * event)
{
Q_UNUSED(event);
rtTop = QRect (0, 0, wizard->width(), frameSize());
int height = captionSize() + topOffset(wizard);
if (vistaState() == VistaBasic)
height -= titleBarSize();
rtTitle = QRect (0, frameSize(), wizard->width(), height);
}
void QVistaHelper::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
QPainter painter(wizard);
drawTitleBar(&painter);
}
void QVistaHelper::mouseMoveEvent(QMouseEvent *event)
{
if (wizard->windowState() & Qt::WindowMaximized) {
event->ignore();
return;
}
QRect rect = wizard->geometry();
if (pressed) {
switch (change) {
case resizeTop:
{
const int dy = event->pos().y() - pressedPos.y();
if ((dy > 0 && rect.height() > wizard->minimumHeight())
|| (dy < 0 && rect.height() < wizard->maximumHeight()))
rect.setTop(rect.top() + dy);
}
break;
case movePosition: {
QPoint newPos = event->pos() - pressedPos;
rect.moveLeft(rect.left() + newPos.x());
rect.moveTop(rect.top() + newPos.y());
break; }
default:
break;
}
wizard->setGeometry(rect);
} else if (vistaState() == VistaAero) {
setMouseCursor(event->pos());
}
event->ignore();
}
void QVistaHelper::mousePressEvent(QMouseEvent *event)
{
change = noChange;
if (event->button() != Qt::LeftButton || wizard->windowState() & Qt::WindowMaximized) {
event->ignore();
return;
}
if (rtTitle.contains(event->pos())) {
change = movePosition;
} else if (rtTop.contains(event->pos()))
change = (vistaState() == VistaAero) ? resizeTop : movePosition;
if (change != noChange) {
if (vistaState() == VistaAero)
setMouseCursor(event->pos());
pressed = true;
pressedPos = event->pos();
} else {
event->ignore();
}
}
void QVistaHelper::mouseReleaseEvent(QMouseEvent *event)
{
change = noChange;
if (pressed) {
pressed = false;
wizard->releaseMouse();
if (vistaState() == VistaAero)
setMouseCursor(event->pos());
}
event->ignore();
}
bool QVistaHelper::eventFilter(QObject *obj, QEvent *event)
{
if (obj != wizard)
return QObject::eventFilter(obj, event);
if (event->type() == QEvent::MouseMove) {
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
qintptr result;
#else
long result;
#endif
MSG msg;
msg.message = WM_NCHITTEST;
msg.wParam = 0;
msg.lParam = MAKELPARAM(mouseEvent->globalX(), mouseEvent->globalY());
msg.hwnd = wizardHWND();
winEvent(&msg, &result);
msg.wParam = result;
msg.message = WM_NCMOUSEMOVE;
winEvent(&msg, &result);
} else if (event->type() == QEvent::MouseButtonPress) {
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
if (mouseEvent->button() == Qt::LeftButton) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
qintptr result;
#else
long result;
#endif
MSG msg;
msg.message = WM_NCHITTEST;
msg.wParam = 0;
msg.lParam = MAKELPARAM(mouseEvent->globalX(), mouseEvent->globalY());
msg.hwnd = wizardHWND();
winEvent(&msg, &result);
msg.wParam = result;
msg.message = WM_NCLBUTTONDOWN;
winEvent(&msg, &result);
}
} else if (event->type() == QEvent::MouseButtonRelease) {
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
if (mouseEvent->button() == Qt::LeftButton) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
qintptr result;
#else
long result;
#endif
MSG msg;
msg.message = WM_NCHITTEST;
msg.wParam = 0;
msg.lParam = MAKELPARAM(mouseEvent->globalX(), mouseEvent->globalY());
msg.hwnd = wizardHWND();
winEvent(&msg, &result);
msg.wParam = result;
msg.message = WM_NCLBUTTONUP;
winEvent(&msg, &result);
}
}
return false;
}
// Return a HDC for the wizard along with the transformation if the
// wizard is a child window.
HDC QVistaHelper::backingStoreDC(const QWidget *wizard, QPoint *offset)
{
HDC hdc = static_cast<HDC>(QGuiApplication::platformNativeInterface()->nativeResourceForBackingStore(QByteArrayLiteral("getDC"), wizard->backingStore()));
*offset = QPoint(0, 0);
if (!wizard->windowHandle())
if (QWidget *nativeParent = wizard->nativeParentWidget())
*offset = wizard->mapTo(nativeParent, *offset);
return hdc;
}
HWND QVistaHelper::wizardHWND() const
{
// Obtain the HWND if the wizard is a top-level window.
// Do not use winId() as this enforces native children of the parent
// widget when called before show() as happens when calling setWizardStyle().
if (QWindow *window = wizard->windowHandle())
if (window->handle())
if (void *vHwnd = QGuiApplication::platformNativeInterface()->nativeResourceForWindow(QByteArrayLiteral("handle"), window))
return static_cast<HWND>(vHwnd);
qWarning().nospace() << "Failed to obtain HWND for wizard.";
return 0;
}
bool QVistaHelper::drawTitleText(QPainter *painter, const QString &text, const QRect &rect, HDC hdc)
{
bool value = false;
if (vistaState() == VistaAero) {
const QRect rectDp = QRect(rect.topLeft() * QVistaHelper::m_devicePixelRatio,
rect.size() * QVistaHelper::m_devicePixelRatio);
const HANDLE hTheme = OpenThemeData(GetDesktopWindow(), L"WINDOW");
if (!hTheme) return false;
// Set up a memory DC and bitmap that we'll draw into
HDC dcMem;
HBITMAP bmp;
BITMAPINFO dib;
ZeroMemory(&dib, sizeof(dib));
dcMem = CreateCompatibleDC(hdc);
dib.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
dib.bmiHeader.biWidth = rectDp.width();
dib.bmiHeader.biHeight = -rectDp.height();
dib.bmiHeader.biPlanes = 1;
dib.bmiHeader.biBitCount = 32;
dib.bmiHeader.biCompression = BI_RGB;
bmp = CreateDIBSection(hdc, &dib, DIB_RGB_COLORS, NULL, NULL, 0);
// Set up the DC
const LOGFONT captionLogFont = getCaptionLogFont(hTheme);
const HFONT hCaptionFont = CreateFontIndirect(&captionLogFont);
auto hOldBmp = reinterpret_cast<HBITMAP>(SelectObject(dcMem, (HGDIOBJ) bmp));
auto hOldFont = reinterpret_cast<HFONT>(SelectObject(dcMem, (HGDIOBJ) hCaptionFont));
// Draw the text!
DTTOPTS dto;
memset(&dto, 0, sizeof(dto));
dto.dwSize = sizeof(dto);
const UINT uFormat = DT_SINGLELINE|DT_CENTER|DT_VCENTER|DT_NOPREFIX;
RECT rctext ={0,0, rectDp.width(), rectDp.height()};
dto.dwFlags = DTT_COMPOSITED|DTT_GLOWSIZE;
dto.iGlowSize = glowSize(wizard);
DrawThemeTextEx(hTheme, dcMem, 0, 0, reinterpret_cast<LPCWSTR>(text.utf16()), -1, uFormat, &rctext, &dto );
BitBlt(hdc, rectDp.left(), rectDp.top(), rectDp.width(), rectDp.height(), dcMem, 0, 0, SRCCOPY);
SelectObject(dcMem, (HGDIOBJ) hOldBmp);
SelectObject(dcMem, (HGDIOBJ) hOldFont);
DeleteObject(bmp);
DeleteObject(hCaptionFont);
DeleteDC(dcMem);
//ReleaseDC(hwnd, hdc);
} else if (vistaState() == VistaBasic) {
painter->drawText(rect, text);
}
return value;
}
bool QVistaHelper::drawBlackRect(const QRect &rect, HDC hdc)
{
bool value = false;
if (vistaState() == VistaAero) {
// Set up a memory DC and bitmap that we'll draw into
const QRect rectDp = QRect(rect.topLeft() * QVistaHelper::m_devicePixelRatio,
rect.size() * QVistaHelper::m_devicePixelRatio);
HDC dcMem;
HBITMAP bmp;
BITMAPINFO dib;
ZeroMemory(&dib, sizeof(dib));
dcMem = CreateCompatibleDC(hdc);
dib.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
dib.bmiHeader.biWidth = rectDp.width();
dib.bmiHeader.biHeight = -rectDp.height();
dib.bmiHeader.biPlanes = 1;
dib.bmiHeader.biBitCount = 32;
dib.bmiHeader.biCompression = BI_RGB;
bmp = CreateDIBSection(hdc, &dib, DIB_RGB_COLORS, NULL, NULL, 0);
auto hOldBmp = reinterpret_cast<HBITMAP>(SelectObject(dcMem, (HGDIOBJ) bmp));
BitBlt(hdc, rectDp.left(), rectDp.top(), rectDp.width(), rectDp.height(), dcMem, 0, 0, SRCCOPY);
SelectObject(dcMem, (HGDIOBJ) hOldBmp);
DeleteObject(bmp);
DeleteDC(dcMem);
}
return value;
}
#ifndef Q_CC_MSVC
static inline int getWindowBottomMargin()
{
return GetSystemMetrics(SM_CYSIZEFRAME);
}
#else
// QTBUG-36192, GetSystemMetrics(SM_CYSIZEFRAME) returns bogus values
// for MSVC2012 which leads to the custom margin having no effect since
// that only works when removing the entire margin.
static inline int getWindowBottomMargin()
{
RECT rect = {0, 0, 0, 0};
AdjustWindowRectEx(&rect, WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_THICKFRAME | WS_DLGFRAME, FALSE, 0);
return qAbs(rect.bottom);
}
#endif // Q_CC_MSVC
int QVistaHelper::frameSizeDp()
{
return getWindowBottomMargin();
}
int QVistaHelper::captionSizeDp()
{
return GetSystemMetrics(SM_CYCAPTION);
}
int QVistaHelper::titleOffset()
{
int iconOffset = wizard ->windowIcon().isNull() ? 0 : iconSize(wizard) + iconSpacing;
return leftMargin(wizard) + iconOffset;
}
int QVistaHelper::iconSize(const QPaintDevice *device)
{
return QStyleHelper::dpiScaled(16, device); // Standard Aero
}
int QVistaHelper::glowSize(const QPaintDevice *device)
{
return QStyleHelper::dpiScaled(10, device);
}
int QVistaHelper::topOffset(const QPaintDevice *device)
{
if (vistaState() != VistaAero)
return titleBarSize() + 3;
static const int aeroOffset =
QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8 ?
QStyleHelper::dpiScaled(4, device) : QStyleHelper::dpiScaled(13, device);
return aeroOffset + titleBarSize();
}
QT_END_NAMESPACE
#endif // style_windowsvista