Skip to content

Commit 9553493

Browse files
joborjakepetroules
authored andcommitted
make the render process DPI-aware
On Windows, system calls that retrieve screen properties (like GetSystemMetrics to get the size of a scroll bar button) are dependent on the DPI awareness setting of the calling process. The render process must use the same DPI awareness setting as the browser process. Retrieve the DPI awareness of the parent process in the render process and set it accordingly. Task-number: QTBUG-48380 Change-Id: Ic17d29d0f584e3cf230ac6ea2b08e3aa0d87ccdd Reviewed-by: Allan Sandfeld Jensen <[email protected]>
1 parent 378c588 commit 9553493

File tree

3 files changed

+168
-0
lines changed

3 files changed

+168
-0
lines changed

src/process/main.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,16 @@ int stat64_proxy(const char *path, struct stat64 *buf)
146146
#endif
147147
#endif // defined(OS_LINUX)
148148

149+
#ifdef Q_OS_WIN
150+
void initDpiAwareness();
151+
#endif // defined(Q_OS_WIN)
152+
149153
int main(int argc, const char **argv)
150154
{
155+
#ifdef Q_OS_WIN
156+
initDpiAwareness();
157+
#endif
158+
151159
// QCoreApplication needs a non-const pointer, while the
152160
// ContentMain in Chromium needs the pointer to be const.
153161
QCoreApplication qtApplication(argc, const_cast<char**>(argv));

src/process/process.pro

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ INCLUDEPATH += ../core
4040

4141
SOURCES = main.cpp
4242

43+
win32 {
44+
SOURCES += \
45+
support_win.cpp
46+
}
47+
4348
contains(QT_CONFIG, qt_framework) {
4449
target.path = $$[QT_INSTALL_LIBS]/QtWebEngineCore.framework/Versions/5/Helpers
4550
} else {

src/process/support_win.cpp

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
/****************************************************************************
2+
**
3+
** Copyright (C) 2015 The Qt Company Ltd.
4+
** Contact: http://www.qt.io/licensing/
5+
**
6+
** This file is part of the QtWebEngine module of the Qt Toolkit.
7+
**
8+
** $QT_BEGIN_LICENSE:LGPL$
9+
** Commercial License Usage
10+
** Licensees holding valid commercial Qt licenses may use this file in
11+
** accordance with the commercial license agreement provided with the
12+
** Software or, alternatively, in accordance with the terms contained in
13+
** a written agreement between you and The Qt Company. For licensing terms
14+
** and conditions see http://www.qt.io/terms-conditions. For further
15+
** information use the contact form at http://www.qt.io/contact-us.
16+
**
17+
** GNU Lesser General Public License Usage
18+
** Alternatively, this file may be used under the terms of the GNU Lesser
19+
** General Public License version 3 as published by the Free Software
20+
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
21+
** packaging of this file. Please review the following information to
22+
** ensure the GNU Lesser General Public License version 3 requirements
23+
** will be met: https://www.gnu.org/licenses/lgpl.html.
24+
**
25+
** GNU General Public License Usage
26+
** Alternatively, this file may be used under the terms of the GNU
27+
** General Public License version 2.0 or later as published by the Free
28+
** Software Foundation and appearing in the file LICENSE.GPL included in
29+
** the packaging of this file. Please review the following information to
30+
** ensure the GNU General Public License version 2.0 requirements will be
31+
** met: http://www.gnu.org/licenses/gpl-2.0.html.
32+
**
33+
** $QT_END_LICENSE$
34+
**
35+
****************************************************************************/
36+
37+
#include <qlibrary.h>
38+
#include <qsysinfo.h>
39+
#include <qt_windows.h>
40+
#include <Tlhelp32.h>
41+
42+
class User32DLL {
43+
public:
44+
User32DLL()
45+
: setProcessDPIAware(0)
46+
{
47+
library.setFileName(QStringLiteral("User32"));
48+
if (!library.load())
49+
return;
50+
setProcessDPIAware = (SetProcessDPIAware)library.resolve("SetProcessDPIAware");
51+
}
52+
53+
bool isValid() const
54+
{
55+
return setProcessDPIAware;
56+
}
57+
58+
typedef BOOL (WINAPI *SetProcessDPIAware)();
59+
60+
// Windows Vista onwards
61+
SetProcessDPIAware setProcessDPIAware;
62+
63+
private:
64+
QLibrary library;
65+
};
66+
67+
// This must match PROCESS_DPI_AWARENESS in ShellScalingApi.h
68+
enum DpiAwareness {
69+
PROCESS_PER_UNAWARE = 0,
70+
PROCESS_PER_SYSTEM_DPI_AWARE = 1,
71+
PROCESS_PER_MONITOR_DPI_AWARE = 2
72+
};
73+
74+
// Shell scaling library (Windows 8.1 onwards)
75+
class ShcoreDLL {
76+
public:
77+
ShcoreDLL()
78+
: getProcessDpiAwareness(0), setProcessDpiAwareness(0)
79+
{
80+
if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS8_1)
81+
return;
82+
library.setFileName(QStringLiteral("SHCore"));
83+
if (!library.load())
84+
return;
85+
getProcessDpiAwareness = (GetProcessDpiAwareness)library.resolve("GetProcessDpiAwareness");
86+
setProcessDpiAwareness = (SetProcessDpiAwareness)library.resolve("SetProcessDpiAwareness");
87+
}
88+
89+
bool isValid() const
90+
{
91+
return getProcessDpiAwareness && setProcessDpiAwareness;
92+
}
93+
94+
typedef HRESULT (WINAPI *GetProcessDpiAwareness)(HANDLE, DpiAwareness *);
95+
typedef HRESULT (WINAPI *SetProcessDpiAwareness)(DpiAwareness);
96+
97+
GetProcessDpiAwareness getProcessDpiAwareness;
98+
SetProcessDpiAwareness setProcessDpiAwareness;
99+
100+
private:
101+
QLibrary library;
102+
};
103+
104+
105+
static DWORD getParentProcessId()
106+
{
107+
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
108+
if (hSnapshot == INVALID_HANDLE_VALUE) {
109+
qErrnoWarning(GetLastError(), "CreateToolhelp32Snapshot failed.");
110+
return NULL;
111+
}
112+
113+
PROCESSENTRY32 pe = {0};
114+
pe.dwSize = sizeof(PROCESSENTRY32);
115+
116+
if (!Process32First(hSnapshot, &pe)) {
117+
qWarning("Cannot retrieve parent process handle.");
118+
return NULL;
119+
}
120+
121+
DWORD parentPid = NULL;
122+
const DWORD pid = GetCurrentProcessId();
123+
do {
124+
if (pe.th32ProcessID == pid) {
125+
parentPid = pe.th32ParentProcessID;
126+
break;
127+
}
128+
} while (Process32Next(hSnapshot, &pe));
129+
CloseHandle(hSnapshot);
130+
return parentPid;
131+
}
132+
133+
void initDpiAwareness()
134+
{
135+
ShcoreDLL shcore;
136+
if (shcore.isValid()) {
137+
DpiAwareness dpiAwareness = PROCESS_PER_MONITOR_DPI_AWARE;
138+
const DWORD pid = getParentProcessId();
139+
if (pid) {
140+
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
141+
DpiAwareness parentDpiAwareness;
142+
HRESULT hr = shcore.getProcessDpiAwareness(hProcess, &parentDpiAwareness);
143+
CloseHandle(hProcess);
144+
if (hr == S_OK)
145+
dpiAwareness = parentDpiAwareness;
146+
}
147+
if (shcore.setProcessDpiAwareness(dpiAwareness) != S_OK)
148+
qErrnoWarning(GetLastError(), "SetProcessDPIAwareness failed.");
149+
} else {
150+
// Fallback. Use SetProcessDPIAware unconditionally.
151+
User32DLL user32;
152+
if (user32.isValid())
153+
user32.setProcessDPIAware();
154+
}
155+
}

0 commit comments

Comments
 (0)