Skip to content

Commit

Permalink
The previous patch caused artifacts because it relied on an order of …
Browse files Browse the repository at this point in the history
…messages that turned out to not be guaranteed, this doesn't rely on such an order. Also removed SubclassSpinBox function and moved the code from that to be handled via the WM_PARENTNOTIFY message in RunProc.
  • Loading branch information
Wallby committed Feb 1, 2024
1 parent adc19be commit 7d041c3
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 48 deletions.
91 changes: 45 additions & 46 deletions src/TabBar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ CTabBar::CTabBar(HINSTANCE hInst)
, m_tabBarDefaultProc(nullptr)
, m_tabBarSpinDefaultProc(nullptr)
, m_spin(nullptr)
, m_bIsSpinVisible(false)
, m_currentHoverTabItem(-1)
, m_bIsCloseHover(false)
, m_whichCloseClickDown(-1)
Expand Down Expand Up @@ -157,7 +156,6 @@ int CTabBar::InsertAtEnd(const wchar_t *subTabName)
// remove the selection so it can be selected properly later.
if (m_nItems == 1)
TabCtrl_SetCurSel(*this, -1);
SubclassSpinBox();
InvalidateRect(*this, nullptr, FALSE);
return index;
}
Expand Down Expand Up @@ -187,7 +185,6 @@ int CTabBar::InsertAfter(int index, const wchar_t *subTabName)
if (m_nItems == 0)
TabCtrl_SetCurSel(*this, -1);
++m_nItems;
SubclassSpinBox();
InvalidateRect(*this, nullptr, FALSE);
return ret;
}
Expand Down Expand Up @@ -405,6 +402,28 @@ LRESULT CTabBar::RunProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PARENTNOTIFY:
{
UINT childMessage = LOWORD(wParam);

switch (childMessage)
{
case WM_CREATE:
{
wchar_t className[100]{};
GetClassName((HWND)lParam, className, _countof(className));
if (wcscmp(UPDOWN_CLASS, className) == 0)
{
SetWindowLongPtr((HWND)lParam, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));

m_tabBarSpinDefaultProc = reinterpret_cast<WNDPROC>(::SetWindowLongPtr((HWND)lParam, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(TabBarSpin_Proc)));
m_spin = (HWND)lParam;
}
}
break;
}
}
break;
case WM_ERASEBKGND:
{
HDC hDC = reinterpret_cast<HDC>(wParam);
Expand Down Expand Up @@ -484,7 +503,7 @@ LRESULT CTabBar::RunProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

DrawMainBorder(&dis);

if (m_bIsSpinVisible)
if (IsSpinVisible())
{
RECT rcSpin{};
GetWindowRect(m_spin, &rcSpin);
Expand Down Expand Up @@ -517,7 +536,9 @@ LRESULT CTabBar::RunProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
dis.rcItem.right = min(dis.rcItem.right, rPage.right);
if (dis.rcItem.right != rPage.right || (dis.rcItem.right - dis.rcItem.left) > CDPIAware::Instance().Scale(*this, MIN_TAB_WIDTH))
{
DrawItem(&dis, static_cast<float>(Animator::GetValue(m_animVars[GetIDFromIndex(nTab).GetValue()])));
}
}
}
}
Expand All @@ -538,7 +559,9 @@ LRESULT CTabBar::RunProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
dis.rcItem.right = min(dis.rcItem.right, rPage.right);
if (dis.rcItem.right != rPage.right || (dis.rcItem.right - dis.rcItem.left) > CDPIAware::Instance().Scale(*this, MIN_TAB_WIDTH))
{
DrawItem(&dis, static_cast<float>(Animator::GetValue(m_animVars[GetIDFromIndex(nSel).GetValue()])));
}
}
}
}
Expand Down Expand Up @@ -678,7 +701,7 @@ LRESULT CTabBar::RunProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
auto index = GetTabIndexAt(xPos, yPos);
RECT rcItem{};
TabCtrl_GetItemRect(*this, index, &rcItem);
if (m_bIsSpinVisible)
if (IsSpinVisible())
{
RECT rcSpin{};
GetWindowRect(m_spin, &rcSpin);
Expand Down Expand Up @@ -755,7 +778,7 @@ LRESULT CTabBar::RunProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
RECT rPage{};
GetClientRect(*this, &rPage);
TabCtrl_AdjustRect(*this, FALSE, &rPage);
if (m_bIsSpinVisible)
if (IsSpinVisible())
{
RECT rcSpin{};
GetWindowRect(m_spin, &rcSpin);
Expand Down Expand Up @@ -1273,13 +1296,6 @@ LRESULT CTabBar::TabBarSpin_Proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM
{
case WM_PAINT:
{
// as WM_SHOWWINDOW is only ever sent with wParam == FALSE, use WM_PAINT instead
// of WM_SHOWWINDOW with wParam == TRUE
// alternatives might be WM_NCPAINT or 1125, which also both seem to be only
// sent when updown control is unhidden
if (!pTab->m_bIsSpinVisible)
pTab->m_bIsSpinVisible = true;

PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
HDC hdc = ps.hdc;
Expand Down Expand Up @@ -1479,24 +1495,31 @@ LRESULT CTabBar::TabBarSpin_Proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM
InvalidateRect(hwnd, nullptr, false);
}
break;
case WM_SHOWWINDOW:
{
if (wParam == FALSE) //< checked and is only ever sent with wParam == FALSE
pTab->m_bIsSpinVisible = false;
else
pTab->m_bIsSpinVisible = true;
break;
}
case WM_DESTROY:
{
pTab->m_bIsSpinVisible = false;
pTab->m_spin = nullptr;
break;
}
default:
break;
}
return CallWindowProc(pTab->m_tabBarSpinDefaultProc, hwnd, message, wParam, lParam);
}

bool CTabBar::IsSpinVisible() const
{
// Tried WM_SHOWWINDOW in TabBarSpin_Proc, but this was only ever sent with wParam == FALSE
// Then tried using WM_PAINT in TabBarSpin_Proc instead of WM_SHOWWINDOW with wParam == TRUE
// This was sent after WM_PAINT in RunProc, thus would create artifacts
// As I couldn't find any proof of guaranteed order, the below should always work

if (!m_spin)
{
return false;
}

LONG spinStyle = GetWindowLong(m_spin, GWL_STYLE);
return (spinStyle & WS_VISIBLE) != 0 ? true : false;
}

DocID CTabBar::GetIDFromIndex(int index) const
Expand Down Expand Up @@ -1534,30 +1557,6 @@ void CTabBar::NotifyTabDelete(int tab)
::SendMessage(m_hParent, WM_NOTIFY, 0, reinterpret_cast<LPARAM>(&nmHdr));
}

