Windows: Start using High DPI API available from Windows 8.1 onwards.

Dynamically load shcore.dll, use SetProcessDpiAwareness() instead
of SetProcessDPIAware() when available. Add command line parameter
to control level.

Task-number: QTBUG-37347
Change-Id: I1259b0943b41e50066e7e3870ed3136afd8f18fe
Reviewed-by: Oliver Wolff <oliver.wolff@digia.com>
bb10
Friedemann Kleint 2014-04-30 11:26:43 +02:00 committed by The Qt Project
parent ae7bbe3400
commit 2e44a9e491
5 changed files with 94 additions and 6 deletions

View File

@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the plugins of the Qt Toolkit.
@ -117,6 +117,14 @@ enum WindowsEventType // Simplify event types
UnknownEvent = 542
};
// Matches Process_DPI_Awareness (Windows 8.1 onwards), used for SetProcessDpiAwareness()
enum ProcessDpiAwareness
{
ProcessDpiUnaware,
ProcessSystemDpiAware,
ProcessPerMonitorDpiAware
};
} // namespace QtWindows
inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamIn)

View File

@ -244,8 +244,26 @@ void QWindowsShell32DLL::init()
sHGetImageList = (SHGetImageList)library.resolve("SHGetImageList");
}
QWindowsShcoreDLL::QWindowsShcoreDLL()
: getProcessDpiAwareness(0)
, setProcessDpiAwareness(0)
, getDpiForMonitor(0)
{
}
void QWindowsShcoreDLL::init()
{
if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS8_1)
return;
QSystemLibrary library(QStringLiteral("SHCore"));
getProcessDpiAwareness = (GetProcessDpiAwareness)library.resolve("GetProcessDpiAwareness");
setProcessDpiAwareness = (SetProcessDpiAwareness)library.resolve("SetProcessDpiAwareness");
getDpiForMonitor = (GetDpiForMonitor)library.resolve("GetDpiForMonitor");
}
QWindowsUser32DLL QWindowsContext::user32dll;
QWindowsShell32DLL QWindowsContext::shell32dll;
QWindowsShcoreDLL QWindowsContext::shcoredll;
#endif // !Q_OS_WINCE
@ -296,9 +314,7 @@ QWindowsContextPrivate::QWindowsContextPrivate()
#ifndef Q_OS_WINCE
QWindowsContext::user32dll.init();
QWindowsContext::shell32dll.init();
// Ensure metrics functions report correct data, QTBUG-30063.
if (QWindowsContext::user32dll.setProcessDPIAware)
QWindowsContext::user32dll.setProcessDPIAware();
QWindowsContext::shcoredll.init();
if (hasTouchSupport(ver) && QWindowsContext::user32dll.initTouch())
m_systemInfo |= QWindowsContext::SI_SupportsTouch;
@ -351,6 +367,25 @@ void QWindowsContext::setTabletAbsoluteRange(int a)
#endif
}
void QWindowsContext::setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiAwareness)
{
#ifndef Q_OS_WINCE
qCDebug(lcQpaWindows) << __FUNCTION__ << dpiAwareness;
if (QWindowsContext::shcoredll.isValid()) {
const HRESULT hr = QWindowsContext::shcoredll.setProcessDpiAwareness(dpiAwareness);
if (FAILED(hr))
qWarning() << "SetProcessDpiAwareness failed:" << QWindowsContext::comErrorString(hr);
} else {
if (dpiAwareness != QtWindows::ProcessDpiUnaware && QWindowsContext::user32dll.setProcessDPIAware) {
if (!QWindowsContext::user32dll.setProcessDPIAware())
qErrnoWarning("SetProcessDPIAware() failed");
}
}
#else // !Q_OS_WINCE
Q_UNUSED(dpiAwareness)
#endif
}
QWindowsContext *QWindowsContext::instance()
{
return m_instance;

View File

@ -126,6 +126,22 @@ struct QWindowsShell32DLL
SHGetStockIconInfo sHGetStockIconInfo;
SHGetImageList sHGetImageList;
};
// Shell scaling library (Windows 8.1 onwards)
struct QWindowsShcoreDLL {
QWindowsShcoreDLL();
void init();
inline bool isValid() const { return getProcessDpiAwareness && setProcessDpiAwareness && getDpiForMonitor; }
typedef HRESULT (WINAPI *GetProcessDpiAwareness)(HANDLE,int);
typedef HRESULT (WINAPI *SetProcessDpiAwareness)(int);
typedef HRESULT (WINAPI *GetDpiForMonitor)(HMONITOR,int,UINT *,UINT *);
GetProcessDpiAwareness getProcessDpiAwareness;
SetProcessDpiAwareness setProcessDpiAwareness;
GetDpiForMonitor getDpiForMonitor;
};
#endif // Q_OS_WINCE
class QWindowsContext
@ -184,6 +200,7 @@ public:
void setWindowCreationContext(const QSharedPointer<QWindowCreationContext> &ctx);
void setTabletAbsoluteRange(int a);
void setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiAwareness);
// Returns a combination of SystemInfoFlags
unsigned systemInfo() const;
@ -197,6 +214,7 @@ public:
#ifndef Q_OS_WINCE
static QWindowsUser32DLL user32dll;
static QWindowsShell32DLL shell32dll;
static QWindowsShcoreDLL shcoredll;
#endif
static QByteArray comErrorString(HRESULT hr);

