Add message NPPM_DARKMODESUBCLASSANDTHEME

to allow plugin authors to use generic dark mode.
Unfortunately not for C# plugins.
related #13572

Fix #13574, close #13596
This commit is contained in:
ozone10 2023-04-26 16:59:37 +02:00 committed by Don Ho
parent b88456764b
commit e7f321f21a
11 changed files with 177 additions and 13 deletions

View File

@ -45,7 +45,7 @@ CPP_DEFINE := UNICODE _UNICODE OEMRESOURCE NOMINMAX _WIN32_WINNT=_WIN32_WINNT_VI
LD := $(CXX)
LDFLAGS := -municode -mwindows
LD_PATH :=
LD_LINK := comctl32 crypt32 dbghelp ole32 sensapi shlwapi uuid uxtheme version wininet wintrust
LD_LINK := comctl32 crypt32 dbghelp ole32 sensapi shlwapi uuid uxtheme version wininet wintrust dwmapi
LD_LINK += $(patsubst lib%.a,%,$(SCINTILLA_TARGET)) $(patsubst lib%.a,%,$(LEXILLA_TARGET)) imm32 msimg32 ole32 oleaut32
SUBMAKEFLAGS := -O --no-print-directory

View File

@ -380,7 +380,7 @@ SET(rcFiles
IF (WIN32)
SET(option WIN32)
SET(win32_LIBRARIES comctl32 shlwapi dbghelp version crypt32 wintrust sensapi wininet imm32 msimg32 uxtheme)
SET(win32_LIBRARIES comctl32 shlwapi dbghelp version crypt32 wintrust sensapi wininet imm32 msimg32 uxtheme dwmapi)
set(CMAKE_CXX_STANDARD 20)
if ( MSVC )
#do not use for mingw builds

View File

@ -271,6 +271,11 @@ bool IsWindows11() // or later OS version
return (g_buildNumber >= 22000);
}
const DWORD GetWindowsBuildNumber()
{
return g_buildNumber;
}
void InitDarkMode()
{
fnRtlGetNtVersionNumbers RtlGetNtVersionNumbers = nullptr;

View File

@ -17,3 +17,4 @@ void InitDarkMode();
void SetDarkMode(bool useDarkMode, bool fixDarkScrollbar);
bool IsWindows10();
bool IsWindows11();
const DWORD GetWindowsBuildNumber();

View File

@ -549,6 +549,47 @@ enum Platform { PF_UNKNOWN, PF_X86, PF_X64, PF_IA64, PF_ARM64 };
// void* NPPM_GETBOOKMARKID(0, 0)
// Returns the bookmark ID
#define NPPM_DARKMODESUBCLASSANDTHEME (NPPMSG + 112)
// ULONG NPPM_DARKMODESUBCLASSANDTHEME(ULONG dmFlags, HWND hwnd)
// Add support for generic dark mode.
//
// Docking panels don't need to call NPPM_DARKMODESUBCLASSANDTHEME for main hwnd.
// Subclassing is applied automatically unless DWS_USEOWNDARKMODE flag is used.
//
// Might not work properly in C# plugins.
//
// Returns succesful combinations of flags.
//
namespace NppDarkMode
{
// Standard flags for main parent after its children are initialized.
constexpr ULONG dmfInit = 0x0000000BUL;
// Standard flags for main parent usually used in NPPN_DARKMODECHANGED.
constexpr ULONG dmfHandleChange = 0x0000000CUL;
};
// Examples:
//
// - after controls initializations in WM_INITDIALOG, in WM_CREATE or after CreateWindow:
//
//auto success = static_cast<ULONG>(::SendMessage(nppData._nppHandle, NPPM_DARKMODESUBCLASSANDTHEME, static_cast<WPARAM>(NppDarkMode::dmfInit), reinterpret_cast<LPARAM>(mainHwnd)));
//
// - handling dark mode change:
//
//extern "C" __declspec(dllexport) void beNotified(SCNotification * notifyCode)
//{
// switch (notifyCode->nmhdr.code)
// {
// case NPPN_DARKMODECHANGED:
// {
// ::SendMessage(nppData._nppHandle, NPPM_DARKMODESUBCLASSANDTHEME, static_cast<WPARAM>(dmfHandleChange), reinterpret_cast<LPARAM>(mainHwnd));
// ::SetWindowPos(mainHwnd, nullptr, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); // to redraw titlebar and window
// break;
// }
// }
//}
// For RUNCOMMAND_USER

View File

@ -3110,6 +3110,11 @@ LRESULT Notepad_plus::process(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPa
return static_cast<LRESULT>(false);
}
case NPPM_DARKMODESUBCLASSANDTHEME:
{
return static_cast<LRESULT>(NppDarkMode::autoSubclassAndThemePlugin(reinterpret_cast<HWND>(lParam), static_cast<ULONG>(wParam)));
}
case NPPM_DOCLISTDISABLEPATHCOLUMN:
case NPPM_DOCLISTDISABLEEXTCOLUMN:
{

View File

@ -20,6 +20,7 @@
#include "DarkMode/DarkMode.h"
#include "DarkMode/UAHMenuBar.h"
#include <dwmapi.h>
#include <uxtheme.h>
#include <vssym32.h>
@ -33,6 +34,9 @@
#ifdef __GNUC__
#include <cmath>
#define WINAPI_LAMBDA WINAPI
#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
#endif
#else
#define WINAPI_LAMBDA
#endif
@ -40,6 +44,7 @@
// already added in project files
// keep for plugin authors
//#ifdef _MSC_VER
//#pragma comment(lib, "dwmapi.lib")
//#pragma comment(lib, "uxtheme.lib")
//#endif
@ -548,6 +553,11 @@ namespace NppDarkMode
return IsWindows11();
}
const DWORD getWindowsBuildNumber()
{
return GetWindowsBuildNumber();
}
COLORREF invertLightness(COLORREF c)
{
WORD h = 0;
@ -2511,16 +2521,15 @@ namespace NppDarkMode
case WM_NOTIFY:
{
auto nmhdr = reinterpret_cast<LPNMHDR>(lParam);
constexpr size_t classNameLen = 16;
TCHAR className[classNameLen]{};
GetClassName(nmhdr->hwndFrom, className, classNameLen);
const auto nmhdr = reinterpret_cast<LPNMHDR>(lParam);
switch (nmhdr->code)
{
case NM_CUSTOMDRAW:
{
constexpr size_t classNameLen = 16;
TCHAR className[classNameLen]{};
GetClassName(nmhdr->hwndFrom, className, classNameLen);
if (wcscmp(className, TOOLBARCLASSNAME) == 0)
{
return NppDarkMode::darkToolBarNotifyCustomDraw(lParam);
@ -2550,6 +2559,97 @@ namespace NppDarkMode
NppDarkMode::autoSubclassAndThemeChildControls(hwnd, true, g_isAtLeastWindows10);
}
ULONG autoSubclassAndThemePlugin(HWND hwnd, ULONG dmFlags)
{
// Used on parent of edit, listbox, static text, treeview, listview and toolbar controls.
// Should be used only one time on parent control after its creation
// even when starting in light mode.
// e.g. in WM_INITDIALOG, in WM_CREATE or after CreateWindow.
constexpr ULONG dmfSubclassParent = 0x00000001UL;
// Should be used only one time on main control/window after initializations of all its children controls
// even when starting in light mode.
// Will also use dmfSetThemeChildren flag.
// e.g. in WM_INITDIALOG, in WM_CREATE or after CreateWindow.
constexpr ULONG dmfSubclassChildren = 0x00000002UL;
// Will apply theme on buttons with style:
// BS_PUSHLIKE, BS_PUSHBUTTON, BS_DEFPUSHBUTTON, BS_SPLITBUTTON or BS_DEFSPLITBUTTON.
// Will apply theme for scrollbars on edit, listbox and rich edit controls.
// Will apply theme for tooltips on listview, treeview and toolbar buttons.
// Should be handled after controls initializations and in NPPN_DARKMODECHANGED.
// Requires at least Windows 10 to work properly.
constexpr ULONG dmfSetThemeChildren = 0x00000004UL;
// Set dark title bar.
// Should be handled after controls initializations and in NPPN_DARKMODECHANGED.
// Requires at least Windows 10 and WS_CAPTION style to work properly.
constexpr ULONG dmfSetTitleBar = 0x00000008UL;
// Will apply dark explorer theme.
// Used mainly for scrollbars and tooltips not handled with dmfSetThemeChildren.
// Might also change style for other elements.
// Should be handled after controls initializations and in NPPN_DARKMODECHANGED.
// Requires at least Windows 10 to work properly.
constexpr ULONG dmfSetThemeDirectly = 0x00000010UL;
// defined in Notepad_plus_msgs.h
//constexpr ULONG dmfInit = dmfSubclassParent | dmfSubclassChildren | dmfSetTitleBar; // 0x000000BUL
//constexpr ULONG dmfHandleChange = dmfSetThemeChildren | dmfSetTitleBar; // 0x000000CUL
constexpr ULONG dmfRequiredMask = dmfSubclassParent | dmfSubclassChildren | dmfSetThemeChildren | dmfSetTitleBar | dmfSetThemeDirectly;
//constexpr ULONG dmfAllMask = dmfSubclassParent | dmfSubclassChildren | dmfSetThemeChildren | dmfSetTitleBar | dmfSetThemeDirectly;
if (hwnd == nullptr || (dmFlags & dmfRequiredMask) == 0)
{
return 0;
}
auto dmfBitwiseCheck = [dmFlags](ULONG flag) -> bool {
return (dmFlags & flag) == flag;
};
ULONG result = 0UL;
if (dmfBitwiseCheck(dmfSubclassParent))
{
const bool success = ::SetWindowSubclass(hwnd, PluginDockWindowSubclass, g_pluginDockWindowSubclassID, 0) == TRUE;
if (success)
{
result |= dmfSubclassParent;
}
}
const bool subclassChildren = dmfBitwiseCheck(dmfSubclassChildren);
if (dmfBitwiseCheck(dmfSetThemeChildren) || subclassChildren)
{
NppDarkMode::autoSubclassAndThemeChildControls(hwnd, subclassChildren, g_isAtLeastWindows10);
result |= dmfSetThemeChildren;
if (subclassChildren)
{
result |= dmfSubclassChildren;
}
}
if (dmfBitwiseCheck(dmfSetTitleBar))
{
const auto style = ::GetWindowLongPtr(hwnd, GWL_STYLE);
if (NppDarkMode::isExperimentalSupported() && ((style & WS_CAPTION) == WS_CAPTION))
{
NppDarkMode::setDarkTitleBar(hwnd);
result |= dmfSetTitleBar;
}
}
if (dmfBitwiseCheck(dmfSetThemeDirectly))
{
if (NppDarkMode::isWindows10())
{
NppDarkMode::setDarkExplorerTheme(hwnd);
result |= dmfSetThemeDirectly;
}
}
return result;
}
constexpr UINT_PTR g_windowNotifySubclassID = 42;
LRESULT CALLBACK WindowNotifySubclass(
@ -2760,8 +2860,17 @@ namespace NppDarkMode
void setDarkTitleBar(HWND hwnd)
{
NppDarkMode::allowDarkModeForWindow(hwnd, NppDarkMode::isEnabled());
NppDarkMode::setTitleBarThemeColor(hwnd);
constexpr DWORD win10Build2004 = 19041;
if (NppDarkMode::getWindowsBuildNumber() >= win10Build2004)
{
BOOL value = NppDarkMode::isEnabled() ? TRUE : FALSE;
::DwmSetWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
}
else
{
NppDarkMode::allowDarkModeForWindow(hwnd, NppDarkMode::isEnabled());
NppDarkMode::setTitleBarThemeColor(hwnd);
}
}
void setDarkExplorerTheme(HWND hwnd)

View File

@ -119,6 +119,7 @@ namespace NppDarkMode
bool isWindows10();
bool isWindows11();
const DWORD getWindowsBuildNumber();
COLORREF invertLightness(COLORREF c);
COLORREF invertLightnessSofter(COLORREF c);
@ -216,6 +217,7 @@ namespace NppDarkMode
LRESULT darkTreeViewNotifyCustomDraw(LPARAM lParam);
void autoSubclassAndThemePluginDockWindow(HWND hwnd);
ULONG autoSubclassAndThemePlugin(HWND hwnd, ULONG dmFlags);
void autoSubclassAndThemeWindowNotify(HWND hwnd);
bool subclassTabUpDownControl(HWND hwnd);

View File

@ -20,7 +20,7 @@
intptr_t CALLBACK GoToLineDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM)
{
switch (message)
switch (message)
{
case WM_INITDIALOG :
{
@ -135,6 +135,7 @@ intptr_t CALLBACK GoToLineDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM)
break;
}
}
return FALSE;
}
default :

View File

@ -294,7 +294,7 @@ bool FunctionListPanel::serialize(const generic_string & outputFilename)
for (auto & i : j[nodesLabel])
{
if (nodeName == i[nameLabel])
if (nodeName == std::string{ i[nameLabel] })
{
i[leavesLabel].push_back(leafName.c_str());
isFound = true;

View File

@ -42,7 +42,7 @@
<AnalyzeExternalRuleset>NativeRecommendedRules.ruleset</AnalyzeExternalRuleset>
</ClCompile>
<Link>
<AdditionalDependencies>comctl32.lib;shlwapi.lib;shell32.lib;Dbghelp.lib;Version.lib;Crypt32.lib;wintrust.lib;Sensapi.lib;wininet.lib;imm32.lib;msimg32.lib;uxtheme.lib;libscintilla.lib;liblexilla.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>comctl32.lib;shlwapi.lib;shell32.lib;Dbghelp.lib;Version.lib;Crypt32.lib;wintrust.lib;Sensapi.lib;wininet.lib;imm32.lib;msimg32.lib;uxtheme.lib;dwmapi.lib;libscintilla.lib;liblexilla.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ShowProgress>LinkVerboseLib</ShowProgress>
<OutputFile>$(OutDir)notepad++.exe</OutputFile>
<Version>1.0</Version>