Use modern subclass for URLCtrl

- delegate HFONT object management to the object instead of the parent, including dpi handling
- clean header includes

Fix #17149, close #17150
This commit is contained in:
ozone10 2025-11-05 19:37:36 +01:00 committed by Don Ho
parent 9ba9759a63
commit 62b985b19a
7 changed files with 92 additions and 92 deletions

View File

@ -158,12 +158,6 @@ intptr_t CALLBACK FolderStyleDialog::run_dlgProc(UINT Message, WPARAM wParam, LP
return SharedParametersDialog::run_dlgProc(Message, wParam, lParam); return SharedParametersDialog::run_dlgProc(Message, wParam, lParam);
} }
case WM_DPICHANGED_AFTERPARENT:
{
_pageLink.destroy();
return TRUE;
}
case WM_COMMAND: case WM_COMMAND:
{ {
switch (wParam) switch (wParam)
@ -200,11 +194,7 @@ intptr_t CALLBACK FolderStyleDialog::run_dlgProc(UINT Message, WPARAM wParam, LP
return SharedParametersDialog::run_dlgProc(Message, wParam, lParam); return SharedParametersDialog::run_dlgProc(Message, wParam, lParam);
} }
} }
case WM_DESTROY:
{
_pageLink.destroy();
return TRUE;
}
default : default :
return SharedParametersDialog::run_dlgProc(Message, wParam, lParam); return SharedParametersDialog::run_dlgProc(Message, wParam, lParam);
} }

View File