View File

@ -167,7 +167,8 @@ struct QWindowsIntegrationPrivate
};
static inline unsigned parseOptions(const QStringList &paramList,
int *tabletAbsoluteRange)
int *tabletAbsoluteRange,
QtWindows::ProcessDpiAwareness *dpiAwareness)
{
unsigned options = 0;
foreach (const QString &param, paramList) {
@ -191,6 +192,8 @@ static inline unsigned parseOptions(const QStringList &paramList,
QWindowsContext::verbose = param.right(param.size() - 8).toInt();
} else if (param.startsWith(QLatin1String("tabletabsoluterange="))) {
*tabletAbsoluteRange = param.rightRef(param.size() - 20).toInt();
} else if (param.startsWith(QLatin1String("dpiawareness="))) {
*dpiAwareness = static_cast<QtWindows::ProcessDpiAwareness>(param.rightRef(param.size() - 13).toInt());
}
}
return options;
@ -201,9 +204,13 @@ QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(const QStringList &paramL
, m_fontDatabase(0)
{
int tabletAbsoluteRange = -1;
m_options = parseOptions(paramList, &tabletAbsoluteRange);
// Default to per-monitor awareness to avoid being scaled when monitors with different DPI
// are connected to Windows 8.1
QtWindows::ProcessDpiAwareness dpiAwareness = QtWindows::ProcessPerMonitorDpiAware;
m_options = parseOptions(paramList, &tabletAbsoluteRange, &dpiAwareness);
if (tabletAbsoluteRange >= 0)
m_context.setTabletAbsoluteRange(tabletAbsoluteRange);
m_context.setProcessDpiAwareness(dpiAwareness);
}
QWindowsIntegrationPrivate::~QWindowsIntegrationPrivate()

View File

@ -68,6 +68,21 @@ static inline QDpi deviceDPI(HDC hdc)
return QDpi(GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY));
}
#ifndef Q_OS_WINCE
static inline QDpi monitorDPI(HMONITOR hMonitor)
{
if (QWindowsContext::shcoredll.isValid()) {
UINT dpiX;
UINT dpiY;
if (SUCCEEDED(QWindowsContext::shcoredll.getDpiForMonitor(hMonitor, 0, &dpiX, &dpiY)))
return QDpi(dpiX, dpiY);
}
return QDpi(0, 0);
}
#endif // !Q_OS_WINCE
static inline QSizeF deviceSizeMM(const QSize &pixels, const QDpi &dpi)
{
const qreal inchToMM = 25.4;
@ -110,7 +125,12 @@ BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM
HDC hdc = CreateDC(info.szDevice, NULL, NULL, NULL);
#endif
if (hdc) {
#ifndef Q_OS_WINCE
const QDpi dpi = monitorDPI(hMonitor);
data.dpi = dpi.first ? dpi : deviceDPI(hdc);
#else
data.dpi = deviceDPI(hdc);
#endif
data.depth = GetDeviceCaps(hdc, BITSPIXEL);
data.format = data.depth == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32;
data.physicalSizeMM = QSizeF(GetDeviceCaps(hdc, HORZSIZE), GetDeviceCaps(hdc, VERTSIZE));