From 29fcd1ac9117a09bd5a988ffdb7fd0e4e0b2fe6b Mon Sep 17 00:00:00 2001 From: ozone10 Date: Sun, 17 Mar 2024 19:00:54 +0100 Subject: [PATCH] Readd dpi API ref https://github.com/notepad-plus-plus/notepad-plus-plus/pull/14871#issuecomment-2002547565 Close #14876 --- PowerEditor/gcc/makefile | 2 +- PowerEditor/src/CMakeLists.txt | 6 +- PowerEditor/src/NppDarkMode.cpp | 228 +++++++++++++++---- PowerEditor/src/NppDarkMode.h | 2 + PowerEditor/src/dpiAware.manifest | 17 +- PowerEditor/src/dpiManagerV2.cpp | 184 +++++++++++++++ PowerEditor/src/dpiManagerV2.h | 120 ++++++++++ PowerEditor/src/winmain.cpp | 2 + PowerEditor/visual.net/notepadPlus.Cpp.props | 2 +- PowerEditor/visual.net/notepadPlus.vcxproj | 3 +- 10 files changed, 507 insertions(+), 59 deletions(-) create mode 100644 PowerEditor/src/dpiManagerV2.cpp create mode 100644 PowerEditor/src/dpiManagerV2.h diff --git a/PowerEditor/gcc/makefile b/PowerEditor/gcc/makefile index 1e3f2a34c..31c7104f5 100644 --- a/PowerEditor/gcc/makefile +++ b/PowerEditor/gcc/makefile @@ -41,7 +41,7 @@ CXXFLAGS := -include $(GCC_DIRECTORY)/gcc-fixes.h -std=c++20 RC := $(CROSS_COMPILE)windres RCFLAGS := CPP_PATH := $(SCINTILLA_DIRECTORY)/include $(LEXILLA_DIRECTORY)/include -CPP_DEFINE := UNICODE _UNICODE OEMRESOURCE NOMINMAX _WIN32_WINNT=_WIN32_WINNT_VISTA TIXML_USE_STL TIXMLA_USE_STL +CPP_DEFINE := UNICODE _UNICODE OEMRESOURCE NOMINMAX _WIN32_WINNT=_WIN32_WINNT_WIN7 NTDDI_VERSION=NTDDI_WIN7 TIXML_USE_STL TIXMLA_USE_STL LD := $(CXX) LDFLAGS := -municode -mwindows LD_PATH := diff --git a/PowerEditor/src/CMakeLists.txt b/PowerEditor/src/CMakeLists.txt index 02365bd51..e1f69e43d 100644 --- a/PowerEditor/src/CMakeLists.txt +++ b/PowerEditor/src/CMakeLists.txt @@ -74,6 +74,7 @@ SET(src_files ./MISC/sha2/sha-256.cpp ./MISC/sha512/sha512.cpp ./NppDarkMode.cpp + ./dpiManagerV2.cpp ./MISC/Process/Processus.cpp ./WinControls/AboutDlg/AboutDlg.cpp ./WinControls/AnsiCharPanel/ansiCharPanel.cpp @@ -203,6 +204,7 @@ SET(include_files ./DarkMode/IatHook.h ./DarkMode/UAHMenuBar.h ./dpiManager.h + ./dpiManagerV2.h ./keys.h ./localizationString.h ./MISC/Common/Sorters.h @@ -393,13 +395,13 @@ IF (WIN32) if ( MSVC ) #do not use for mingw builds SET(CMAKE_CXX_FLAGS "/EHa /MP /W4") - SET(defs -DUNICODE -D_UNICODE -D_WIN32_WINNT=_WIN32_WINNT_VISTA -D_USE_64BIT_TIME_T -DTIXML_USE_STL -DTIXMLA_USE_STL -DNOMINMAX -DOEMRESOURCE -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING ) + SET(defs -DUNICODE -D_UNICODE -D_WIN32_WINNT=_WIN32_WINNT_WIN7 -DNTDDI_VERSION=NTDDI_WIN7 -D_USE_64BIT_TIME_T -DTIXML_USE_STL -DTIXMLA_USE_STL -DNOMINMAX -DOEMRESOURCE -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING ) set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd") else ( MSVC ) # For possible MinGW compilation SET(CMAKE_CXX_FLAGS "-include../gcc/gcc-fixes.h -std=c++20 -fpermissive -municode") - SET(defs -DUNICODE -D_UNICODE -D_WIN32_WINNT=_WIN32_WINNT_VISTA -D_USE_64BIT_TIME_T -DTIXML_USE_STL -DTIXMLA_USE_STL -DNOMINMAX -DOEMRESOURCE) + SET(defs -DUNICODE -D_UNICODE -D_WIN32_WINNT=_WIN32_WINNT_WIN7 -DNTDDI_VERSION=NTDDI_WIN7 -D_USE_64BIT_TIME_T -DTIXML_USE_STL -DTIXMLA_USE_STL -DNOMINMAX -DOEMRESOURCE) endif ( MSVC ) ENDIF (WIN32) diff --git a/PowerEditor/src/NppDarkMode.cpp b/PowerEditor/src/NppDarkMode.cpp index af3eb7adf..faecf7321 100644 --- a/PowerEditor/src/NppDarkMode.cpp +++ b/PowerEditor/src/NppDarkMode.cpp @@ -26,6 +26,7 @@ #include "Parameters.h" #include "resource.h" +#include "dpiManagerV2.h" #include @@ -52,7 +53,7 @@ //#pragma comment(lib, "uxtheme.lib") //#endif -constexpr COLORREF HEXRGB(DWORD rrggbb) { +static constexpr COLORREF HEXRGB(DWORD rrggbb) { // from 0xRRGGBB like natural #RRGGBB // to the little-endian 0xBBGGRR return @@ -327,7 +328,7 @@ namespace NppDarkMode Theme tCustom(darkCustomizedColors); - Theme& getTheme() + static Theme& getTheme() { switch (g_colorToneChoice) { @@ -360,7 +361,7 @@ namespace NppDarkMode static Options _options; // actual runtime options static AdvancedOptions g_advOptions; - Options configuredOptions() + static Options configuredOptions() { NppGUI nppGui = NppParameters::getInstance().getNppGUI(); Options opt; @@ -1031,7 +1032,7 @@ namespace NppDarkMode } }; - void renderButton(HWND hwnd, HDC hdc, HTHEME hTheme, int iPartID, int iStateID) + static void renderButton(HWND hwnd, HDC hdc, HTHEME hTheme, int iPartID, int iStateID) { RECT rcClient{}; WCHAR szText[256] = { '\0' }; @@ -1115,7 +1116,7 @@ namespace NppDarkMode SelectObject(hdc, hOldFont); } - void paintButton(HWND hwnd, HDC hdc, ButtonData& buttonData) + static void paintButton(HWND hwnd, HDC hdc, ButtonData& buttonData) { DWORD nState = static_cast(SendMessage(hwnd, BM_GETSTATE, 0, 0)); const auto nStyle = GetWindowLongPtr(hwnd, GWL_STYLE); @@ -1190,7 +1191,7 @@ namespace NppDarkMode constexpr UINT_PTR g_buttonSubclassID = 42; - LRESULT CALLBACK ButtonSubclass( + static LRESULT CALLBACK ButtonSubclass( HWND hWnd, UINT uMsg, WPARAM wParam, @@ -1215,18 +1216,28 @@ namespace NppDarkMode RemoveWindowSubclass(hWnd, ButtonSubclass, g_buttonSubclassID); delete pButtonData; break; + case WM_ERASEBKGND: + { if (NppDarkMode::isEnabled() && pButtonData->ensureTheme(hWnd)) { return TRUE; } - else - { - break; - } + break; + } + + case WM_DPICHANGED: + { + pButtonData->closeTheme(); + return 0; + } + case WM_THEMECHANGED: + { pButtonData->closeTheme(); break; + } + case WM_PRINTCLIENT: case WM_PAINT: if (NppDarkMode::isEnabled() && pButtonData->ensureTheme(hWnd)) @@ -1274,7 +1285,7 @@ namespace NppDarkMode SetWindowSubclass(hwnd, ButtonSubclass, g_buttonSubclassID, pButtonData); } - void paintGroupbox(HWND hwnd, HDC hdc, ButtonData& buttonData) + static void paintGroupbox(HWND hwnd, HDC hdc, ButtonData& buttonData) { auto nStyle = ::GetWindowLongPtr(hwnd, GWL_STYLE); bool isDisabled = (nStyle & WS_DISABLED) == WS_DISABLED; @@ -1367,7 +1378,7 @@ namespace NppDarkMode constexpr UINT_PTR g_groupboxSubclassID = 42; - LRESULT CALLBACK GroupboxSubclass( + static LRESULT CALLBACK GroupboxSubclass( HWND hWnd, UINT uMsg, WPARAM wParam, @@ -1386,18 +1397,28 @@ namespace NppDarkMode RemoveWindowSubclass(hWnd, GroupboxSubclass, g_groupboxSubclassID); delete pButtonData; break; + case WM_ERASEBKGND: + { if (NppDarkMode::isEnabled() && pButtonData->ensureTheme(hWnd)) { return TRUE; } - else - { - break; - } + break; + } + + case WM_DPICHANGED: + { + pButtonData->closeTheme(); + return 0; + } + case WM_THEMECHANGED: + { pButtonData->closeTheme(); break; + } + case WM_PRINTCLIENT: case WM_PAINT: if (NppDarkMode::isEnabled() && pButtonData->ensureTheme(hWnd)) @@ -1418,10 +1439,6 @@ namespace NppDarkMode return 0; } - else - { - break; - } break; } return DefSubclassProc(hWnd, uMsg, wParam, lParam); @@ -1435,7 +1452,7 @@ namespace NppDarkMode constexpr UINT_PTR g_tabSubclassID = 42; - LRESULT CALLBACK TabSubclass( + static LRESULT CALLBACK TabSubclass( HWND hWnd, UINT uMsg, WPARAM wParam, @@ -1522,15 +1539,15 @@ namespace NppDarkMode ::SendMessage(hWnd, TCM_GETITEM, i, reinterpret_cast(&tci)); - auto dpiManager = NppParameters::getInstance()._dpiManager; + const auto dpi = DPIManagerV2::getDpiForParent(hWnd); RECT rcText = rcItem; - rcText.left += dpiManager.scaleX(5); - rcText.right -= dpiManager.scaleX(3); + rcText.left += DPIManagerV2::scale(5, dpi); + rcText.right -= DPIManagerV2::scale(3, dpi); if (isSelectedTab) { - rcText.bottom -= dpiManager.scaleY(4); + rcText.bottom -= DPIManagerV2::scale(4, dpi); ::InflateRect(&rcFrame, 0, 1); } if (i != nTabs - 1) @@ -1595,9 +1612,34 @@ namespace NppDarkMode SetWindowSubclass(hwnd, TabSubclass, g_tabSubclassID, 0); } + struct BorderMetricsData + { + UINT _dpi = USER_DEFAULT_SCREEN_DPI; + LONG _xEdge = ::GetSystemMetrics(SM_CXEDGE); + LONG _yEdge = ::GetSystemMetrics(SM_CYEDGE); + LONG _xScroll = ::GetSystemMetrics(SM_CXVSCROLL); + LONG _yScroll = ::GetSystemMetrics(SM_CYVSCROLL); + + BorderMetricsData() {}; + + BorderMetricsData(HWND hWnd) + { + setMetricsForDpi(DPIManagerV2::getDpiForParent(hWnd)); + } + + void setMetricsForDpi(UINT dpi) + { + _dpi = dpi; + _xEdge = DPIManagerV2::getSystemMetricsForDpi(SM_CXEDGE, _dpi); + _yEdge = DPIManagerV2::getSystemMetricsForDpi(SM_CYEDGE, _dpi); + _xScroll = DPIManagerV2::getSystemMetricsForDpi(SM_CXVSCROLL, _dpi); + _yScroll = DPIManagerV2::getSystemMetricsForDpi(SM_CYVSCROLL, _dpi); + } + }; + constexpr UINT_PTR g_customBorderSubclassID = 42; - LRESULT CALLBACK CustomBorderSubclass( + static LRESULT CALLBACK CustomBorderSubclass( HWND hWnd, UINT uMsg, WPARAM wParam, @@ -1606,7 +1648,7 @@ namespace NppDarkMode DWORD_PTR dwRefData ) { - UNREFERENCED_PARAMETER(dwRefData); + auto pBorderMetricsData = reinterpret_cast(dwRefData); static bool isHotStatic = false; @@ -1624,21 +1666,21 @@ namespace NppDarkMode HDC hdc = ::GetWindowDC(hWnd); RECT rcClient{}; ::GetClientRect(hWnd, &rcClient); - rcClient.right += (2 * ::GetSystemMetrics(SM_CXEDGE)); + rcClient.right += (2 * pBorderMetricsData->_xEdge); auto style = ::GetWindowLongPtr(hWnd, GWL_STYLE); bool hasVerScrollbar = (style & WS_VSCROLL) == WS_VSCROLL; if (hasVerScrollbar) { - rcClient.right += ::GetSystemMetrics(SM_CXVSCROLL); + rcClient.right += pBorderMetricsData->_xScroll; } - rcClient.bottom += (2 * ::GetSystemMetrics(SM_CYEDGE)); + rcClient.bottom += (2 * pBorderMetricsData->_yEdge); bool hasHorScrollbar = (style & WS_HSCROLL) == WS_HSCROLL; if (hasHorScrollbar) { - rcClient.bottom += ::GetSystemMetrics(SM_CYHSCROLL); + rcClient.bottom += pBorderMetricsData->_yScroll; } HPEN hPen = ::CreatePen(PS_SOLID, 1, NppDarkMode::getBackgroundColor()); @@ -1674,25 +1716,32 @@ namespace NppDarkMode } auto lpRect = reinterpret_cast(lParam); - ::InflateRect(lpRect, -(::GetSystemMetrics(SM_CXEDGE)), -(::GetSystemMetrics(SM_CYEDGE))); + ::InflateRect(lpRect, -(pBorderMetricsData->_xEdge), -(pBorderMetricsData->_yEdge)); auto style = ::GetWindowLongPtr(hWnd, GWL_STYLE); bool hasVerScrollbar = (style & WS_VSCROLL) == WS_VSCROLL; if (hasVerScrollbar) { - lpRect->right -= ::GetSystemMetrics(SM_CXVSCROLL); + lpRect->right -= pBorderMetricsData->_xScroll; } bool hasHorScrollbar = (style & WS_HSCROLL) == WS_HSCROLL; if (hasHorScrollbar) { - lpRect->bottom -= ::GetSystemMetrics(SM_CYHSCROLL); + lpRect->bottom -= pBorderMetricsData->_yScroll; } return 0; } break; + case WM_DPICHANGED: + { + pBorderMetricsData->setMetricsForDpi(LOWORD(wParam)); + ::SetWindowPos(hWnd, nullptr, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); + return 0; + } + case WM_MOUSEMOVE: { if (!NppDarkMode::isEnabled()) @@ -1745,20 +1794,22 @@ namespace NppDarkMode case WM_NCDESTROY: { RemoveWindowSubclass(hWnd, CustomBorderSubclass, uIdSubclass); + delete pBorderMetricsData; } break; } return DefSubclassProc(hWnd, uMsg, wParam, lParam); } - void subclassCustomBorderForListBoxAndEditControls(HWND hwnd) + static void subclassCustomBorderForListBoxAndEditControls(HWND hwnd) { - SetWindowSubclass(hwnd, CustomBorderSubclass, g_customBorderSubclassID, 0); + auto pBorderMetricsData = reinterpret_cast(new BorderMetricsData(hwnd)); + SetWindowSubclass(hwnd, CustomBorderSubclass, g_customBorderSubclassID, pBorderMetricsData); } constexpr UINT_PTR g_comboBoxSubclassID = 42; - LRESULT CALLBACK ComboBoxSubclass( + static LRESULT CALLBACK ComboBoxSubclass( HWND hWnd, UINT uMsg, WPARAM wParam, @@ -1789,7 +1840,7 @@ namespace NppDarkMode auto holdBrush = ::SelectObject(hdc, NppDarkMode::getDarkerBackgroundBrush()); - auto& dpiManager = NppParameters::getInstance()._dpiManager; + const auto dpi = DPIManagerV2::getDpiForParent(hWnd); RECT rcArrow{}; @@ -1804,7 +1855,7 @@ namespace NppDarkMode else { rcArrow = { - rc.right - dpiManager.scaleX(17), rc.top + 1, + rc.right - DPIManagerV2::scale(17, dpi), rc.top + 1, rc.right - 1, rc.bottom - 1 }; } @@ -1887,7 +1938,7 @@ namespace NppDarkMode }; ::Polyline(hdc, edge, _countof(edge)); - int roundCornerValue = NppDarkMode::isWindows11() ? dpiManager.scaleX(4) : 0; + const int roundCornerValue = NppDarkMode::isWindows11() ? DPIManagerV2::scale(4, dpi) : 0; NppDarkMode::paintRoundFrameRect(hdc, rc, hSelectedPen, roundCornerValue, roundCornerValue); ::SelectObject(hdc, holdPen); @@ -1920,7 +1971,7 @@ namespace NppDarkMode constexpr UINT_PTR g_listViewSubclassID = 42; - LRESULT CALLBACK ListViewSubclass( + static LRESULT CALLBACK ListViewSubclass( HWND hWnd, UINT uMsg, WPARAM wParam, @@ -1977,14 +2028,14 @@ namespace NppDarkMode return DefSubclassProc(hWnd, uMsg, wParam, lParam); } - void subclassListViewControl(HWND hwnd) + static void subclassListViewControl(HWND hwnd) { SetWindowSubclass(hwnd, ListViewSubclass, g_listViewSubclassID, 0); } constexpr UINT_PTR g_upDownSubclassID = 42; - LRESULT CALLBACK UpDownSubclass( + static LRESULT CALLBACK UpDownSubclass( HWND hWnd, UINT uMsg, WPARAM wParam, @@ -2090,6 +2141,12 @@ namespace NppDarkMode return FALSE; } + case WM_DPICHANGED: + { + pButtonData->closeTheme(); + return 0; + } + case WM_THEMECHANGED: { pButtonData->closeTheme(); @@ -2118,7 +2175,7 @@ namespace NppDarkMode return DefSubclassProc(hWnd, uMsg, wParam, lParam); } - void subclassAndThemeUpDownControl(HWND hwnd, NppDarkModeParams p) + static void subclassAndThemeUpDownControl(HWND hwnd, NppDarkModeParams p) { if (p._subclass) { @@ -2445,8 +2502,12 @@ namespace NppDarkMode { if (NppDarkMode::isEnabled()) { - auto dpiManager = NppParameters::getInstance()._dpiManager; - roundCornerValue = NppDarkMode::isWindows11() ? dpiManager.scaleX(5) : 0; + if (NppDarkMode::isWindows11()) + { + const auto nmhdr = reinterpret_cast(lParam); + const auto dpi = DPIManagerV2::getDpiForParent(nmhdr->hwndFrom); + roundCornerValue = DPIManagerV2::scale(5, dpi); + } ::FillRect(nmtbcd->nmcd.hdc, &nmtbcd->nmcd.rc, NppDarkMode::getDarkerBackgroundBrush()); return CDRF_NOTIFYITEMDRAW; @@ -2631,7 +2692,7 @@ namespace NppDarkMode constexpr UINT_PTR g_pluginDockWindowSubclassID = 42; - LRESULT CALLBACK PluginDockWindowSubclass( + static LRESULT CALLBACK PluginDockWindowSubclass( HWND hWnd, UINT uMsg, WPARAM wParam, @@ -2855,7 +2916,7 @@ namespace NppDarkMode constexpr UINT_PTR g_windowNotifySubclassID = 42; - LRESULT CALLBACK WindowNotifySubclass( + static LRESULT CALLBACK WindowNotifySubclass( HWND hWnd, UINT uMsg, WPARAM wParam, @@ -2914,6 +2975,77 @@ namespace NppDarkMode SetWindowSubclass(hwnd, WindowNotifySubclass, g_windowNotifySubclassID, 0); } + // currently send message only to selected buttons; listbox and edit controls with scrollbars + void sendMessageToChildControls(HWND hwndParent, UINT msg, WPARAM wParam, LPARAM lParam) + { + struct WMessage + { + UINT _msg = 0; + WPARAM _wParam = 0; + LPARAM _lParam = 0; + }; + + struct WMessage p { msg, wParam, lParam }; + + ::EnumChildWindows(hwndParent, [](HWND hwnd, LPARAM childLParam) WINAPI_LAMBDA->BOOL{ + auto & p = *reinterpret_cast(childLParam); + constexpr size_t classNameLen = 32; + TCHAR className[classNameLen]{}; + ::GetClassName(hwnd, className, classNameLen); + auto style = ::GetWindowLongPtr(hwnd, GWL_STYLE); + + if (wcscmp(className, WC_BUTTON) == 0) + { + switch (style & BS_TYPEMASK) + { + case BS_CHECKBOX: + case BS_AUTOCHECKBOX: + case BS_3STATE: + case BS_AUTO3STATE: + case BS_RADIOBUTTON: + case BS_AUTORADIOBUTTON: + { + if ((style & BS_PUSHLIKE) != BS_PUSHLIKE) + { + ::SendMessage(hwnd, p._msg, p._wParam, p._lParam); + } + break; + } + + default: + { + break; + } + } + return TRUE; + } + + if (wcscmp(className, WC_EDIT) == 0) + { + bool hasScrollBar = ((style & WS_HSCROLL) == WS_HSCROLL) || ((style & WS_VSCROLL) == WS_VSCROLL); + if (hasScrollBar) + { + ::SendMessage(hwnd, p._msg, p._wParam, p._lParam); + } + return TRUE; + } + + if (wcscmp(className, WC_LISTBOX) == 0) + { + if ((style & LBS_COMBOBOX) != LBS_COMBOBOX) + { + bool hasScrollBar = ((style & WS_HSCROLL) == WS_HSCROLL) || ((style & WS_VSCROLL) == WS_VSCROLL); + if (hasScrollBar) + { + ::SendMessage(hwnd, p._msg, p._wParam, p._lParam); + } + } + return TRUE; + } + return TRUE; + }, reinterpret_cast(&p)); + } + void setDarkTitleBar(HWND hwnd) { constexpr DWORD win10Build2004 = 19041; diff --git a/PowerEditor/src/NppDarkMode.h b/PowerEditor/src/NppDarkMode.h index f14abca51..ffe9a6b06 100644 --- a/PowerEditor/src/NppDarkMode.h +++ b/PowerEditor/src/NppDarkMode.h @@ -222,6 +222,8 @@ namespace NppDarkMode ULONG autoSubclassAndThemePlugin(HWND hwnd, ULONG dmFlags); void autoSubclassAndThemeWindowNotify(HWND hwnd); + void sendMessageToChildControls(HWND hwndParent, UINT msg, WPARAM wParam, LPARAM lParam); + void setDarkTitleBar(HWND hwnd); void setDarkExplorerTheme(HWND hwnd); void setDarkScrollBar(HWND hwnd); diff --git a/PowerEditor/src/dpiAware.manifest b/PowerEditor/src/dpiAware.manifest index da6fae4f6..97fd51443 100644 --- a/PowerEditor/src/dpiAware.manifest +++ b/PowerEditor/src/dpiAware.manifest @@ -1,9 +1,14 @@ - - - true - - + + + true + + + system, unaware + + + false + + \ No newline at end of file diff --git a/PowerEditor/src/dpiManagerV2.cpp b/PowerEditor/src/dpiManagerV2.cpp new file mode 100644 index 000000000..f9d28288a --- /dev/null +++ b/PowerEditor/src/dpiManagerV2.cpp @@ -0,0 +1,184 @@ +// This file is part of Notepad++ project +// Copyright (c) 2024 ozone10 and Notepad++ team + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// at your option any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +#include "dpiManagerV2.h" + +template +bool ptrFn(HMODULE handle, P& pointer, const char* name) +{ + auto p = reinterpret_cast