void CTabBar::SubclassSpinBox()
{
if (m_spin == nullptr)
{
EnumChildWindows(
*this, [](HWND hChild, LPARAM lParam) -> BOOL {
auto pThis = reinterpret_cast<CTabBar *>(lParam);
wchar_t className[100]{};
GetClassName(hChild, className, _countof(className));
if (wcscmp(UPDOWN_CLASS, className) == 0)
{
SetWindowLongPtr(hChild, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pThis));

pThis->m_tabBarSpinDefaultProc = reinterpret_cast<WNDPROC>(::SetWindowLongPtr(hChild, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(TabBarSpin_Proc)));
pThis->m_spin = hChild;
pThis->m_bIsSpinVisible = true;
return FALSE;
}
return TRUE;
},
reinterpret_cast<LPARAM>(this));
}
}

bool CloseButtonZone::IsHit(int x, int y, const RECT &testZone) const
{
if (((x + m_width + m_fromRight) < testZone.right) || (x > (testZone.right - m_fromRight)))
Expand Down
3 changes: 1 addition & 2 deletions src/TabBar.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ class CTabBar : public CWindow
int GetTabIndexAt(int x, int y) const;
bool IsPointInParentZone(POINT screenPoint) const;
void NotifyTabDelete(int tab);
void SubclassSpinBox();
bool IsSpinVisible() const;

private:
int m_nItems;
Expand All @@ -145,7 +145,6 @@ class CTabBar : public CWindow
WNDPROC m_tabBarDefaultProc;
WNDPROC m_tabBarSpinDefaultProc;
HWND m_spin;
bool m_bIsSpinVisible;

RECT m_currentHoverTabRect;
int m_currentHoverTabItem;
Expand Down

0 comments on commit 7d041c3

Please sign in to comment.