Skip to content

Commit

Permalink
Title bar background color and text color follow windows settings whe…
Browse files Browse the repository at this point in the history
…n not customized (WinMerge#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.
  • Loading branch information
sdottaka committed Nov 16, 2024
1 parent acf4b6d commit 44f94c0
Show file tree
Hide file tree
Showing 9 changed files with 138 additions and 77 deletions.
39 changes: 39 additions & 0 deletions Src/Common/AccentColor.cpp
Original file line number Diff line number Diff line change
@@ -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);
}
22 changes: 22 additions & 0 deletions Src/Common/AccentColor.h
Original file line number Diff line number Diff line change
@@ -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;
};
72 changes: 10 additions & 62 deletions Src/Common/MDITabBar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@
#include "IMDITab.h"
#include "cecolor.h"
#include "RoundedRectWithShadow.h"
#include <dwmapi.h>
#include <RegKey.h>
#pragma comment(lib, "dwmapi.lib")

#ifdef _DEBUG
#define new DEBUG_NEW
Expand Down Expand Up @@ -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;
}

Expand All @@ -98,67 +86,27 @@ 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<BYTE>(czclr >> 16), static_cast<BYTE>(czclr >> 8), static_cast<BYTE>(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<BYTE>(czclr >> 16);
const BYTE g = static_cast<BYTE>(czclr >> 8);
const BYTE b = static_cast<BYTE>(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()
{
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);
Expand All @@ -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]));
Expand Down Expand Up @@ -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());
Expand Down
14 changes: 4 additions & 10 deletions Src/Common/MDITabBar.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ class CMyTabCtrl : public CTabCtrl
, m_nTooltipTabItemIndex(-1)
, m_bOnTitleBar(false)
, m_bActive(false)
, m_dwInactiveTitleColor(0)
{}

protected:
Expand All @@ -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);
Expand All @@ -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
Expand Down Expand Up @@ -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;
};

/**
Expand All @@ -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(); }
Expand Down
11 changes: 6 additions & 5 deletions Src/MainFrm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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))
{
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions Src/Merge.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -913,6 +913,7 @@
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)$(TargetName)2.pch</PrecompiledHeaderOutputFile>
</ClCompile>
<ClCompile Include="Common\AccentColor.cpp" />
<ClCompile Include="Common\cio.cpp">
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)$(TargetName)2.pch</PrecompiledHeaderOutputFile>
Expand Down Expand Up @@ -1456,6 +1457,7 @@
<ClInclude Include="BasicFlatStatusBar.h" />
<ClInclude Include="ClipboardHistory.h" />
<ClInclude Include="ColorSchemes.h" />
<ClInclude Include="Common\AccentColor.h" />
<ClInclude Include="Common\SysColorHook.h" />
<ClInclude Include="MouseHook.h" />
<ClInclude Include="MenuBar.h" />
Expand Down
6 changes: 6 additions & 0 deletions Src/Merge.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,9 @@
<ClCompile Include="ColorSchemes.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Common\AccentColor.cpp">
<Filter>MFCGui\Common\Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="charsets.h">
Expand Down Expand Up @@ -1436,6 +1439,9 @@
<ClInclude Include="ColorSchemes.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Common\AccentColor.h">
<Filter>MFCGui\Common\Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="res\binarydiff.ico">
Expand Down
46 changes: 46 additions & 0 deletions Src/TitleBarHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "StdAfx.h"
#include "TitleBarHelper.h"
#include "AccentColor.h"

#if !defined(SM_CXPADDEDBORDER)
#define SM_CXPADDEDBORDER 92
Expand Down Expand Up @@ -288,3 +289,48 @@ COLORREF CTitleBarHelper::GetIntermediateColor(COLORREF a, COLORREF b, float rat
const uint8_t B = static_cast<int8_t>((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<BYTE>(czclr >> 16);
const BYTE g = static_cast<BYTE>(czclr >> 8);
const BYTE b = static_cast<BYTE>(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();
}
3 changes: 3 additions & 0 deletions Src/TitleBarHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down

0 comments on commit 44f94c0

Please sign in to comment.