(::GetProcAddress(handle, name)); + if (p != nullptr) + { + pointer = p; + return true; + } + return false; +} + +using fnGetDpiForSystem = UINT (WINAPI*)(VOID); +using fnGetDpiForWindow = UINT (WINAPI*)(HWND hwnd); +using fnGetSystemMetricsForDpi = int (WINAPI*)(int nIndex, UINT dpi); +using fnSystemParametersInfoForDpi = BOOL (WINAPI*)(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni, UINT dpi); +using fnSetThreadDpiAwarenessContext = DPI_AWARENESS_CONTEXT (WINAPI*)(DPI_AWARENESS_CONTEXT dpiContext); + +fnGetDpiForSystem _fnGetDpiForSystem = nullptr; +fnGetDpiForWindow _fnGetDpiForWindow = nullptr; +fnGetSystemMetricsForDpi _fnGetSystemMetricsForDpi = nullptr; +fnSystemParametersInfoForDpi _fnSystemParametersInfoForDpi = nullptr; +fnSetThreadDpiAwarenessContext _fnSetThreadDpiAwarenessContext = nullptr; + +void DPIManagerV2::initDpiAPI() +{ + if (NppDarkMode::isWindows10()) + { + HMODULE hUser32 = ::GetModuleHandleW(L"user32.dll"); + if (hUser32 != nullptr) + { + ptrFn(hUser32, _fnGetDpiForSystem, "GetDpiForSystem"); + ptrFn(hUser32, _fnGetDpiForWindow, "GetDpiForWindow"); + ptrFn(hUser32, _fnGetSystemMetricsForDpi, "GetSystemMetricsForDpi"); + ptrFn(hUser32, _fnSystemParametersInfoForDpi, "SystemParametersInfoForDpi"); + ptrFn(hUser32, _fnSetThreadDpiAwarenessContext, "SetThreadDpiAwarenessContext"); + } + } +} + +int DPIManagerV2::getSystemMetricsForDpi(int nIndex, UINT dpi) +{ + if (_fnGetSystemMetricsForDpi != nullptr) + { + return _fnGetSystemMetricsForDpi(nIndex, dpi); + } + return DPIManagerV2::scale(::GetSystemMetrics(nIndex), dpi); +} + +DPI_AWARENESS_CONTEXT DPIManagerV2::setThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT dpiContext) +{ + if (_fnSetThreadDpiAwarenessContext != nullptr) + { + return _fnSetThreadDpiAwarenessContext(dpiContext); + } + return NULL; +} + +UINT DPIManagerV2::getDpiForSystem() +{ + if (_fnGetDpiForSystem != nullptr) + { + return _fnGetDpiForSystem(); + } + + UINT dpi = USER_DEFAULT_SCREEN_DPI; + HDC hdc = ::GetDC(nullptr); + if (hdc != nullptr) + { + dpi = ::GetDeviceCaps(hdc, LOGPIXELSX); + ::ReleaseDC(nullptr, hdc); + } + return dpi; +} + +UINT DPIManagerV2::getDpiForWindow(HWND hWnd) +{ + if (_fnGetDpiForWindow != nullptr) + { + const auto dpi = _fnGetDpiForWindow(hWnd); + if (dpi > 0) + { + return dpi; + } + } + return getDpiForSystem(); +} + +void DPIManagerV2::setPositionDpi(LPARAM lParam, HWND hWnd) +{ + const auto prcNewWindow = reinterpret_cast(lParam); + + ::SetWindowPos(hWnd, + nullptr, + prcNewWindow->left, + prcNewWindow->top, + prcNewWindow->right - prcNewWindow->left, + prcNewWindow->bottom - prcNewWindow->top, + SWP_NOZORDER | SWP_NOACTIVATE); +} + +LOGFONT DPIManagerV2::getDefaultGUIFontForDpi(UINT dpi, FontType type) +{ + int result = 0; + LOGFONT lf{}; + NONCLIENTMETRICS ncm{}; + ncm.cbSize = sizeof(NONCLIENTMETRICS); + if (_fnSystemParametersInfoForDpi != nullptr + && (_fnSystemParametersInfoForDpi(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0, dpi) != FALSE)) + { + result = 2; + } + else if (::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0) != FALSE) + { + result = 1; + } + + if (result > 0) + { + switch (type) + { + case FontType::menu: + { + lf = ncm.lfMenuFont; + break; + } + + case FontType::status: + { + lf = ncm.lfStatusFont; + break; + } + + case FontType::caption: + { + lf = ncm.lfCaptionFont; + break; + } + + case FontType::smcaption: + { + lf = ncm.lfSmCaptionFont; + break; + } + //case FontType::message: + default: + { + lf = ncm.lfMessageFont; + break; + } + } + } + else // should not happen, fallback + { + auto hf = static_cast(::GetStockObject(DEFAULT_GUI_FONT)); + ::GetObject(hf, sizeof(LOGFONT), &lf); + } + + if (result < 2) + { + lf.lfHeight = scaleFont(lf.lfHeight, dpi); + } + + return lf; +} diff --git a/PowerEditor/src/dpiManagerV2.h b/PowerEditor/src/dpiManagerV2.h new file mode 100644 index 000000000..1ac12059f --- /dev/null +++ b/PowerEditor/src/dpiManagerV2.h @@ -0,0 +1,120 @@ +// This file is part of Notepad++ project +// Copyright (c) 2024 ozone10 and Notepad++ team + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// at your option any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +#pragma once +#include "NppDarkMode.h" + +class DPIManagerV2 +{ +public: + DPIManagerV2() { + setDpiWithSystem(); + } + virtual ~DPIManagerV2() = default; + + enum class FontType { menu, status, message, caption, smcaption }; + + static void initDpiAPI(); + + static int getSystemMetricsForDpi(int nIndex, UINT dpi); + static DPI_AWARENESS_CONTEXT setThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT dpiContext); + + static UINT getDpiForSystem(); + static UINT getDpiForWindow(HWND hWnd); + static UINT getDpiForParent(HWND hWnd) { + return getDpiForWindow(::GetParent(hWnd)); + } + + void setDpiWithSystem() { + _dpi = getDpiForSystem(); + } + + // parameter is WPARAM + void setDpiWP(WPARAM wParam) { + _dpi = LOWORD(wParam); + } + + void setDpi(UINT newDpi) { + _dpi = newDpi; + } + + void setDpi(HWND hWnd) { + setDpi(getDpiForWindow(hWnd)); + } + + void setDpiWithParent(HWND hWnd) { + setDpi(::GetParent(hWnd)); + } + + UINT getDpi() const { + return _dpi; + } + + static void setPositionDpi(LPARAM lParam, HWND hWnd); + + static int scale(int x, UINT dpi, UINT dpi2) { + return MulDiv(x, dpi, dpi2); + } + + static int scale(int x, UINT dpi) { + return scale(x, dpi, USER_DEFAULT_SCREEN_DPI); + } + + static int unscale(int x, UINT dpi) { + return scale(x, USER_DEFAULT_SCREEN_DPI, dpi); + } + + int scale(int x) { + return scale(x, _dpi); + } + + int unscale(int x) { + return unscale(x, _dpi); + } + + int scaleX(int x) { + return scale(x); + } + + int unscaleX(int x) { + return unscale(x); + } + + int scaleY(int y) { + return scale(y); + } + + int unscaleY(int y) { + return unscale(y); + } + + static int scaleFont(int pt, UINT dpi) { + return -(scale(pt, dpi, 72)); + } + + int scaleFont(int pt) { + return scaleFont(pt, _dpi); + } + + static LOGFONT getDefaultGUIFontForDpi(UINT dpi, FontType type = FontType::message); + static LOGFONT getDefaultGUIFontForDpi(HWND hWnd, FontType type = FontType::message) { + return getDefaultGUIFontForDpi(getDpiForWindow(hWnd), type); + } + +private: + UINT _dpi = USER_DEFAULT_SCREEN_DPI; +}; diff --git a/PowerEditor/src/winmain.cpp b/PowerEditor/src/winmain.cpp index 66401d6f2..f1db98ebf 100644 --- a/PowerEditor/src/winmain.cpp +++ b/PowerEditor/src/winmain.cpp @@ -20,6 +20,7 @@ #include "MiniDumper.h" //Write dump files #include "verifySignedfile.h" #include "NppDarkMode.h" +#include "dpiManagerV2.h" #include typedef std::vector ParamVector; @@ -502,6 +503,7 @@ int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE /*hPrevInstance NppGUI & nppGui = nppParameters.getNppGUI(); NppDarkMode::initDarkMode(); + DPIManagerV2::initDpiAPI(); bool doUpdateNpp = nppGui._autoUpdateOpt._doAutoUpdate; bool doUpdatePluginList = nppGui._autoUpdateOpt._doAutoUpdate; diff --git a/PowerEditor/visual.net/notepadPlus.Cpp.props b/PowerEditor/visual.net/notepadPlus.Cpp.props index 26609f63a..526604586 100644 --- a/PowerEditor/visual.net/notepadPlus.Cpp.props +++ b/PowerEditor/visual.net/notepadPlus.Cpp.props @@ -25,7 +25,7 @@ ..\src;..\src\MISC;..\src\MISC\Common;..\src\MISC\Exception;..\src\MISC\PluginsManager;..\src\MISC\Process;..\src\MISC\RegExt;..\src\MISC\md5;..\src\MISC\sha1;..\src\MISC\sha2;..\src\MISC\sha512;..\src\MISC\SysMsg;..\src\ScintillaComponent;..\src\Win32Explr;..\src\WinControls;..\src\WinControls\AboutDlg;..\src\WinControls\AnsiCharPanel;..\src\WinControls\ClipboardHistory;..\src\WinControls\ColourPicker;..\src\WinControls\ContextMenu;..\src\WinControls\DockingWnd;..\src\WinControls\DocumentMap;..\src\WinControls\FileBrowser;..\src\WinControls\FindCharsInRange;..\src\WinControls\FunctionList;..\src\WinControls\Grid;..\src\WinControls\ImageListSet;..\src\WinControls\OpenSaveFileDialog;..\src\WinControls\PluginsAdmin;..\src\WinControls\Preference;..\src\WinControls\ProjectPanel;..\src\WinControls\ReadDirectoryChanges;..\src\WinControls\shortcut;..\src\WinControls\SplitterContainer;..\src\WinControls\StaticDialog;..\src\WinControls\StaticDialog\RunDlg;..\src\WinControls\StatusBar;..\src\WinControls\TabBar;..\src\WinControls\TaskList;..\src\WinControls\ToolBar;..\src\WinControls\ToolTip;..\src\WinControls\TrayIcon;..\src\WinControls\TreeView;..\src\WinControls\VerticalFileSwitcher;..\src\WinControls\WindowsDlg;%(AdditionalIncludeDirectories) - WIN32;_WIN32_WINNT=_WIN32_WINNT_VISTA;_WINDOWS;OEMRESOURCE;NOMINMAX;_USE_64BIT_TIME_T;TIXML_USE_STL;TIXMLA_USE_STL;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;%(PreprocessorDefinitions) + WIN32;_WIN32_WINNT=_WIN32_WINNT_WIN7;NTDDI_VERSION=NTDDI_WIN7;_WINDOWS;OEMRESOURCE;NOMINMAX;_USE_64BIT_TIME_T;TIXML_USE_STL;TIXMLA_USE_STL;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;%(PreprocessorDefinitions) Async Level4 true diff --git a/PowerEditor/visual.net/notepadPlus.vcxproj b/PowerEditor/visual.net/notepadPlus.vcxproj index 97517da0b..7d6fba981 100755 --- a/PowerEditor/visual.net/notepadPlus.vcxproj +++ b/PowerEditor/visual.net/notepadPlus.vcxproj @@ -65,7 +65,6 @@ - @@ -114,6 +113,7 @@ + @@ -242,6 +242,7 @@ +