@ -45,7 +45,6 @@ public :
void destroy() override { void destroy() override {
//_emailLink.destroy(); //_emailLink.destroy();
_pageLink.destroy();
if (_hIcon != nullptr) if (_hIcon != nullptr)
{ {
::DestroyIcon(_hIcon); ::DestroyIcon(_hIcon);

View File

@ -16,8 +16,13 @@
#include "URLCtrl.h" #include "URLCtrl.h"
#include <commctrl.h>
#include "Common.h"
#include "NppConstants.h"
#include "NppDarkMode.h" #include "NppDarkMode.h"
#include "Parameters.h" #include "dpiManagerV2.h"
void URLCtrl::create(HWND itemHandle, const wchar_t * link, COLORREF linkColor) void URLCtrl::create(HWND itemHandle, const wchar_t * link, COLORREF linkColor)
@ -36,10 +41,7 @@ void URLCtrl::create(HWND itemHandle, const wchar_t * link, COLORREF linkColor)
_visitedColor = RGB(128,0,128); _visitedColor = RGB(128,0,128);
// subclass the static control // subclass the static control
_oldproc = reinterpret_cast<WNDPROC>(::SetWindowLongPtr(itemHandle, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(URLCtrlProc))); ::SetWindowSubclass(itemHandle, URLCtrlProc, static_cast<UINT_PTR>(SubclassID::first), reinterpret_cast<DWORD_PTR>(this));
// associate the URL structure with the static control
::SetWindowLongPtr(itemHandle, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
// save hwnd // save hwnd
_hSelf = itemHandle; _hSelf = itemHandle;
@ -58,10 +60,7 @@ void URLCtrl::create(HWND itemHandle, int cmd, HWND msgDest)
_linkColor = RGB(0,0,255); _linkColor = RGB(0,0,255);
// subclass the static control // subclass the static control
_oldproc = reinterpret_cast<WNDPROC>(::SetWindowLongPtr(itemHandle, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(URLCtrlProc))); ::SetWindowSubclass(itemHandle, URLCtrlProc, static_cast<UINT_PTR>(SubclassID::first), reinterpret_cast<DWORD_PTR>(this));
// associate the URL structure with the static control
::SetWindowLongPtr(itemHandle, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
// save hwnd // save hwnd
_hSelf = itemHandle; _hSelf = itemHandle;
@ -115,14 +114,24 @@ void URLCtrl::action()
} }
} }
LRESULT URLCtrl::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) LRESULT CALLBACK URLCtrl::URLCtrlProc(
HWND hwnd,
UINT Message,
WPARAM wParam,
LPARAM lParam,
UINT_PTR uIdSubclass,
DWORD_PTR dwRefData
)
{ {
auto* pRefData = reinterpret_cast<URLCtrl*>(dwRefData);
switch (Message) switch (Message)
{ {
// Free up the structure we allocated
case WM_NCDESTROY: case WM_NCDESTROY:
//HeapFree(GetProcessHeap(), 0, url); {
::RemoveWindowSubclass(hwnd, URLCtrlProc, uIdSubclass);
break; break;
}
// Paint the static control using our custom // Paint the static control using our custom
// colours, and with an underline text style // colours, and with an underline text style
@ -142,10 +151,10 @@ LRESULT URLCtrl::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
PAINTSTRUCT ps{}; PAINTSTRUCT ps{};
HDC hdc = ::BeginPaint(hwnd, &ps); HDC hdc = ::BeginPaint(hwnd, &ps);
if ((_linkColor == _visitedColor) || (_linkColor == NppDarkMode::getDarkerTextColor())) if ((pRefData->_linkColor == pRefData->_visitedColor) || (pRefData->_linkColor == NppDarkMode::getDarkerTextColor()))
{ {
_linkColor = NppDarkMode::isEnabled() ? NppDarkMode::getDarkerTextColor() : _visitedColor; pRefData->_linkColor = NppDarkMode::isEnabled() ? NppDarkMode::getDarkerTextColor() : pRefData->_visitedColor;
::SetTextColor(hdc, _linkColor); ::SetTextColor(hdc, pRefData->_linkColor);
} }
else if (NppDarkMode::isEnabled()) else if (NppDarkMode::isEnabled())
{ {
@ -153,23 +162,23 @@ LRESULT URLCtrl::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
} }
else else
{ {
::SetTextColor(hdc, _linkColor); ::SetTextColor(hdc, pRefData->_linkColor);
} }
::SetBkColor(hdc, getCtrlBgColor(GetParent(hwnd))); ///*::GetSysColor(COLOR_3DFACE)*/); ::SetBkColor(hdc, getCtrlBgColor(GetParent(hwnd))); ///*::GetSysColor(COLOR_3DFACE)*/);
// Create an underline font // Create an underline font
if (_hfUnderlined == nullptr) if (pRefData->_hfUnderlined == nullptr)
{ {
// Get the default GUI font // Get the default GUI font
LOGFONT lf{ DPIManagerV2::getDefaultGUIFontForDpi(::GetParent(hwnd)) }; LOGFONT lf{ DPIManagerV2::getDefaultGUIFontForDpi(::GetParent(hwnd)) };
lf.lfUnderline = TRUE; lf.lfUnderline = TRUE;
// Create a new font // Create a new font
_hfUnderlined = ::CreateFontIndirect(&lf); pRefData->_hfUnderlined = ::CreateFontIndirect(&lf);
} }
HANDLE hOld = SelectObject(hdc, _hfUnderlined); auto hOld = static_cast<HFONT>(::SelectObject(hdc, pRefData->_hfUnderlined));
// Draw the text! // Draw the text!
wchar_t szWinText[MAX_PATH] = { '\0' }; wchar_t szWinText[MAX_PATH] = { '\0' };
@ -183,9 +192,15 @@ LRESULT URLCtrl::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
return 0; return 0;
} }
case WM_DPICHANGED_AFTERPARENT:
{
pRefData->destroy();
return 0;
}
case WM_SETTEXT: case WM_SETTEXT:
{ {
LRESULT ret = ::CallWindowProc(_oldproc, hwnd, Message, wParam, lParam); const LRESULT ret = ::DefSubclassProc(hwnd, Message, wParam, lParam);
::InvalidateRect(hwnd, 0, 0); ::InvalidateRect(hwnd, 0, 0);
return ret; return ret;
} }
@ -193,44 +208,58 @@ LRESULT URLCtrl::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
//case WM_SETCURSOR: //case WM_SETCURSOR:
case WM_MOUSEMOVE: case WM_MOUSEMOVE:
{ {
::SetCursor(loadHandCursor()); ::SetCursor(pRefData->loadHandCursor());
return TRUE; return 0;
} }
case WM_LBUTTONDOWN: case WM_LBUTTONDOWN:
_clicking = true;
break;
case WM_LBUTTONUP:
if (_clicking)
{ {
_clicking = false; pRefData->_clicking = true;
break;
action();
} }
case WM_LBUTTONUP:
{
if (pRefData->_clicking)
{
pRefData->_clicking = false;
pRefData->action();
}
break; break;
}
//Support using space to activate this object //Support using space to activate this object
case WM_KEYDOWN: case WM_KEYDOWN:
{
if (wParam == VK_SPACE) if (wParam == VK_SPACE)
_clicking = true; pRefData->_clicking = true;
break; break;
}
case WM_KEYUP: case WM_KEYUP:
if (wParam == VK_SPACE && _clicking)
{ {
_clicking = false; if (wParam == VK_SPACE && pRefData->_clicking)
{
action(); pRefData->_clicking = false;
pRefData->action();
} }
break; break;
}
// A standard static control returns HTTRANSPARENT here, which // A standard static control returns HTTRANSPARENT here, which
// prevents us from receiving any mouse messages. So, return // prevents us from receiving any mouse messages. So, return
// HTCLIENT instead. // HTCLIENT instead.
case WM_NCHITTEST: case WM_NCHITTEST:
{
return HTCLIENT; return HTCLIENT;
} }
return ::CallWindowProc(_oldproc, hwnd, Message, wParam, lParam);
case WM_DESTROY:
{
pRefData->destroy();
break;
}
}
return ::DefSubclassProc(hwnd, Message, wParam, lParam);
} }

