Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use modern DPI awareness settings #13254

Merged
merged 21 commits into from Aug 30, 2022
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 5 additions & 3 deletions source/core.py
@@ -1,5 +1,5 @@
# A part of NonVisual Desktop Access (NVDA)
# Copyright (C) 2006-2021 NV Access Limited, Aleksey Sadovoy, Christopher Toth, Joseph Lee, Peter Vágner,
# Copyright (C) 2006-2022 NV Access Limited, Aleksey Sadovoy, Christopher Toth, Joseph Lee, Peter Vágner,
# Derek Riemer, Babbage B.V., Zahari Yurukov, Łukasz Golonka
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.
Expand Down Expand Up @@ -423,8 +423,10 @@ def main():
Finally, it starts the wx main loop.
"""
log.debug("Core starting")

ctypes.windll.user32.SetProcessDPIAware()
# TODO: change to globalVars.runningFromSource
if getattr(sys, 'frozen', None) is None:
from winAPI.dpiAwareness import setDPIAwareness
setDPIAwareness()

import config
if not globalVars.appArgs.configPath:
Expand Down
50 changes: 50 additions & 0 deletions source/manifest.template.xml
@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly
xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"
xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"
>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel
level="asInvoker"
uiAccess="%(uiAccess)s"
/>
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 7 -->
<supportedOS
Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"
/>
<!-- Windows 8 -->
<supportedOS
Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"
/>
<!-- Windows 8.1 -->
<supportedOS
Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"
/>
<!-- Windows 10 -->
<supportedOS
Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"
/>
</application>
</compatibility>
<asmv3:application>
<asmv3:windowsSettings>
<dpiAware
xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings"
>
true/pm
</dpiAware>
<dpiAwareness
xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings"
>
PerMonitorV2, PerMonitor
</dpiAwareness>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>
55 changes: 11 additions & 44 deletions source/setup.py
@@ -1,70 +1,35 @@
# -*- coding: UTF-8 -*-
#setup.py
#A part of NonVisual Desktop Access (NVDA)
#Copyright (C) 2006-2018 NV Access Limited, Peter Vágner, Joseph Lee
#This file is covered by the GNU General Public License.
#See the file COPYING for more details.
# A part of NonVisual Desktop Access (NVDA)
# Copyright (C) 2006-2022 NV Access Limited, Peter Vágner, Joseph Lee
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.

import os
import sys
import copy
import gettext
gettext.install("nvda")
from setuptools import setup
import py2exe as py2exeModule
seanbudd marked this conversation as resolved.
Show resolved Hide resolved
from glob import glob
import fnmatch
# versionInfo names must be imported after Gettext
# Suppress E402 (module level import not at top of file)
from versionInfo import (
description,
formatBuildVersionString,
name,
version,
publisher
publisher,
url,
) # noqa: E402
from versionInfo import *
from py2exe import distutils_buildexe
from py2exe.dllfinder import DllFinder
import wx
import importlib.machinery
# Explicitly put the nvda_dmp dir on the build path so the DMP library is included
sys.path.append(os.path.join("..", "include", "nvda_dmp"))
RT_MANIFEST = 24
manifest_template = """\
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel
level="asInvoker"
uiAccess="%(uiAccess)s"
/>
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 7 -->
<supportedOS
Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"
/>
<!-- Windows 8 -->
<supportedOS
Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"
/>
<!-- Windows 8.1 -->
<supportedOS
Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"
/>
<!-- Windows 10 -->
<supportedOS
Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"
/>
</application>
</compatibility>
</assembly>
"""
manifestTemplateFilePath = "manifest.template.xml"

# py2exe's idea of whether a dll is a system dll appears to be wrong sometimes, so monkey patch it.
orig_determine_dll_type = DllFinder.determine_dll_type
Expand Down Expand Up @@ -92,6 +57,8 @@ def initialize_options(self):
self.enable_uiAccess = False

def run(self):
with open(manifestTemplateFilePath, "r") as manifestTemplateFile:
seanbudd marked this conversation as resolved.
Show resolved Hide resolved
manifestTemplate = manifestTemplateFile.read()
dist = self.distribution
if self.enable_uiAccess:
# Add a target for nvda_uiAccess, using nvda_noUIAccess as a base.
Expand All @@ -108,7 +75,7 @@ def run(self):
(
RT_MANIFEST,
1,
(manifest_template % dict(uiAccess=target['uiAccess'])).encode("utf-8")
(manifestTemplate % dict(uiAccess=target['uiAccess'])).encode("utf-8")
),
]
super(py2exe, self).run()
Expand Down
4 changes: 4 additions & 0 deletions source/winAPI/__init__.py
@@ -0,0 +1,4 @@
# A part of NonVisual Desktop Access (NVDA)
# Copyright (C) 2022 NV Access Limited
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.
37 changes: 37 additions & 0 deletions source/winAPI/dpiAwareness.py
@@ -0,0 +1,37 @@
# A part of NonVisual Desktop Access (NVDA)
# Copyright (C) 2022 NV Access Limited
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.

import ctypes

from logHandler import log


PROCESS_PER_MONITOR_DPI_AWARE = 2
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = -4


def setDPIAwareness() -> None:
"""
Different versions of Windows inconsistently support different styles of DPI Awareness.
This function attempts to set process DPI awareness using the most modern Windows API method available.

https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setprocessdpiawarenesscontext
"""
# Support is inconsistent across versions of Windows, so try/excepts are used rather than explicit
# version checks.
try:
# Method introduced in Windows 10
ctypes.windll.user32.SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)
seanbudd marked this conversation as resolved.
Show resolved Hide resolved
except AttributeError:
log.debug("Cannot set DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2, falling back to older method")
else:
return
try:
# Method introduced in Windows 8
ctypes.windll.shcore.SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE)
except AttributeError:
log.debug("Cannot set PROCESS_PER_MONITOR_DPI_AWARE, falling back to universal method")
else:
ctypes.windll.user32.SetProcessDPIAware()