Skip to content

Commit

Permalink
Fix & enhance HighDPI support on Windows in wxPython example (#398, #399
Browse files Browse the repository at this point in the history
)

Fix DpiAware.GetSystemDpi, CalculateWindowSize (deprecated now).
Add DpiAware.Scale.
  • Loading branch information
cztomczak committed Aug 16, 2018
1 parent 8a20fdb commit e6bcf2c
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 79 deletions.
109 changes: 55 additions & 54 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,60 +256,60 @@ Additional information for v31.2 release:

### API categories

#### Modules

* [cefpython](api/cefpython.md#cefpython) module


#### Settings

* [ApplicationSettings](api/ApplicationSettings.md#application-settings) dictionary
* [BrowserSettings](api/BrowserSettings.md#browser-settings) dictionary
* [CommandLineSwitches](api/CommandLineSwitches.md#command-line-switches) dictionary


#### Classes and objects

* [Browser](api/Browser.md#browser-object) object
* [Callback](api/Callback.md#callback-object) object
* [Cookie](api/Cookie.md#cookie-class) class
* [CookieManager](api/CookieManager.md#cookiemanager-class) class
* [DpiAware](api/DpiAware.md#dpiaware-class) class (Win)
* [DragData](api/DragData.md#dragdata-object) object
* [Frame](api/Frame.md#frame-object) object
* [Image](api/Image.md#image-object) object
* [JavascriptBindings](api/JavascriptBindings.md#javascriptbindings-class) class
* [JavascriptCallback](api/JavascriptCallback.md#javascriptcallback-object) object
* [PaintBuffer](api/PaintBuffer.md#paintbuffer-object) object
* [Request](api/Request.md#request-class) class
* [Response](api/Response.md#response-object) object
* [WebPluginInfo](api/WebPluginInfo.md#webplugininfo-object) object
* [WebRequest](api/WebRequest.md#webrequest-class) class
* [WindowInfo](api/WindowInfo.md#windowinfo-class) class
* [WindowUtils](api/WindowUtils.md#windowutils-class) class


#### Client handlers (interfaces)

* [DisplayHandler](api/DisplayHandler.md#displayhandler-interface)
* [DownloadHandler](api/DownloadHandler.md#downloadhandler)
* [FocusHandler](api/FocusHandler.md#focushandler-interface)
* [JavascriptDialogHandler](api/JavascriptDialogHandler.md#javascriptdialoghandler-interface)
* [KeyboardHandler](api/KeyboardHandler.md#keyboardhandler-interface)
* [LifespanHandler](api/LifespanHandler.md#lifespanhandler-interface)
* [LoadHandler](api/LoadHandler.md#loadhandler-interface)
* [RenderHandler](api/RenderHandler.md#renderhandler-interface)
* [RequestHandler](api/RequestHandler.md#requesthandler-interface)
* [ResourceHandler](api/ResourceHandler.md#resourcehandler-interface)
* [V8ContextHandler](api/V8ContextHandler.md#v8contexthandler-interface)


#### Other interfaces

* [CookieVisitor](api/CookieVisitor.md#cookievisitor-interface) interface
* [StringVisitor](api/StringVisitor.md#stringvisitor-interface) interface
* [WebRequestClient](api/WebRequestClient.md#webrequestclient-interface) interface

#### Modules

* [cefpython](api/cefpython.md#cefpython) module


#### Settings

* [ApplicationSettings](api/ApplicationSettings.md#application-settings) dictionary
* [BrowserSettings](api/BrowserSettings.md#browser-settings) dictionary
* [CommandLineSwitches](api/CommandLineSwitches.md#command-line-switches) dictionary


#### Classes and objects

* [Browser](api/Browser.md#browser-object) object
* [Callback](api/Callback.md#callback-object) object
* [Cookie](api/Cookie.md#cookie-class) class
* [CookieManager](api/CookieManager.md#cookiemanager-class) class
* [DpiAware](api/DpiAware.md#dpiaware-class) class (Win)
* [DragData](api/DragData.md#dragdata-object) object
* [Frame](api/Frame.md#frame-object) object
* [Image](api/Image.md#image-object) object
* [JavascriptBindings](api/JavascriptBindings.md#javascriptbindings-class) class
* [JavascriptCallback](api/JavascriptCallback.md#javascriptcallback-object) object
* [PaintBuffer](api/PaintBuffer.md#paintbuffer-object) object
* [Request](api/Request.md#request-class) class
* [Response](api/Response.md#response-object) object
* [WebPluginInfo](api/WebPluginInfo.md#webplugininfo-object) object
* [WebRequest](api/WebRequest.md#webrequest-class) class
* [WindowInfo](api/WindowInfo.md#windowinfo-class) class
* [WindowUtils](api/WindowUtils.md#windowutils-class) class


#### Client handlers (interfaces)

* [DisplayHandler](api/DisplayHandler.md#displayhandler-interface)
* [DownloadHandler](api/DownloadHandler.md#downloadhandler)
* [FocusHandler](api/FocusHandler.md#focushandler-interface)
* [JavascriptDialogHandler](api/JavascriptDialogHandler.md#javascriptdialoghandler-interface)
* [KeyboardHandler](api/KeyboardHandler.md#keyboardhandler-interface)
* [LifespanHandler](api/LifespanHandler.md#lifespanhandler-interface)
* [LoadHandler](api/LoadHandler.md#loadhandler-interface)
* [RenderHandler](api/RenderHandler.md#renderhandler-interface)
* [RequestHandler](api/RequestHandler.md#requesthandler-interface)
* [ResourceHandler](api/ResourceHandler.md#resourcehandler-interface)
* [V8ContextHandler](api/V8ContextHandler.md#v8contexthandler-interface)


#### Other interfaces

* [CookieVisitor](api/CookieVisitor.md#cookievisitor-interface) interface
* [StringVisitor](api/StringVisitor.md#stringvisitor-interface) interface
* [WebRequestClient](api/WebRequestClient.md#webrequestclient-interface) interface


### API index

Expand Down Expand Up @@ -524,6 +524,7 @@ Additional information for v31.2 release:
* [GetSystemDpi](api/DpiAware.md#getsystemdpi)
* [IsProcessDpiAware](api/DpiAware.md#isprocessdpiaware)
* [SetProcessDpiAware](api/DpiAware.md#setprocessdpiaware)
* [Scale](api/DpiAware.md#scale)
* [DragData (object)](api/DragData.md#dragdata-object)
* [IsLink](api/DragData.md#islink)
* [IsFragment](api/DragData.md#isfragment)
Expand Down
1 change: 1 addition & 0 deletions api/API-index.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@
* [GetSystemDpi](DpiAware.md#getsystemdpi)
* [IsProcessDpiAware](DpiAware.md#isprocessdpiaware)
* [SetProcessDpiAware](DpiAware.md#setprocessdpiaware)
* [Scale](DpiAware.md#scale)
* [DragData (object)](DragData.md#dragdata-object)
* [IsLink](DragData.md#islink)
* [IsFragment](DragData.md#isfragment)
Expand Down
30 changes: 25 additions & 5 deletions api/DpiAware.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Table of contents:
* [GetSystemDpi](#getsystemdpi)
* [IsProcessDpiAware](#isprocessdpiaware)
* [SetProcessDpiAware](#setprocessdpiaware)
* [Scale](#scale)



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

Deprecated. Use `Scale()` method instead which can handle
non standard DPI settings such as '132%' on Windows 10.

This utility function will adjust width/height using
OS DPI settings. For 800/600 with Win7 DPI settings
being set to "Larger 150%" will return 1200/900.

Calculation for DPI < 96 is not yet supported. Use
the `GetSystemDpi` method for that.


### EnableHighDpiSupport

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

Returns tuple(int dpix, int dpiy).

Returns Windows DPI settings ("Custom scaling" on Win10).

Win7 DPI (Control Panel > Appearance and Personalization > Display):

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

Example zoom levels based on DPI. For use with the ApplicationSettings.`auto_zooming` option.
Example zoom levels based on DPI. For use with the
ApplicationSettings.`auto_zooming` option.

* dpix=96 zoomlevel=0.0
* dpix=120 zoomlevel=1.0
* dpix=144 zoomlevel=2.0
* dpix=72 zoomlevel=-1.0

If DPI awareness wasn't yet enabled, then `GetSystemDpi` will always return a default 96 DPI.
If DPI awareness wasn't yet enabled, then `GetSystemDpi` will always
return a default 96 DPI.

DPI settings should not be cached. When `SetProcessDpiAware`
is not yet called, then OS returns 96 DPI, even though it
is set to 144 DPI. After DPI Awareness is enabled for the
running process it will return the correct 144 DPI.


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

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).


### Scale

| Parameter | Type |
| --- | --- |
| size | int/tuple/list |
| __Return__ | tuple |

Scale units for high DPI devices.
2 changes: 1 addition & 1 deletion examples/tkinter_.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def __init__(self, root):
self.navigation_bar = None

# Root
root.geometry("800x600")
root.geometry("900x640")
tk.Grid.rowconfigure(root, 0, weight=1)
tk.Grid.columnconfigure(root, 0, weight=1)

Expand Down
39 changes: 35 additions & 4 deletions examples/wxpython.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
sys.exit(1)

# Configuration
WIDTH = 800
HEIGHT = 600
WIDTH = 900
HEIGHT = 640

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


def scale_window_size_for_high_dpi(width, height):
"""Scale window size for high DPI devices. This func can be
called on all operating systems, but scales only for Windows.
If scaled value is bigger than the work area on the display
then it will be reduced."""
if not WINDOWS:
return width, height
(_, _, max_width, max_height) = wx.GetClientDisplayRect().Get()
# noinspection PyUnresolvedReferences, PyArgumentList
(width, height) = cef.DpiAware.Scale((width, height))
if width > max_width:
width = max_width
if height > max_height:
height = max_height
return width, height


class MainFrame(wx.Frame):

def __init__(self):
wx.Frame.__init__(self, parent=None, id=wx.ID_ANY,
title='wxPython example', size=(WIDTH, HEIGHT))
self.browser = None

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

# noinspection PyUnresolvedReferences, PyArgumentList
print("[wxpython.py] System DPI settings: %s"
% str(cef.DpiAware.GetSystemDpi()))
print("[wxpython.py] wx.GetDisplayPPI = %s" % wx.GetDisplayPPI())
print("[wxpython.py] wx.GetDisplaySize = %s" % wx.GetDisplaySize())

print("[wxpython.py] MainFrame declared size: %s" % str((WIDTH, HEIGHT)))
size = scale_window_size_for_high_dpi(WIDTH, HEIGHT)
print("[wxpython.py] MainFrame DPI scaled size: %s" % str(size))

wx.Frame.__init__(self, parent=None, id=wx.ID_ANY,
title='wxPython example', size=size)
# wxPython will set a smaller size when it is bigger
# than desktop size.
print("[wxpython.py] MainFrame actual size: %s" % self.GetSize())

self.setup_icon()
self.create_menu()
self.Bind(wx.EVT_CLOSE, self.OnClose)
Expand Down
51 changes: 37 additions & 14 deletions src/dpi_aware_win.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,51 @@ class DpiAware:

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

@staticmethod
def CalculateWindowSize(int width, int height):
"""@DEPRECATED. Use Scale() method instead."""
# Calculation for DPI < 96 is not yet supported.
GetDpiAwareWindowSize(&width, &height)
return tuple(width, height)
return width, height

@staticmethod
def Scale(arg):
"""Scale units for high DPI devices. Argument can be an int,
tuple or list."""
(dpix, dpiy) = DpiAware.GetSystemDpi()
# - Using only "dpix" value to calculate zoom level since all
# modern displays have equal horizontal and vertical resolution.
default_dpix = 96
scale = MulDiv(dpix, 100, default_dpix)
if isinstance(arg, (int, long)):
v = arg
new_value = MulDiv(v, scale, 100)
return new_value
ret_tuple = isinstance(arg, tuple)
ret = list()
for i,v in enumerate(arg):
v = int(v)
ret.append(MulDiv(v, scale, 100))
if ret_tuple:
return tuple(ret)
return ret

@staticmethod
def IsProcessDpiAware():
Expand Down
1 change: 0 additions & 1 deletion src/extern/dpi_aware_win.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,3 @@ cdef extern from "client_handler/dpi_aware.h":
cdef void GetDpiAwareWindowSize(int* width, int* height)
cdef void SetProcessDpiAware()
cdef cpp_bool IsProcessDpiAware()

2 changes: 2 additions & 0 deletions src/extern/windows.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,5 @@ cdef extern from "Windows.h" nogil:
cdef int ICON_SMALL
cdef HWND GetParent(HWND hwnd)

cdef int MulDiv(int number, int numerator, int denominator)

0 comments on commit e6bcf2c

Please sign in to comment.