From 44f94c0e9a91143bf3285cf679adf35ffd063427 Mon Sep 17 00:00:00 2001 From: Takashi Sawanaka Date: Sat, 16 Nov 2024 22:00:00 +0900 Subject: [PATCH] Title bar background color and text color follow windows settings when not customized (#2505) (2) - Use accent color as titlebar color only if "Show accent color in title bars and window borders" is set to "On" in the Windows Settings > Personalization > Colors page. - For Windows XP support, I would like to avoid using DwmGetColorizationColor(). I would like to get accent color from registry. - WinMerge originally used COLOR_ACTIVECAPTION and COLOR_INACTIVECAPTION, but I don't want to use them as titlebar color because they are documented as unsupported in Windows 10 and later. - Move accent color related handling from CMDITabBar to CTitleBarHelper. --- Src/Common/AccentColor.cpp | 39 +++++++++++++++++++++ Src/Common/AccentColor.h | 22 ++++++++++++ Src/Common/MDITabBar.cpp | 72 ++++++-------------------------------- Src/Common/MDITabBar.h | 14 +++----- Src/MainFrm.cpp | 11 +++--- Src/Merge.vcxproj | 2 ++ Src/Merge.vcxproj.filters | 6 ++++ Src/TitleBarHelper.cpp | 46 ++++++++++++++++++++++++ Src/TitleBarHelper.h | 3 ++ 9 files changed, 138 insertions(+), 77 deletions(-) create mode 100644 Src/Common/AccentColor.cpp create mode 100644 Src/Common/AccentColor.h diff --git a/Src/Common/AccentColor.cpp b/Src/Common/AccentColor.cpp new file mode 100644 index 00000000000..12b8b40d261 --- /dev/null +++ b/Src/Common/AccentColor.cpp @@ -0,0 +1,39 @@ +// Copyright (c) 2024 Takashi Sawanaka +// SPDX-License-Identifier: BSL-1.0 +/** + * @file AccentColor.cpp + * + * @brief Implementation of the CAccentColor class + */ + +#include "StdAfx.h" +#include "AccentColor.h" +#include "RegKey.h" + +CAccentColor::CAccentColor() + : m_accentColor(CLR_NONE) + , m_accentColorInactive(CLR_NONE) + , m_colorPrevalence(false) +{ + Reload(); +} + +CAccentColor& CAccentColor::Get() +{ + static CAccentColor s_accentColor; + return s_accentColor; +} + +void CAccentColor::Reload() +{ + CRegKeyEx reg; + if (ERROR_SUCCESS != reg.Open(HKEY_CURRENT_USER, _T("SOFTWARE\\Microsoft\\Windows\\DWM"))) + return; + m_accentColor = reg.ReadDword(_T("AccentColor"), CLR_NONE); + if (m_accentColor != CLR_NONE) + m_accentColor &= 0xffffff; + m_accentColorInactive = reg.ReadDword(_T("AccentColorInactive"), CLR_NONE); + if (m_accentColorInactive != CLR_NONE) + m_accentColorInactive &= 0xffffff; + m_colorPrevalence = reg.ReadDword(_T("ColorPrevalence"), false); +} diff --git a/Src/Common/AccentColor.h b/Src/Common/AccentColor.h new file mode 100644 index 00000000000..d91a835a4f8 --- /dev/null +++ b/Src/Common/AccentColor.h @@ -0,0 +1,22 @@ +// Copyright (c) 2024 Takashi Sawanaka +// SPDX-License-Identifier: BSL-1.0 +/** + * @file AccentColor.h + * + * @brief Declaration file for CAccentColor class + */ + +class CAccentColor +{ +public: + CAccentColor(); + COLORREF GetAccentColor() const { return m_accentColor; }; + COLORREF GetAccentColorInactive() const { return m_accentColorInactive; } + bool GetColorPrevalence() const { return m_colorPrevalence; } + void Reload(); + static CAccentColor& Get(); +private: + COLORREF m_accentColor; + COLORREF m_accentColorInactive; + bool m_colorPrevalence; +}; diff --git a/Src/Common/MDITabBar.cpp b/Src/Common/MDITabBar.cpp index 8c86f134c66..fc6651c653d 100644 --- a/Src/Common/MDITabBar.cpp +++ b/Src/Common/MDITabBar.cpp @@ -9,9 +9,6 @@ #include "IMDITab.h" #include "cecolor.h" #include "RoundedRectWithShadow.h" -#include -#include -#pragma comment(lib, "dwmapi.lib") #ifdef _DEBUG #define new DEBUG_NEW @@ -72,15 +69,6 @@ BOOL CMyTabCtrl::Create(CMDIFrameWnd* pMainFrame, CWnd* pParent) m_pMainFrame = pMainFrame; m_tooltips.Create(m_pMainFrame, TTS_NOPREFIX); m_tooltips.AddTool(this, _T("")); - CRegKeyEx reg; - constexpr tchar_t* AccentColorInactive = _T("AccentColorInactive"); - constexpr tchar_t* RegDir = _T("SOFTWARE\\Microsoft\\Windows\\DWM"); - if (ERROR_SUCCESS == reg.Open(HKEY_CURRENT_USER, RegDir)) - { - const auto clr = reg.ReadDword(AccentColorInactive, 0); - if (clr) - m_dwInactiveTitleColor = RGB(GetRValue(clr), GetGValue(clr), GetBValue(clr)); - } return TRUE; } @@ -98,46 +86,10 @@ BOOL CMyTabCtrl::PreTranslateMessage(MSG* pMsg) return __super::PreTranslateMessage(pMsg); } -COLORREF CMyTabCtrl::GetDwmTitlebarColors() -{ - if (!m_bActive) - { - if (m_dwInactiveTitleColor) - return m_dwInactiveTitleColor; - return GetSysColor(COLOR_INACTIVECAPTION); - } - DWORD czclr = 0; - BOOL opaqueBlend = FALSE; - HRESULT hr = DwmGetColorizationColor(&czclr, &opaqueBlend); - if (SUCCEEDED(hr)) - { - return RGB(static_cast(czclr >> 16), static_cast(czclr >> 8), static_cast(czclr)); - } - return GetSysColor(COLOR_ACTIVECAPTION); -} - -COLORREF CMyTabCtrl::GetDwmTitleTextColors() +void CMyTabCtrl::SetActive(bool bActive) { - if (!m_bActive) - { - COLORREF clr = m_dwInactiveTitleColor ? m_dwInactiveTitleColor : GetSysColor(COLOR_INACTIVECAPTION); - if (GetRValue(clr) < 128 && GetGValue(clr) < 128 && GetBValue(clr) < 128) - return RGB(245, 245, 245); - return RGB(10, 10, 10); - } - DWORD czclr = 0; - BOOL opaqueBlend = FALSE; - HRESULT hr = DwmGetColorizationColor(&czclr, &opaqueBlend); - if (SUCCEEDED(hr)) - { - const BYTE r = static_cast(czclr >> 16); - const BYTE g = static_cast(czclr >> 8); - const BYTE b = static_cast(czclr); - if (r < 128 && g < 128 && b < 128) - return RGB(255, 255, 255); - return RGB(0, 0, 0); - } - return GetSysColor(COLOR_CAPTIONTEXT); + CTitleBarHelper::ReloadAccentColor(); + m_bActive = bActive; } static inline COLORREF getTextColor() @@ -145,20 +97,16 @@ static inline COLORREF getTextColor() return GetSysColor(COLOR_WINDOWTEXT); } -COLORREF CMyTabCtrl::GetBackColor() +COLORREF CMyTabCtrl::GetBackColor() const { const COLORREF clr = GetSysColor(COLOR_3DFACE); if (!m_bOnTitleBar) return clr; - if (!m_bCustomSystemColor) - return GetDwmTitlebarColors(); - const COLORREF bgclr = m_bActive ? - RGB(GetRValue(clr), std::clamp(GetGValue(clr) + 8, 0, 255), std::clamp(GetBValue(clr) + 8, 0, 255)) - : clr; - return bgclr; + return CTitleBarHelper::GetBackColor(m_bActive); } static inline bool IsHighContrastEnabled() + { HIGHCONTRAST hc = { sizeof(HIGHCONTRAST) }; SystemParametersInfo(SPI_GETHIGHCONTRAST, sizeof(hc), &hc, 0); @@ -179,8 +127,8 @@ void CMyTabCtrl::OnPaint() const int nCount = GetItemCount(); if (nCount == 0) { - const COLORREF winTitleTextColor = (m_bOnTitleBar && !m_bCustomSystemColor) ? - GetDwmTitleTextColors() : GetSysColor(COLOR_WINDOWTEXT); + const COLORREF winTitleTextColor = m_bOnTitleBar ? + CTitleBarHelper::GetTextColor(m_bActive) : getTextColor(); dc.SetTextColor(winTitleTextColor); TCHAR szBuf[256]; AfxGetMainWnd()->GetWindowText(szBuf, sizeof(szBuf) / sizeof(szBuf[0])); @@ -445,8 +393,8 @@ void CMyTabCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) } else { - const COLORREF txtclr = (m_bOnTitleBar && !m_bCustomSystemColor) ? - GetDwmTitleTextColors() : GetSysColor(COLOR_BTNTEXT); + const COLORREF txtclr = m_bOnTitleBar ? + CTitleBarHelper::GetTextColor(m_bActive) : GetSysColor(COLOR_BTNTEXT); SetTextColor(lpDraw->hDC, txtclr); } CSize iconsize(determineIconSize(), determineIconSize()); diff --git a/Src/Common/MDITabBar.h b/Src/Common/MDITabBar.h index 4a529b79d9e..a7bfd3bc9d3 100644 --- a/Src/Common/MDITabBar.h +++ b/Src/Common/MDITabBar.h @@ -24,7 +24,6 @@ class CMyTabCtrl : public CTabCtrl , m_nTooltipTabItemIndex(-1) , m_bOnTitleBar(false) , m_bActive(false) - , m_dwInactiveTitleColor(0) {} protected: @@ -34,13 +33,11 @@ class CMyTabCtrl : public CTabCtrl bool m_bCloseButtonDown; bool m_bOnTitleBar; bool m_bActive; - bool m_bCustomSystemColor; CRect m_rcCurrentCloseButtom; int m_nDraggingTabItemIndex; int m_nTooltipTabItemIndex; /**< Index of the tab displaying tooltip */ CMDIFrameWnd *m_pMainFrame; CToolTipCtrl m_tooltips; /**< Tooltip for the tab */ - COLORREF m_dwInactiveTitleColor; public: BOOL Create(CMDIFrameWnd* pMainFrame, CWnd* pParent); @@ -49,10 +46,8 @@ class CMyTabCtrl : public CTabCtrl void UpdateTabs(); void SetOnTitleBar(bool onTitleBar) { m_bOnTitleBar = onTitleBar; } bool GetActive() const { return m_bActive; } - void SetActive(bool bActive) { m_bActive = bActive; } - COLORREF GetBackColor(); - bool GetCustomSystemColor() const { return m_bCustomSystemColor; } - void SetCustomSystemColor(bool bCustom) { m_bCustomSystemColor = bCustom; } + void SetActive(bool bActive); + COLORREF GetBackColor() const; // Overrides // ClassWizard generated virtual function overrides @@ -86,8 +81,8 @@ class CMyTabCtrl : public CTabCtrl void SwapTabs(int nIndexA, int nIndexB); int GetMaxTitleLength() const; void UpdateToolTips(int index); - COLORREF GetDwmTitleTextColors(); - COLORREF GetDwmTitlebarColors(); + COLORREF GetDwmTitleTextColor() const; + COLORREF GetDwmTitlebarColor() const; }; /** @@ -111,7 +106,6 @@ class CMDITabBar : public CControlBar virtual ~CMDITabBar() {} BOOL Update(bool bOnTitleBar, bool bMaxmized); void UpdateActive(bool bActive); - void UpdateCustomSystemColor(bool bCustom) { m_tabCtrl.SetCustomSystemColor(bCustom); }; BOOL Create(CMDIFrameWnd* pParentWnd); void UpdateTabs() { m_tabCtrl.UpdateTabs(); } bool GetAutoMaxWidth() const { return m_tabCtrl.GetAutoMaxWidth(); } diff --git a/Src/MainFrm.cpp b/Src/MainFrm.cpp index 762d189dca6..7c49e3ec931 100644 --- a/Src/MainFrm.cpp +++ b/Src/MainFrm.cpp @@ -71,6 +71,10 @@ #include "DirWatcher.h" #include "Win_VersionHelper.h" +#if !defined(SM_CXPADDEDBORDER) +#define SM_CXPADDEDBORDER 92 +#endif + using std::vector; using boost::begin; using boost::end; @@ -416,7 +420,6 @@ int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) m_bTabsOnTitleBar = GetOptionsMgr()->GetBool(OPT_TABBAR_ON_TITLEBAR); m_wndTabBar.Update(m_bTabsOnTitleBar.value_or(false), false); - m_wndTabBar.UpdateCustomSystemColor(GetOptionsMgr()->GetBool(OPT_SYSCOLOR_HOOK_ENABLED)); if (m_bTabsOnTitleBar.value_or(false) && !m_wndTabBar.Create(this)) { @@ -1235,11 +1238,9 @@ void CMainFrame::OnOptions() for (auto pImgMergeFrame : GetAllImgMergeFrames()) pImgMergeFrame->RefreshOptions(); - const bool optSysColorHookEnabled = GetOptionsMgr()->GetBool(OPT_SYSCOLOR_HOOK_ENABLED); - if (sysColorHookEnabled != optSysColorHookEnabled || - sysColorsSerialized != GetOptionsMgr()->GetString(OPT_SYSCOLOR_HOOK_COLORS)) + if (sysColorHookEnabled != GetOptionsMgr()->GetBool(OPT_SYSCOLOR_HOOK_ENABLED) || + sysColorsSerialized != GetOptionsMgr()->GetString(OPT_SYSCOLOR_HOOK_COLORS)) { - m_wndTabBar.UpdateCustomSystemColor(optSysColorHookEnabled); theApp.ReloadCustomSysColors(); AfxGetMainWnd()->SendMessage(WM_SYSCOLORCHANGE); RedrawWindow(nullptr, nullptr, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE | RDW_ALLCHILDREN); diff --git a/Src/Merge.vcxproj b/Src/Merge.vcxproj index 70b254c83c8..c64170e1df5 100644 --- a/Src/Merge.vcxproj +++ b/Src/Merge.vcxproj @@ -913,6 +913,7 @@ pch.h $(IntDir)$(TargetName)2.pch + pch.h $(IntDir)$(TargetName)2.pch @@ -1456,6 +1457,7 @@ + diff --git a/Src/Merge.vcxproj.filters b/Src/Merge.vcxproj.filters index b16d87e59ca..045360bfa74 100644 --- a/Src/Merge.vcxproj.filters +++ b/Src/Merge.vcxproj.filters @@ -750,6 +750,9 @@ Source Files + + MFCGui\Common\Source Files + @@ -1436,6 +1439,9 @@ Header Files + + MFCGui\Common\Header Files + diff --git a/Src/TitleBarHelper.cpp b/Src/TitleBarHelper.cpp index 692758cc70d..5135a78a63d 100644 --- a/Src/TitleBarHelper.cpp +++ b/Src/TitleBarHelper.cpp @@ -8,6 +8,7 @@ #include "StdAfx.h" #include "TitleBarHelper.h" +#include "AccentColor.h" #if !defined(SM_CXPADDEDBORDER) #define SM_CXPADDEDBORDER 92 @@ -288,3 +289,48 @@ COLORREF CTitleBarHelper::GetIntermediateColor(COLORREF a, COLORREF b, float rat const uint8_t B = static_cast((GetBValue(a) - GetBValue(b)) * ratio) + GetBValue(b); return RGB(R, G, B); } + +COLORREF CTitleBarHelper::GetBackColor(bool bActive) +{ + if (!CAccentColor::Get().GetColorPrevalence()) + { + const COLORREF clr = GetSysColor(COLOR_3DFACE); + const COLORREF bgclr = bActive ? + RGB(GetRValue(clr), std::clamp(GetGValue(clr) + 8, 0, 255), std::clamp(GetBValue(clr) + 8, 0, 255)) + : clr; + return bgclr; + } + const COLORREF czclr = (!bActive) ? + CAccentColor::Get().GetAccentColorInactive() : + CAccentColor::Get().GetAccentColor(); + return czclr != CLR_NONE ? czclr : GetSysColor(COLOR_3DFACE); +} + +COLORREF CTitleBarHelper::GetTextColor(bool bActive) +{ + if (!CAccentColor::Get().GetColorPrevalence()) + return GetSysColor(COLOR_BTNTEXT); + if (!bActive) + { + COLORREF clr = GetSysColor(COLOR_3DFACE); + if (GetRValue(clr) < 128 && GetGValue(clr) < 128 && GetBValue(clr) < 128) + return RGB(245, 245, 245); + return RGB(10, 10, 10); + } + const COLORREF czclr = CAccentColor::Get().GetAccentColor(); + if (czclr != CLR_NONE) + { + const BYTE r = static_cast(czclr >> 16); + const BYTE g = static_cast(czclr >> 8); + const BYTE b = static_cast(czclr); + if (r < 128 && g < 128 && b < 128) + return RGB(255, 255, 255); + return RGB(0, 0, 0); + } + return GetSysColor(COLOR_BTNTEXT); +} + +void CTitleBarHelper::ReloadAccentColor() +{ + CAccentColor::Get().Reload(); +} diff --git a/Src/TitleBarHelper.h b/Src/TitleBarHelper.h index 71a86de8b45..b4e0b8eef0c 100644 --- a/Src/TitleBarHelper.h +++ b/Src/TitleBarHelper.h @@ -23,6 +23,9 @@ class CTitleBarHelper { void SetMaximized(bool maximized) { m_maximized = maximized; } bool GetMaximized() const { return m_maximized; } void SetSize(int cx, int cy); + static COLORREF GetBackColor(bool bActive); + static COLORREF GetTextColor(bool bActive); + static void ReloadAccentColor(); LRESULT OnNcHitTest(CPoint pt); void OnNcMouseMove(UINT nHitTest, CPoint point); void OnNcMouseLeave();