This patch adds support for switching between monitors of different pixel density (DPI).
This prevents blurred text when switching between laptop's display and an external monitor.
See:
https://docs.microsoft.com/pl-pl/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows
https://docs.microsoft.com/en-us/windows/win32/sbscs/application-manifests
https://docs.microsoft.com/pl-pl/windows/win32/hidpi/wm-dpichanged
SciTE and Scintilla aren't per-monitor DPI aware. They aren't even really DPI aware. This used to behave better on earlier versions of Windows when (in my recollection, which might be wrong)
GetDeviceCaps(CreateCompatibleDC(NULL), LOGPIXELSY)could be used to track the system DPI. However, on current Windows 10, this appears to stick to the value at application startup. Thus starting a new instance of SciTE will be adapted to the current DPI but changing DPI will not change the size of text inside Scintilla.Scintilla could be made to better track current DPI (calling
GetDpiForSystem) but per-monitor DPI (GetDpiForWindow) doesn't fit in very nicely. Much of the drawing code in the platform layer has no access to the window it is drawing on or measuring for. Fixing this may require a change to the interface between the platform layer and platform-independent core so may have to wait until the next major version.Pretending to be per-monitor DPI aware will stop the blurred text but won't scale it correctly.
I see. Waiting for SciTE 5 then!
I hate restarting SciTE and reopening a dozen files every time I dock or undock my laptop. Sharp text of wrong size (that I can zoom in or out) works better for me than blurred text.
Committed for SciTE with [4430c5]. SciTE forwards WM_DPICHANGED to Scintilla.
Implemented support for Scintilla with [134a38]. Scintilla checks if DPI has changed inside painting and invalidates cached data if it has. Responds to WM_DPICHANGED by invalidation and redraw.
Related
Commit: [4430c5]
Commit: [134a38]
I think these change need test.
Before these changes, Notepad2 computes font size zoom factor like following:
1. get LOGPIXELSY of editor window on startup as
defaultDPI2. get current DPI of editor window on startup (with GetDpiForWindow, GetDpiForMonitor, and LOGPIXELSY) and in WM_DPICHANGED (use HIWORD(wParam)) as
currentDPI3. the zoom factor is
currentDPI/defaultDPI.so for user with only one monitor at 200% scale, on application startup, the zoom factor is 1, no need to zoom. Font zoom is only needed when user dynamic change scale settings or move to monitor with different DPI, it's not needed after login out and re-login in.
after these changes, the relations become complicated.
After this change, Scintilla becomes responsible for scaling text size. Applications should not scale text size due to monitor scaling but should forward WM_DPICHANGED to Scintilla.
Having applications multiply all font sizes by the scaling factor when calling SCI_STYLEGETSIZE[FRACTIONAL] makes applications more complex.
However there are other styles that need scaled by application (with scale factor
currentDPI/96): whitespace dot size, extra ascent/descent, line frame size etc.Application also need to scale the margin width.
There is a remaining bug [bugs:#2063]
Another is stroke width, I don't remember where is was previously discussed.
Related
Bugs:
#2063Some features are currently single-pixel, like stroke width, or a small number of pixels so the appropriate time to scale is a trade-off. Making 1.5-pixel wide lines which are then blurry is unpopular with many users wanting pixel-grid-aligned lines. If stroke width is to scale, then the application should be able to control when and how far scaling occurs.
As text is multiple pixels in size and already non-grid-aligned it does not suffer the same issue.
There are still some difference.
Notepad2 current:
Scintilla current:
I actually simulate GetSystemMetricsForDpi() with:
The default monitor is where application first displayed in on startup.
I will need to check again whether LOGPIXELSY is same on all monitor.
OK the font scaling is fixed, checked the document at:
https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getdevicecaps
SciTE seems still has something wrong (the candidate window is short than others, font is also smaller than others), see the screenshot.
add
sizeZoomed = MulDiv(sizeZoomed, 175, 100);inScintillaWin::ImeStartComposition()has no help.Run Notepad2, Notepad, SciTE with font Microsoft YaHei UI, size 11 on 1920x1080, manually change scale from 100% to 175%.
That code is taking the effect of the DPI into account. The lf.lfHeight is -14 for 100%, -25 for 175%, and -29 for 200%.
They indeed computed to the same value (deviceHeight=2566), and it only affect the composition window, not the candidate window. I still not figured out what caused the shorter candidate window in SciTE (though text in editor window rendered correctly).
A potential fix lf.lfHeight:
USER_DEFAULT_SCREEN_DPI can be defined and used to replace other 96.0 or 96.0f.
Many thanks for this change! I have built SciTE myself to try it. The text remains sharp when switching the monitors, that's fantastic. The tabs in SciTE don't scale well though - they become noticeably larger when switching from a laptop display to a monitor.
The tab bar should be fixed with [979191].
The worst remaining issue is with strips but they may require deleting then recreating each control. I'll leave strips alone for now.
Related
Commit: [979191]
I confirm the tabs are fine now. The size of the Ctrl+F strip is a minor issue for me.
The bug for SciTE seems because it's not manifested to support Windows 10, update SciTE.exe.manifest to list Win 10 as a supported OS fixed the IME candidate window bug.
Here is the updated manifest, changed dpiAwareness (based on Notepad2's), https://docs.microsoft.com/en-us/windows/win32/sbscs/application-manifests
There is a remaining bug: the reverseArrowCursor need recreate/resize after DPI changed.
Edit: Need to create a new reverse arrow cursor for new DPI, without destroying old one.
A possible doc update:
Last edit: Zufu Liu 2020-05-21
Added compatibility section with [48fb41].
At 200%, the IME seems excessively large to me. I'd expect the aim would be to match the size the text will be in the document but if this is what is wanted for Chinese then so be it.
Related
Commit: [48fb41]
Mentioned WM_DPICHANGED in documentation. Whether the application is DPI aware is really an application decision.
GetDpiForMonitor is missing from DpiForWindow.
https://docs.microsoft.com/en-us/windows/win32/api/shellscalingapi/nf-shellscalingapi-getdpiformonitor
Why do you want this? If its just to support old versions of Windows then its not really worth the effort.
I find dpi in ScintillaWin is not initialized and updated in WM_DPICHANGED.
it's checked every time in WndPaint(), will this reduce performance?
ct.CallTipCancel();
ac.Cancel();
are missing from WM_DPICHANGED.
How do you provoke WM_DPICHANGED while either of these are active? Selecting the Settings app or moving the window closes them.
Drag application window, move to anothor monitor.
for SciTE, press Ctrl+Enter, ac shows, then click title bar, move SciTE, ac is at old position.