diff --git a/src/TabBar.cpp b/src/TabBar.cpp index d5e4d0b1..502241d1 100644 --- a/src/TabBar.cpp +++ b/src/TabBar.cpp @@ -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) @@ -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; } @@ -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; } @@ -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(this)); + + m_tabBarSpinDefaultProc = reinterpret_cast(::SetWindowLongPtr((HWND)lParam, GWLP_WNDPROC, reinterpret_cast(TabBarSpin_Proc))); + m_spin = (HWND)lParam; + } + } + break; + } + } + break; case WM_ERASEBKGND: { HDC hDC = reinterpret_cast(wParam); @@ -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); @@ -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(Animator::GetValue(m_animVars[GetIDFromIndex(nTab).GetValue()]))); + } } } } @@ -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(Animator::GetValue(m_animVars[GetIDFromIndex(nSel).GetValue()]))); + } } } } @@ -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); @@ -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); @@ -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; @@ -1479,17 +1495,8 @@ 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; } @@ -1497,6 +1504,22 @@ LRESULT CTabBar::TabBarSpin_Proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM 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 @@ -1534,30 +1557,6 @@ void CTabBar::NotifyTabDelete(int tab) ::SendMessage(m_hParent, WM_NOTIFY, 0, reinterpret_cast(&nmHdr)); } -void CTabBar::SubclassSpinBox() -{ - if (m_spin == nullptr) - { - EnumChildWindows( - *this, [](HWND hChild, LPARAM lParam) -> BOOL { - auto pThis = reinterpret_cast(lParam); - wchar_t className[100]{}; - GetClassName(hChild, className, _countof(className)); - if (wcscmp(UPDOWN_CLASS, className) == 0) - { - SetWindowLongPtr(hChild, GWLP_USERDATA, reinterpret_cast(pThis)); - - pThis->m_tabBarSpinDefaultProc = reinterpret_cast(::SetWindowLongPtr(hChild, GWLP_WNDPROC, reinterpret_cast(TabBarSpin_Proc))); - pThis->m_spin = hChild; - pThis->m_bIsSpinVisible = true; - return FALSE; - } - return TRUE; - }, - reinterpret_cast(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))) diff --git a/src/TabBar.h b/src/TabBar.h index 3fc9683a..5fba3d8b 100644 --- a/src/TabBar.h +++ b/src/TabBar.h @@ -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; @@ -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;