X Tutup
Skip to content

Commit e6bcf2c

Browse files
committed
Fix & enhance HighDPI support on Windows in wxPython example (cztomczak#398, cztomczak#399)
Fix DpiAware.GetSystemDpi, CalculateWindowSize (deprecated now). Add DpiAware.Scale.
1 parent 8a20fdb commit e6bcf2c

File tree

8 files changed

+156
-79
lines changed

8 files changed

+156
-79
lines changed

README.md

Lines changed: 55 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -256,60 +256,60 @@ Additional information for v31.2 release:
256256

257257
### API categories
258258

259-
#### Modules
260-
261-
* [cefpython](api/cefpython.md#cefpython) module
262-
263-
264-
#### Settings
265-
266-
* [ApplicationSettings](api/ApplicationSettings.md#application-settings) dictionary
267-
* [BrowserSettings](api/BrowserSettings.md#browser-settings) dictionary
268-
* [CommandLineSwitches](api/CommandLineSwitches.md#command-line-switches) dictionary
269-
270-
271-
#### Classes and objects
272-
273-
* [Browser](api/Browser.md#browser-object) object
274-
* [Callback](api/Callback.md#callback-object) object
275-
* [Cookie](api/Cookie.md#cookie-class) class
276-
* [CookieManager](api/CookieManager.md#cookiemanager-class) class
277-
* [DpiAware](api/DpiAware.md#dpiaware-class) class (Win)
278-
* [DragData](api/DragData.md#dragdata-object) object
279-
* [Frame](api/Frame.md#frame-object) object
280-
* [Image](api/Image.md#image-object) object
281-
* [JavascriptBindings](api/JavascriptBindings.md#javascriptbindings-class) class
282-
* [JavascriptCallback](api/JavascriptCallback.md#javascriptcallback-object) object
283-
* [PaintBuffer](api/PaintBuffer.md#paintbuffer-object) object
284-
* [Request](api/Request.md#request-class) class
285-
* [Response](api/Response.md#response-object) object
286-
* [WebPluginInfo](api/WebPluginInfo.md#webplugininfo-object) object
287-
* [WebRequest](api/WebRequest.md#webrequest-class) class
288-
* [WindowInfo](api/WindowInfo.md#windowinfo-class) class
289-
* [WindowUtils](api/WindowUtils.md#windowutils-class) class
290-
291-
292-
#### Client handlers (interfaces)
293-
294-
* [DisplayHandler](api/DisplayHandler.md#displayhandler-interface)
295-
* [DownloadHandler](api/DownloadHandler.md#downloadhandler)
296-
* [FocusHandler](api/FocusHandler.md#focushandler-interface)
297-
* [JavascriptDialogHandler](api/JavascriptDialogHandler.md#javascriptdialoghandler-interface)
298-
* [KeyboardHandler](api/KeyboardHandler.md#keyboardhandler-interface)
299-
* [LifespanHandler](api/LifespanHandler.md#lifespanhandler-interface)
300-
* [LoadHandler](api/LoadHandler.md#loadhandler-interface)
301-
* [RenderHandler](api/RenderHandler.md#renderhandler-interface)
302-
* [RequestHandler](api/RequestHandler.md#requesthandler-interface)
303-
* [ResourceHandler](api/ResourceHandler.md#resourcehandler-interface)
304-
* [V8ContextHandler](api/V8ContextHandler.md#v8contexthandler-interface)
305-
306-
307-
#### Other interfaces
308-
309-
* [CookieVisitor](api/CookieVisitor.md#cookievisitor-interface) interface
310-
* [StringVisitor](api/StringVisitor.md#stringvisitor-interface) interface
311-
* [WebRequestClient](api/WebRequestClient.md#webrequestclient-interface) interface
312-
259+
#### Modules
260+
261+
* [cefpython](api/cefpython.md#cefpython) module
262+
263+
264+
#### Settings
265+
266+
* [ApplicationSettings](api/ApplicationSettings.md#application-settings) dictionary
267+
* [BrowserSettings](api/BrowserSettings.md#browser-settings) dictionary
268+
* [CommandLineSwitches](api/CommandLineSwitches.md#command-line-switches) dictionary
269+
270+
271+
#### Classes and objects
272+
273+
* [Browser](api/Browser.md#browser-object) object
274+
* [Callback](api/Callback.md#callback-object) object
275+
* [Cookie](api/Cookie.md#cookie-class) class
276+
* [CookieManager](api/CookieManager.md#cookiemanager-class) class
277+
* [DpiAware](api/DpiAware.md#dpiaware-class) class (Win)
278+
* [DragData](api/DragData.md#dragdata-object) object
279+
* [Frame](api/Frame.md#frame-object) object
280+
* [Image](api/Image.md#image-object) object
281+
* [JavascriptBindings](api/JavascriptBindings.md#javascriptbindings-class) class
282+
* [JavascriptCallback](api/JavascriptCallback.md#javascriptcallback-object) object
283+
* [PaintBuffer](api/PaintBuffer.md#paintbuffer-object) object
284+
* [Request](api/Request.md#request-class) class
285+
* [Response](api/Response.md#response-object) object
286+
* [WebPluginInfo](api/WebPluginInfo.md#webplugininfo-object) object
287+
* [WebRequest](api/WebRequest.md#webrequest-class) class
288+
* [WindowInfo](api/WindowInfo.md#windowinfo-class) class
289+
* [WindowUtils](api/WindowUtils.md#windowutils-class) class
290+
291+
292+
#### Client handlers (interfaces)
293+
294+
* [DisplayHandler](api/DisplayHandler.md#displayhandler-interface)
295+
* [DownloadHandler](api/DownloadHandler.md#downloadhandler)
296+
* [FocusHandler](api/FocusHandler.md#focushandler-interface)
297+
* [JavascriptDialogHandler](api/JavascriptDialogHandler.md#javascriptdialoghandler-interface)
298+
* [KeyboardHandler](api/KeyboardHandler.md#keyboardhandler-interface)
299+
* [LifespanHandler](api/LifespanHandler.md#lifespanhandler-interface)
300+
* [LoadHandler](api/LoadHandler.md#loadhandler-interface)
301+
* [RenderHandler](api/RenderHandler.md#renderhandler-interface)
302+
* [RequestHandler](api/RequestHandler.md#requesthandler-interface)
303+
* [ResourceHandler](api/ResourceHandler.md#resourcehandler-interface)
304+
* [V8ContextHandler](api/V8ContextHandler.md#v8contexthandler-interface)
305+
306+
307+
#### Other interfaces
308+
309+
* [CookieVisitor](api/CookieVisitor.md#cookievisitor-interface) interface
310+
* [StringVisitor](api/StringVisitor.md#stringvisitor-interface) interface
311+
* [WebRequestClient](api/WebRequestClient.md#webrequestclient-interface) interface
312+
313313

314314
### API index
315315

@@ -524,6 +524,7 @@ Additional information for v31.2 release:
524524
* [GetSystemDpi](api/DpiAware.md#getsystemdpi)
525525
* [IsProcessDpiAware](api/DpiAware.md#isprocessdpiaware)
526526
* [SetProcessDpiAware](api/DpiAware.md#setprocessdpiaware)
527+
* [Scale](api/DpiAware.md#scale)
527528
* [DragData (object)](api/DragData.md#dragdata-object)
528529
* [IsLink](api/DragData.md#islink)
529530
* [IsFragment](api/DragData.md#isfragment)

api/API-index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@
213213
* [GetSystemDpi](DpiAware.md#getsystemdpi)
214214
* [IsProcessDpiAware](DpiAware.md#isprocessdpiaware)
215215
* [SetProcessDpiAware](DpiAware.md#setprocessdpiaware)
216+
* [Scale](DpiAware.md#scale)
216217
* [DragData (object)](DragData.md#dragdata-object)
217218
* [IsLink](DragData.md#islink)
218219
* [IsFragment](DragData.md#isfragment)

api/DpiAware.md

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Table of contents:
1616
* [GetSystemDpi](#getsystemdpi)
1717
* [IsProcessDpiAware](#isprocessdpiaware)
1818
* [SetProcessDpiAware](#setprocessdpiaware)
19+
* [Scale](#scale)
1920

2021

2122

@@ -37,13 +38,13 @@ Enabling High DPI support in app can be done by embedding a DPI awareness xml ma
3738
| height | int |
3839
| __Return__ | tuple |
3940

41+
Deprecated. Use `Scale()` method instead which can handle
42+
non standard DPI settings such as '132%' on Windows 10.
43+
4044
This utility function will adjust width/height using
4145
OS DPI settings. For 800/600 with Win7 DPI settings
4246
being set to "Larger 150%" will return 1200/900.
4347

44-
Calculation for DPI < 96 is not yet supported. Use
45-
the `GetSystemDpi` method for that.
46-
4748

4849
### EnableHighDpiSupport
4950

@@ -68,20 +69,29 @@ Description from upstream CEF:
6869

6970
Returns tuple(int dpix, int dpiy).
7071

72+
Returns Windows DPI settings ("Custom scaling" on Win10).
73+
7174
Win7 DPI (Control Panel > Appearance and Personalization > Display):
7275

7376
* text size Larger 150% => dpix/dpiy 144
7477
* text size Medium 125% => dpix/dpiy 120
7578
* text size Smaller 100% => dpix/dpiy 96
7679

77-
Example zoom levels based on DPI. For use with the ApplicationSettings.`auto_zooming` option.
80+
Example zoom levels based on DPI. For use with the
81+
ApplicationSettings.`auto_zooming` option.
7882

7983
* dpix=96 zoomlevel=0.0
8084
* dpix=120 zoomlevel=1.0
8185
* dpix=144 zoomlevel=2.0
8286
* dpix=72 zoomlevel=-1.0
8387

84-
If DPI awareness wasn't yet enabled, then `GetSystemDpi` will always return a default 96 DPI.
88+
If DPI awareness wasn't yet enabled, then `GetSystemDpi` will always
89+
return a default 96 DPI.
90+
91+
DPI settings should not be cached. When `SetProcessDpiAware`
92+
is not yet called, then OS returns 96 DPI, even though it
93+
is set to 144 DPI. After DPI Awareness is enabled for the
94+
running process it will return the correct 144 DPI.
8595

8696

8797
### IsProcessDpiAware
@@ -106,3 +116,13 @@ See [Issue #358](../../../issues/358) for how the behavior changed in
106116
latest CEF. This method now internally calls `EnableHighDpiSupport()`.
107117

108118
Enables DPI awareness for the running process. Embedding a DPI manifest in .exe is the prefered way, as it gives more reliable results, otherwise some display bugs may appear (discussed in the "Introduction" section on this page).
119+
120+
121+
### Scale
122+
123+
| Parameter | Type |
124+
| --- | --- |
125+
| size | int/tuple/list |
126+
| __Return__ | tuple |
127+
128+
Scale units for high DPI devices.

examples/tkinter_.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def __init__(self, root):
6767
self.navigation_bar = None
6868

6969
# Root
70-
root.geometry("800x600")
70+
root.geometry("900x640")
7171
tk.Grid.rowconfigure(root, 0, weight=1)
7272
tk.Grid.columnconfigure(root, 0, weight=1)
7373

examples/wxpython.py

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@
3333
sys.exit(1)
3434

3535
# Configuration
36-
WIDTH = 800
37-
HEIGHT = 600
36+
WIDTH = 900
37+
HEIGHT = 640
3838

3939
# Globals
4040
g_count_windows = 0
@@ -71,11 +71,26 @@ def check_versions():
7171
assert cef.__version__ >= "55.3", "CEF Python v55.3+ required to run this"
7272

7373

74+
def scale_window_size_for_high_dpi(width, height):
75+
"""Scale window size for high DPI devices. This func can be
76+
called on all operating systems, but scales only for Windows.
77+
If scaled value is bigger than the work area on the display
78+
then it will be reduced."""
79+
if not WINDOWS:
80+
return width, height
81+
(_, _, max_width, max_height) = wx.GetClientDisplayRect().Get()
82+
# noinspection PyUnresolvedReferences, PyArgumentList
83+
(width, height) = cef.DpiAware.Scale((width, height))
84+
if width > max_width:
85+
width = max_width
86+
if height > max_height:
87+
height = max_height
88+
return width, height
89+
90+
7491
class MainFrame(wx.Frame):
7592

7693
def __init__(self):
77-
wx.Frame.__init__(self, parent=None, id=wx.ID_ANY,
78-
title='wxPython example', size=(WIDTH, HEIGHT))
7994
self.browser = None
8095

8196
# Must ignore X11 errors like 'BadWindow' and others by
@@ -87,6 +102,22 @@ def __init__(self):
87102
global g_count_windows
88103
g_count_windows += 1
89104

105+
# noinspection PyUnresolvedReferences, PyArgumentList
106+
print("[wxpython.py] System DPI settings: %s"
107+
% str(cef.DpiAware.GetSystemDpi()))
108+
print("[wxpython.py] wx.GetDisplayPPI = %s" % wx.GetDisplayPPI())
109+
print("[wxpython.py] wx.GetDisplaySize = %s" % wx.GetDisplaySize())
110+
111+
print("[wxpython.py] MainFrame declared size: %s" % str((WIDTH, HEIGHT)))
112+
size = scale_window_size_for_high_dpi(WIDTH, HEIGHT)
113+
print("[wxpython.py] MainFrame DPI scaled size: %s" % str(size))
114+
115+
wx.Frame.__init__(self, parent=None, id=wx.ID_ANY,
116+
title='wxPython example', size=size)
117+
# wxPython will set a smaller size when it is bigger
118+
# than desktop size.
119+
print("[wxpython.py] MainFrame actual size: %s" % self.GetSize())
120+
90121
self.setup_icon()
91122
self.create_menu()
92123
self.Bind(wx.EVT_CLOSE, self.OnClose)

src/dpi_aware_win.pyx

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,51 @@ class DpiAware:
88

99
@staticmethod
1010
def GetSystemDpi():
11-
# Win7 DPI (Control Panel > Appearance and Personalization > Display):
12-
# text size Larger 150% => dpix/dpiy 144
13-
# text size Medium 125% => dpix/dpiy 120
14-
# text size Smaller 100% => dpix/dpiy 96
15-
#
16-
# dpix=96 zoomlevel=0.0
17-
# dpix=120 zoomlevel=1.0
18-
# dpix=144 zoomlevel=2.0
19-
# dpix=72 zoomlevel=-1.0
20-
#
21-
# If DPI awareness wasn't yet enabled, then GetSystemDpi
22-
# will always return a default 96 DPI.
11+
"""Returns Windows DPI settings ("Custom scaling" on Win10).
12+
13+
Win7 DPI (Control Panel > Appearance and Personalization > Display):
14+
text size Larger 150% => dpix/dpiy 144
15+
text size Medium 125% => dpix/dpiy 120
16+
text size Smaller 100% => dpix/dpiy 96
17+
18+
DPI settings should not be cached. When SetProcessDpiAware
19+
is not yet called, then OS returns 96 DPI, even though it
20+
is set to 144 DPI. After DPI Awareness is enabled for the
21+
running process it will return the correct 144 DPI.
22+
"""
2323
cdef int dpix = 0
2424
cdef int dpiy = 0
2525
GetSystemDpi(&dpix, &dpiy)
26-
return tuple(dpix, dpiy)
26+
return dpix, dpiy
2727

2828
@staticmethod
2929
def CalculateWindowSize(int width, int height):
30+
"""@DEPRECATED. Use Scale() method instead."""
3031
# Calculation for DPI < 96 is not yet supported.
3132
GetDpiAwareWindowSize(&width, &height)
32-
return tuple(width, height)
33+
return width, height
34+
35+
@staticmethod
36+
def Scale(arg):
37+
"""Scale units for high DPI devices. Argument can be an int,
38+
tuple or list."""
39+
(dpix, dpiy) = DpiAware.GetSystemDpi()
40+
# - Using only "dpix" value to calculate zoom level since all
41+
# modern displays have equal horizontal and vertical resolution.
42+
default_dpix = 96
43+
scale = MulDiv(dpix, 100, default_dpix)
44+
if isinstance(arg, (int, long)):
45+
v = arg
46+
new_value = MulDiv(v, scale, 100)
47+
return new_value
48+
ret_tuple = isinstance(arg, tuple)
49+
ret = list()
50+
for i,v in enumerate(arg):
51+
v = int(v)
52+
ret.append(MulDiv(v, scale, 100))
53+
if ret_tuple:
54+
return tuple(ret)
55+
return ret
3356

3457
@staticmethod
3558
def IsProcessDpiAware():

src/extern/dpi_aware_win.pxd

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,3 @@ cdef extern from "client_handler/dpi_aware.h":
99
cdef void GetDpiAwareWindowSize(int* width, int* height)
1010
cdef void SetProcessDpiAware()
1111
cdef cpp_bool IsProcessDpiAware()
12-

src/extern/windows.pxd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,5 @@ cdef extern from "Windows.h" nogil:
128128
cdef int ICON_SMALL
129129
cdef HWND GetParent(HWND hwnd)
130130

131+
cdef int MulDiv(int number, int numerator, int denominator)
132+

0 commit comments

Comments
 (0)
X Tutup