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

View File

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

View File

@ -16,8 +16,13 @@
#include "URLCtrl.h"
#include <commctrl.h>
#include "Common.h"
#include "NppConstants.h"
#include "NppDarkMode.h"
#include "Parameters.h"
#include "dpiManagerV2.h"
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);
// subclass the static control
_oldproc = reinterpret_cast<WNDPROC>(::SetWindowLongPtr(itemHandle, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(URLCtrlProc)));
// associate the URL structure with the static control
::SetWindowLongPtr(itemHandle, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
::SetWindowSubclass(itemHandle, URLCtrlProc, static_cast<UINT_PTR>(SubclassID::first), reinterpret_cast<DWORD_PTR>(this));
// save hwnd
_hSelf = itemHandle;
@ -58,10 +60,7 @@ void URLCtrl::create(HWND itemHandle, int cmd, HWND msgDest)
_linkColor = RGB(0,0,255);
// subclass the static control
_oldproc = reinterpret_cast<WNDPROC>(::SetWindowLongPtr(itemHandle, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(URLCtrlProc)));
// associate the URL structure with the static control
::SetWindowLongPtr(itemHandle, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
::SetWindowSubclass(itemHandle, URLCtrlProc, static_cast<UINT_PTR>(SubclassID::first), reinterpret_cast<DWORD_PTR>(this));
// save hwnd
_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)
{
// Free up the structure we allocated
case WM_NCDESTROY:
//HeapFree(GetProcessHeap(), 0, url);
{
::RemoveWindowSubclass(hwnd, URLCtrlProc, uIdSubclass);
break;
}
// Paint the static control using our custom
// colours, and with an underline text style
@ -142,10 +151,10 @@ LRESULT URLCtrl::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
PAINTSTRUCT 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;
::SetTextColor(hdc, _linkColor);
pRefData->_linkColor = NppDarkMode::isEnabled() ? NppDarkMode::getDarkerTextColor() : pRefData->_visitedColor;
::SetTextColor(hdc, pRefData->_linkColor);
}
else if (NppDarkMode::isEnabled())
{
@ -153,23 +162,23 @@ LRESULT URLCtrl::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
}
else
{
::SetTextColor(hdc, _linkColor);
::SetTextColor(hdc, pRefData->_linkColor);
}
::SetBkColor(hdc, getCtrlBgColor(GetParent(hwnd))); ///*::GetSysColor(COLOR_3DFACE)*/);
// Create an underline font
if (_hfUnderlined == nullptr)
if (pRefData->_hfUnderlined == nullptr)
{
// Get the default GUI font
LOGFONT lf{ DPIManagerV2::getDefaultGUIFontForDpi(::GetParent(hwnd)) };
lf.lfUnderline = TRUE;
// 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!
wchar_t szWinText[MAX_PATH] = { '\0' };
@ -183,9 +192,15 @@ LRESULT URLCtrl::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
return 0;
}
case WM_DPICHANGED_AFTERPARENT:
{
pRefData->destroy();
return 0;
}
case WM_SETTEXT:
{
LRESULT ret = ::CallWindowProc(_oldproc, hwnd, Message, wParam, lParam);
const LRESULT ret = ::DefSubclassProc(hwnd, Message, wParam, lParam);
::InvalidateRect(hwnd, 0, 0);
return ret;
}
@ -193,44 +208,58 @@ LRESULT URLCtrl::runProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
//case WM_SETCURSOR:
case WM_MOUSEMOVE:
{
::SetCursor(loadHandCursor());
return TRUE;
::SetCursor(pRefData->loadHandCursor());
return 0;
}
case WM_LBUTTONDOWN:
_clicking = true;
break;
case WM_LBUTTONUP:
if (_clicking)
{
_clicking = false;
action();
pRefData->_clicking = true;
break;
}
case WM_LBUTTONUP:
{
if (pRefData->_clicking)
{
pRefData->_clicking = false;
pRefData->action();
}
break;
}
//Support using space to activate this object
case WM_KEYDOWN:
{
if (wParam == VK_SPACE)
_clicking = true;
pRefData->_clicking = true;
break;
}
case WM_KEYUP:
if (wParam == VK_SPACE && _clicking)
{
_clicking = false;
action();
if (wParam == VK_SPACE && pRefData->_clicking)
{
pRefData->_clicking = false;
pRefData->action();
}
break;
}
// A standard static control returns HTTRANSPARENT here, which
// prevents us from receiving any mouse messages. So, return
// HTCLIENT instead.
case WM_NCHITTEST:
{
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
#include "Window.h"
#include "Common.h"
#include <string>
class URLCtrl : public Window {
public:
@ -36,14 +36,10 @@ protected :
HWND _msgDest = nullptr;
unsigned long _cmdID = 0;
WNDPROC _oldproc = nullptr;
COLORREF _linkColor = RGB(0xFF, 0xFF, 0xFF);
COLORREF _visitedColor = RGB(0xFF, 0xFF, 0xFF);
bool _clicking = false;
static LRESULT CALLBACK URLCtrlProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam){
return ((URLCtrl *)(::GetWindowLongPtr(hwnd, GWLP_USERDATA)))->runProc(hwnd, Message, wParam, lParam);
}
static LRESULT CALLBACK URLCtrlProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
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);
_goToSettings.destroy();
const int cpDynamicalSize = _dpiManager.scale(25);
move2CtrlRight(IDC_FG_STATIC, _pFgColour->getHSelf(), cpDynamicalSize, cpDynamicalSize);
move2CtrlRight(IDC_BG_STATIC, _pBgColour->getHSelf(), cpDynamicalSize, cpDynamicalSize);
@ -1399,8 +1397,6 @@ void WordStyleDlg::doDialog(bool isRTL)
void WordStyleDlg::destroy()
{
_goToSettings.destroy();
if (_pFgColour != nullptr)
{
_pFgColour->destroy();

View File

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

View File

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