View File

@ -18,7 +18,7 @@
#pragma once #pragma once
#include "Window.h" #include "Window.h"
#include "Common.h" #include <string>
class URLCtrl : public Window { class URLCtrl : public Window {
public: public:
@ -36,14 +36,10 @@ protected :
HWND _msgDest = nullptr; HWND _msgDest = nullptr;
unsigned long _cmdID = 0; unsigned long _cmdID = 0;
WNDPROC _oldproc = nullptr;
COLORREF _linkColor = RGB(0xFF, 0xFF, 0xFF); COLORREF _linkColor = RGB(0xFF, 0xFF, 0xFF);
COLORREF _visitedColor = RGB(0xFF, 0xFF, 0xFF); COLORREF _visitedColor = RGB(0xFF, 0xFF, 0xFF);
bool _clicking = false; bool _clicking = false;
static LRESULT CALLBACK URLCtrlProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam){ static LRESULT CALLBACK URLCtrlProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
return ((URLCtrl *)(::GetWindowLongPtr(hwnd, GWLP_USERDATA)))->runProc(hwnd, Message, wParam, lParam);
}
LRESULT runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam); LRESULT runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam);
}; };

View File

@ -277,8 +277,6 @@ intptr_t CALLBACK WordStyleDlg::run_dlgProc(UINT Message, WPARAM wParam, LPARAM
{ {
_dpiManager.setDpiWP(wParam); _dpiManager.setDpiWP(wParam);
_goToSettings.destroy();
const int cpDynamicalSize = _dpiManager.scale(25); const int cpDynamicalSize = _dpiManager.scale(25);
move2CtrlRight(IDC_FG_STATIC, _pFgColour->getHSelf(), cpDynamicalSize, cpDynamicalSize); move2CtrlRight(IDC_FG_STATIC, _pFgColour->getHSelf(), cpDynamicalSize, cpDynamicalSize);
move2CtrlRight(IDC_BG_STATIC, _pBgColour->getHSelf(), cpDynamicalSize, cpDynamicalSize); move2CtrlRight(IDC_BG_STATIC, _pBgColour->getHSelf(), cpDynamicalSize, cpDynamicalSize);
@ -1399,8 +1397,6 @@ void WordStyleDlg::doDialog(bool isRTL)
void WordStyleDlg::destroy() void WordStyleDlg::destroy()
{ {
_goToSettings.destroy();
if (_pFgColour != nullptr) if (_pFgColour != nullptr)
{ {
_pFgColour->destroy(); _pFgColour->destroy();

View File

@ -72,9 +72,6 @@ class WordStyleDlg : public StaticDialog
public : public :
WordStyleDlg() = default; WordStyleDlg() = default;
~WordStyleDlg() override { ~WordStyleDlg() override {
_goToSettings.destroy();
_globalOverrideLinkTip.destroy();
if (_globalOverrideTip) if (_globalOverrideTip)
::DestroyWindow(_globalOverrideTip); ::DestroyWindow(_globalOverrideTip);
} }

View File

@ -1177,7 +1177,6 @@ intptr_t CALLBACK PluginsAdminDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR
case WM_DPICHANGED: case WM_DPICHANGED:
{ {
_dpiManager.setDpiWP(wParam); _dpiManager.setDpiWP(wParam);
_repoLink.destroy();
const size_t szColVer = _dpiManager.scale(100); const size_t szColVer = _dpiManager.scale(100);
const size_t szColName = szColVer * 2; const size_t szColName = szColVer * 2;
@ -1330,12 +1329,6 @@ intptr_t CALLBACK PluginsAdminDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR
return TRUE; return TRUE;
} }
case WM_DESTROY:
{
_repoLink.destroy();
return TRUE;
}
} }
return FALSE; return FALSE;
} }