aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--doc/ScintillaHistory.html6
-rw-r--r--win32/PlatWin.cxx59
-rw-r--r--win32/PlatWin.h2
-rw-r--r--win32/ScintillaWin.cxx21
4 files changed, 67 insertions, 21 deletions
diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html
index 0827120c6..9ebc7ce7d 100644
--- a/doc/ScintillaHistory.html
+++ b/doc/ScintillaHistory.html
@@ -570,6 +570,12 @@
Released 27 April 2020.
</li>
<li>
+ Implement per-monitor DPI Awareness on Win32 so both Scintilla and SciTE
+ will adapt to the display scale when moved between monitors.
+ Applications should forward WM_DPICHANGED to Scintilla.
+ <a href="https://sourceforge.net/p/scintilla/bugs/2171/">Bug #2171</a>.
+ </li>
+ <li>
Optimized performance when opening huge files.
<a href="https://sourceforge.net/p/scintilla/feature-requests/1347/">Feature #1347</a>.
</li>
diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx
index f09cdfcf1..d4d7b8026 100644
--- a/win32/PlatWin.cxx
+++ b/win32/PlatWin.cxx
@@ -243,6 +243,14 @@ void SetWindowPointer(HWND hWnd, void *ptr) noexcept {
namespace {
+using GetDpiForWindowSig = UINT(WINAPI *)(HWND hwnd);
+GetDpiForWindowSig fnGetDpiForWindow = nullptr;
+
+void LoadDpiForWindow() noexcept {
+ HMODULE user32 = ::GetModuleHandleW(L"user32.dll");
+ fnGetDpiForWindow = DLLFunction<GetDpiForWindowSig>(user32, "GetDpiForWindow");
+}
+
HINSTANCE hinstPlatformRes {};
HCURSOR reverseArrowCursor {};
@@ -415,6 +423,16 @@ public:
};
typedef VarBuffer<XYPOSITION, stackBufferLength> TextPositions;
+UINT DpiForWindow(WindowID wid) noexcept {
+ if (fnGetDpiForWindow) {
+ return fnGetDpiForWindow(HwndFromWindowID(wid));
+ }
+ HDC hdcMeasure = ::CreateCompatibleDC({});
+ const UINT scale = ::GetDeviceCaps(hdcMeasure, LOGPIXELSY);
+ ::DeleteDC(hdcMeasure);
+ return scale;
+}
+
class SurfaceGDI : public Surface {
bool unicodeMode=false;
HDC hdc{};
@@ -426,6 +444,9 @@ class SurfaceGDI : public Surface {
HFONT fontOld{};
HBITMAP bitmap{};
HBITMAP bitmapOld{};
+
+ int logPixelsY = 72;
+
int maxWidthMeasure = INT_MAX;
// There appears to be a 16 bit string length limit in GDI on NT.
int maxLenText = 65535;
@@ -537,20 +558,22 @@ bool SurfaceGDI::Initialised() {
return hdc != 0;
}
-void SurfaceGDI::Init(WindowID) {
+void SurfaceGDI::Init(WindowID wid) {
Release();
hdc = ::CreateCompatibleDC({});
hdcOwned = true;
::SetTextAlign(hdc, TA_BASELINE);
+ logPixelsY = DpiForWindow(wid);
}
-void SurfaceGDI::Init(SurfaceID sid, WindowID) {
+void SurfaceGDI::Init(SurfaceID sid, WindowID wid) {
Release();
hdc = static_cast<HDC>(sid);
::SetTextAlign(hdc, TA_BASELINE);
+ logPixelsY = DpiForWindow(wid);
}
-void SurfaceGDI::InitPixMap(int width, int height, Surface *surface_, WindowID) {
+void SurfaceGDI::InitPixMap(int width, int height, Surface *surface_, WindowID wid) {
Release();
SurfaceGDI *psurfOther = dynamic_cast<SurfaceGDI *>(surface_);
// Should only ever be called with a SurfaceGDI, not a SurfaceD2D
@@ -562,6 +585,7 @@ void SurfaceGDI::InitPixMap(int width, int height, Surface *surface_, WindowID)
::SetTextAlign(hdc, TA_BASELINE);
SetUnicodeMode(psurfOther->unicodeMode);
SetDBCSMode(psurfOther->codePage);
+ logPixelsY = DpiForWindow(wid);
}
void SurfaceGDI::PenColour(ColourDesired fore) {
@@ -599,7 +623,7 @@ void SurfaceGDI::SetFont(const Font &font_) noexcept {
}
int SurfaceGDI::LogPixelsY() {
- return ::GetDeviceCaps(hdc, LOGPIXELSY);
+ return logPixelsY;
}
int SurfaceGDI::DeviceHeightFont(int points) {
@@ -992,8 +1016,6 @@ class SurfaceD2D : public Surface {
ID2D1SolidColorBrush *pBrush;
int logPixelsY;
- float dpiScaleX;
- float dpiScaleY;
void Clear() noexcept;
void SetFont(const Font &font_);
@@ -1007,7 +1029,7 @@ public:
SurfaceD2D &operator=(SurfaceD2D &&) = delete;
~SurfaceD2D() override;
- void SetScale();
+ void SetScale(WindowID wid);
void Init(WindowID wid) override;
void Init(SurfaceID sid, WindowID wid) override;
void InitPixMap(int width, int height, Surface *surface_, WindowID wid) override;
@@ -1078,8 +1100,6 @@ SurfaceD2D::SurfaceD2D() noexcept :
pBrush = nullptr;
logPixelsY = 72;
- dpiScaleX = 1.0;
- dpiScaleY = 1.0;
}
SurfaceD2D::~SurfaceD2D() {
@@ -1110,12 +1130,8 @@ void SurfaceD2D::Release() {
Clear();
}
-void SurfaceD2D::SetScale() {
- HDC hdcMeasure = ::CreateCompatibleDC({});
- logPixelsY = ::GetDeviceCaps(hdcMeasure, LOGPIXELSY);
- dpiScaleX = ::GetDeviceCaps(hdcMeasure, LOGPIXELSX) / 96.0f;
- dpiScaleY = logPixelsY / 96.0f;
- ::DeleteDC(hdcMeasure);
+void SurfaceD2D::SetScale(WindowID wid) {
+ logPixelsY = DpiForWindow(wid);
}
bool SurfaceD2D::Initialised() {
@@ -1126,20 +1142,20 @@ HRESULT SurfaceD2D::FlushDrawing() {
return pRenderTarget->Flush();
}
-void SurfaceD2D::Init(WindowID /* wid */) {
+void SurfaceD2D::Init(WindowID wid) {
Release();
- SetScale();
+ SetScale(wid);
}
-void SurfaceD2D::Init(SurfaceID sid, WindowID) {
+void SurfaceD2D::Init(SurfaceID sid, WindowID wid) {
Release();
- SetScale();
+ SetScale(wid);
pRenderTarget = static_cast<ID2D1RenderTarget *>(sid);
}
-void SurfaceD2D::InitPixMap(int width, int height, Surface *surface_, WindowID) {
+void SurfaceD2D::InitPixMap(int width, int height, Surface *surface_, WindowID wid) {
Release();
- SetScale();
+ SetScale(wid);
SurfaceD2D *psurfOther = dynamic_cast<SurfaceD2D *>(surface_);
// Should only ever be called with a SurfaceD2D, not a SurfaceGDI
PLATFORM_ASSERT(psurfOther);
@@ -3312,6 +3328,7 @@ void Platform::Assert(const char *c, const char *file, int line) {
void Platform_Initialise(void *hInstance) {
hinstPlatformRes = static_cast<HINSTANCE>(hInstance);
+ LoadDpiForWindow();
LoadReverseArrowCursor();
ListBoxX_Register();
}
diff --git a/win32/PlatWin.h b/win32/PlatWin.h
index 9d17dff69..5ce12b6c0 100644
--- a/win32/PlatWin.h
+++ b/win32/PlatWin.h
@@ -52,6 +52,8 @@ T DLLFunction(HMODULE hModule, LPCSTR lpProcName) noexcept {
return fp;
}
+UINT DpiForWindow(WindowID wid) noexcept;
+
#if defined(USE_D2D)
extern bool LoadD2D();
extern ID2D1Factory *pD2DFactory;
diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx
index 01ffcbe76..046ff7f10 100644
--- a/win32/ScintillaWin.cxx
+++ b/win32/ScintillaWin.cxx
@@ -96,6 +96,10 @@
#define WM_UNICHAR 0x0109
#endif
+#ifndef WM_DPICHANGED
+#define WM_DPICHANGED 0x02E0
+#endif
+
#ifndef UNICODE_NOCHAR
#define UNICODE_NOCHAR 0xFFFF
#endif
@@ -282,6 +286,8 @@ class ScintillaWin :
unsigned int linesPerScroll; ///< Intellimouse support
int wheelDelta; ///< Wheel delta from roll
+ UINT dpi = 72;
+
HRGN hRgnUpdate;
bool hasOKText;
@@ -337,6 +343,8 @@ class ScintillaWin :
Sci::Position TargetAsUTF8(char *text) const;
Sci::Position EncodedFromUTF8(const char *utf8, char *encoded) const;
+ void CheckDpiChanged();
+
bool PaintDC(HDC hdc);
sptr_t WndPaint();
@@ -847,6 +855,14 @@ Sci::Position ScintillaWin::EncodedFromUTF8(const char *utf8, char *encoded) con
}
}
+void ScintillaWin::CheckDpiChanged() {
+ const UINT dpiNow = DpiForWindow(wMain.GetID());
+ if (dpi != dpiNow) {
+ dpi = dpiNow;
+ InvalidateStyleData();
+ }
+}
+
bool ScintillaWin::PaintDC(HDC hdc) {
if (technology == SC_TECHNOLOGY_DEFAULT) {
AutoSurface surfaceWindow(hdc, this);
@@ -877,6 +893,7 @@ bool ScintillaWin::PaintDC(HDC hdc) {
}
sptr_t ScintillaWin::WndPaint() {
+ CheckDpiChanged();
//ElapsedPeriod ep;
// Redirect assertions to debug output and save current state
@@ -1897,6 +1914,10 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam
InvalidateStyleData();
break;
+ case WM_DPICHANGED:
+ InvalidateStyleRedraw();
+ break;
+
case WM_CONTEXTMENU:
return ShowContextMenu(iMessage, wParam, lParam);