From 2fd0af4f8f2e320ef257b879cba8959e29dff39f Mon Sep 17 00:00:00 2001 From: Katayama Hirofumi MZ Date: Tue, 3 Jun 2025 06:59:30 +0900 Subject: [PATCH] [EXPLORER] AppBar Part 3 (#7966) Follow-up of #7946. JIRA issue: CORE-7237 - Implement ABM_GETSTATE, ABM_GETTASKBARPOS, ABM_ACTIVATE, ABM_WINDOWPOSCHANGED, ABM_GETAUTOHIDEBAR, ABM_SETAUTOHIDEBAR, and ABM_SETSTATE appbar messages. - Implement TWM_SETZORDER tray message. --- base/shell/explorer/appbar.cpp | 121 +++++++++++++++++++++++++++++++- base/shell/explorer/appbar.h | 17 ++++- base/shell/explorer/precomp.h | 1 + base/shell/explorer/traywnd.cpp | 106 +++++++++++++++++----------- 4 files changed, 199 insertions(+), 46 deletions(-) diff --git a/base/shell/explorer/appbar.cpp b/base/shell/explorer/appbar.cpp index 52e87208b56..fd254d7e3f9 100644 --- a/base/shell/explorer/appbar.cpp +++ b/base/shell/explorer/appbar.cpp @@ -11,6 +11,7 @@ CAppBarManager::CAppBarManager() : m_hAppBarDPA(NULL) + , m_ahwndAutoHideBars { 0 } { } @@ -450,13 +451,40 @@ void CAppBarManager::RecomputeAllWorkareas() ::EnumDisplayMonitors(NULL, NULL, CAppBarManager::MonitorEnumProc, (LPARAM)this); } +BOOL CAppBarManager::SetAutoHideBar(_In_ HWND hwndTarget, _In_ BOOL bSetOrReset, _In_ UINT uSide) +{ + ATLASSERT(uSide < _countof(m_ahwndAutoHideBars)); + HWND *phwndAutoHide = &m_ahwndAutoHideBars[uSide]; + if (!IsWindow(*phwndAutoHide)) + *phwndAutoHide = NULL; + + if (bSetOrReset) // Set? + { + if (!*phwndAutoHide) + *phwndAutoHide = hwndTarget; + return *phwndAutoHide == hwndTarget; + } + else // Reset + { + if (*phwndAutoHide == hwndTarget) + *phwndAutoHide = NULL; + return TRUE; + } +} + +void CAppBarManager::OnAppBarActivationChange2(_In_ HWND hwndNewAutoHide, _In_ UINT uSide) +{ + HWND hwndAutoHideBar = OnAppBarGetAutoHideBar(uSide); + if (hwndAutoHideBar && hwndAutoHideBar != hwndNewAutoHide) + ::PostMessageW(GetTrayWnd(), TWM_SETZORDER, (WPARAM)hwndAutoHideBar, uSide); +} + PAPPBAR_COMMAND CAppBarManager::GetAppBarMessage(_Inout_ PCOPYDATASTRUCT pCopyData) { PAPPBAR_COMMAND pData = (PAPPBAR_COMMAND)pCopyData->lpData; - if (pCopyData->cbData != sizeof(*pData) || - pData->abd.cbSize != sizeof(pData->abd)) + if (pCopyData->cbData != sizeof(*pData) || pData->abd.cbSize != sizeof(pData->abd)) { ERR("Invalid AppBar message\n"); return NULL; @@ -465,6 +493,80 @@ CAppBarManager::GetAppBarMessage(_Inout_ PCOPYDATASTRUCT pCopyData) return pData; } +// ABM_GETSTATE +UINT CAppBarManager::OnAppBarGetState() +{ + return (IsAutoHideState() ? ABS_AUTOHIDE : 0) | (IsAlwaysOnTop() ? ABS_ALWAYSONTOP : 0); +} + +// ABM_GETTASKBARPOS +BOOL CAppBarManager::OnAppBarGetTaskbarPos(_Inout_ PAPPBAR_COMMAND pData) +{ + PAPPBARDATAINTEROP pOutput = AppBar_LockOutput(pData); + if (!pOutput) + { + ERR("!pOutput: %d\n", pData->dwProcessId); + return FALSE; + } + + pOutput->rc = *GetTrayRect(); + pOutput->uEdge = GetPosition(); + + AppBar_UnLockOutput(pOutput); + return TRUE; +} + +// ABM_ACTIVATE, ABM_WINDOWPOSCHANGED +void CAppBarManager::OnAppBarActivationChange(_In_ const APPBAR_COMMAND *pData) +{ + HWND hWnd = (HWND)UlongToHandle(pData->abd.hWnd32); + PAPPBAR pAppBar = FindAppBar(hWnd); + if (!pAppBar) + { + ERR("Not found: %p\n", hWnd); + return; + } + + HWND hwndAppBar = pAppBar->hWnd; + for (UINT uSide = ABE_LEFT; uSide <= ABE_BOTTOM; ++uSide) + { + if (m_ahwndAutoHideBars[uSide] == hwndAppBar && uSide != pAppBar->uEdge) + return; + } + + OnAppBarActivationChange2(hwndAppBar, pAppBar->uEdge); +} + +// ABM_GETAUTOHIDEBAR +HWND CAppBarManager::OnAppBarGetAutoHideBar(_In_ UINT uSide) +{ + if (uSide >= _countof(m_ahwndAutoHideBars)) + return NULL; + + if (!::IsWindow(m_ahwndAutoHideBars[uSide])) + m_ahwndAutoHideBars[uSide] = NULL; + return m_ahwndAutoHideBars[uSide]; +} + +// ABM_SETAUTOHIDEBAR +BOOL CAppBarManager::OnAppBarSetAutoHideBar(_In_ const APPBAR_COMMAND *pData) +{ + if (pData->abd.uEdge >= _countof(m_ahwndAutoHideBars)) + return FALSE; + HWND hwndTarget = (HWND)UlongToHandle(pData->abd.hWnd32); + return SetAutoHideBar(hwndTarget, (BOOL)pData->abd.lParam64, pData->abd.uEdge); +} + +// ABM_SETSTATE +void CAppBarManager::OnAppBarSetState(_In_ UINT uState) +{ + if ((uState & ~(ABS_AUTOHIDE | ABS_ALWAYSONTOP))) + return; + + SetAutoHideState(!!(uState & ABS_AUTOHIDE)); + UpdateAlwaysOnTop(!!(uState & ABS_ALWAYSONTOP)); +} + // WM_COPYDATA TABDMC_APPBAR LRESULT CAppBarManager::OnAppBarMessage(_Inout_ PCOPYDATASTRUCT pCopyData) { @@ -485,6 +587,21 @@ LRESULT CAppBarManager::OnAppBarMessage(_Inout_ PCOPYDATASTRUCT pCopyData) case ABM_SETPOS: OnAppBarSetPos(pData); break; + case ABM_GETSTATE: + return OnAppBarGetState(); + case ABM_GETTASKBARPOS: + return OnAppBarGetTaskbarPos(pData); + case ABM_ACTIVATE: + case ABM_WINDOWPOSCHANGED: + OnAppBarActivationChange(pData); + break; + case ABM_GETAUTOHIDEBAR: + return (LRESULT)OnAppBarGetAutoHideBar(pData->abd.uEdge); + case ABM_SETAUTOHIDEBAR: + return OnAppBarSetAutoHideBar(pData); + case ABM_SETSTATE: + OnAppBarSetState((UINT)pData->abd.lParam64); + break; default: { FIXME("0x%X\n", pData->dwMessage); diff --git a/base/shell/explorer/appbar.h b/base/shell/explorer/appbar.h index e0894b18dbb..e36b558d4dd 100644 --- a/base/shell/explorer/appbar.h +++ b/base/shell/explorer/appbar.h @@ -51,6 +51,7 @@ public: protected: HDPA m_hAppBarDPA; // DPA (Dynamic Pointer Array) + HWND m_ahwndAutoHideBars[4]; // The side --> auto-hide window PAPPBAR FindAppBar(_In_ HWND hwndAppBar) const; void EliminateAppBar(_In_ INT iItem); @@ -60,11 +61,19 @@ protected: void ComputeHiddenRect(_Inout_ PRECT prc, _In_ UINT uSide); PAPPBAR_COMMAND GetAppBarMessage(_Inout_ PCOPYDATASTRUCT pCopyData); void GetDockedRect(_Out_ PRECT prcDocked); + BOOL SetAutoHideBar(_In_ HWND hwndTarget, _In_ BOOL bSetOrReset, _In_ UINT uSide); + void OnAppBarActivationChange2(_In_ HWND hwndNewAutoHide, _In_ UINT uSide); BOOL OnAppBarNew(_In_ const APPBAR_COMMAND *pData); void OnAppBarRemove(_In_ const APPBAR_COMMAND *pData); void OnAppBarQueryPos(_Inout_ PAPPBAR_COMMAND pData); void OnAppBarSetPos(_Inout_ PAPPBAR_COMMAND pData); + UINT OnAppBarGetState(); + BOOL OnAppBarGetTaskbarPos(_Inout_ PAPPBAR_COMMAND pData); + void OnAppBarActivationChange(_In_ const APPBAR_COMMAND *pData); + HWND OnAppBarGetAutoHideBar(_In_ UINT uSide); + BOOL OnAppBarSetAutoHideBar(_In_ const APPBAR_COMMAND *pData); + void OnAppBarSetState(_In_ UINT uState); void OnAppBarNotifyAll( _In_opt_ HMONITOR hMon, @@ -89,11 +98,15 @@ protected: virtual BOOL IsAutoHideState() const = 0; virtual BOOL IsHidingState() const = 0; - virtual HMONITOR GetMonitor() const = 0; - virtual HMONITOR GetPreviousMonitor() const = 0; + virtual BOOL IsAlwaysOnTop() const = 0; + virtual HMONITOR& GetMonitor() = 0; + virtual HMONITOR& GetPreviousMonitor() = 0; virtual INT GetPosition() const = 0; virtual const RECT* GetTrayRect() = 0; + virtual HWND GetTrayWnd() const = 0; virtual HWND GetDesktopWnd() const = 0; + virtual void SetAutoHideState(_In_ BOOL bAutoHide) = 0; + virtual void UpdateAlwaysOnTop(_In_ BOOL bAlwaysOnTop) = 0; static BOOL CALLBACK MonitorEnumProc( diff --git a/base/shell/explorer/precomp.h b/base/shell/explorer/precomp.h index 8ebe8d41cd6..924adbfee71 100644 --- a/base/shell/explorer/precomp.h +++ b/base/shell/explorer/precomp.h @@ -132,6 +132,7 @@ HRESULT WINAPI _CBandSite_CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void #define TWM_GETTASKSWITCH (WM_USER + 236) #define TWM_OPENSTARTMENU (WM_USER + 260) #define TWM_SETTINGSCHANGED (WM_USER + 300) +#define TWM_SETZORDER (WM_USER + 338) #define TWM_PULSE (WM_USER + 400) extern const GUID IID_IShellDesktopTray; diff --git a/base/shell/explorer/traywnd.cpp b/base/shell/explorer/traywnd.cpp index 5976227501f..2fb4c68e76c 100644 --- a/base/shell/explorer/traywnd.cpp +++ b/base/shell/explorer/traywnd.cpp @@ -1462,14 +1462,13 @@ GetPrimaryScreenRect: without user interaction. */ rcTray = m_TrayRects[m_Position]; - if (g_TaskbarSettings.sr.AutoHide) + if (IsAutoHideState()) { rcTray.left += m_AutoHideOffset.cx; rcTray.right += m_AutoHideOffset.cx; rcTray.top += m_AutoHideOffset.cy; rcTray.bottom += m_AutoHideOffset.cy; } - } ChangePos: @@ -1543,7 +1542,7 @@ ChangePos: /* If AutoHide is false then change the workarea to exclude the area that the taskbar covers. */ - if (!g_TaskbarSettings.sr.AutoHide) + if (!IsAutoHideState()) { switch (m_Position) { @@ -1902,20 +1901,17 @@ ChangePos: void ProcessMouseTracking() { - RECT rcCurrent; POINT pt; - BOOL over; - UINT state = m_AutoHideState; - GetCursorPos(&pt); + + RECT rcCurrent; GetWindowRect(&rcCurrent); - over = PtInRect(&rcCurrent, pt); - if (m_StartButton.SendMessage( BM_GETSTATE, 0, 0) != BST_UNCHECKED) - { + BOOL over = PtInRect(&rcCurrent, pt); + if (m_StartButton.SendMessage(BM_GETSTATE, 0, 0) != BST_UNCHECKED) over = TRUE; - } + UINT state = m_AutoHideState; if (over) { if (state == AUTOHIDE_HIDING) @@ -1994,7 +1990,6 @@ ChangePos: /* fallthrough */ case AUTOHIDE_HIDDEN: - switch (m_Position) { case ABE_LEFT: @@ -2054,7 +2049,6 @@ ChangePos: /* fallthrough */ case AUTOHIDE_SHOWN: - KillTimer(TIMER_ID_AUTOHIDE); m_AutoHideState = AUTOHIDE_SHOWN; break; @@ -2063,10 +2057,6 @@ ChangePos: SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER); } - - - - /********************************************************** * ##### taskbar drawing ##### */ @@ -2128,10 +2118,6 @@ ChangePos: return 0; } - - - - /* * ITrayWindow */ @@ -2370,7 +2356,7 @@ ChangePos: InitShellServices(&m_ShellServices); - if (g_TaskbarSettings.sr.AutoHide) + if (IsAutoHideState()) { m_AutoHideState = AUTOHIDE_HIDING; SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_HIDE, NULL); @@ -2689,6 +2675,7 @@ ChangePos: /* Remove the clipping on multi monitor systems while dragging around */ ApplyClipping(FALSE); } + m_PreviousMonitor = m_Monitor; return TRUE; } @@ -3081,6 +3068,13 @@ HandleTrayContextMenu: return 0; } + // TWM_SETZORDER + LRESULT OnSetZOrder(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + return ::SetWindowPos(m_hWnd, (HWND)wParam, 0, 0, 0, 0, + SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); + } + LRESULT OnHotkey(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { return HandleHotKey(wParam); @@ -3189,7 +3183,7 @@ HandleTrayContextMenu: { SendMessage(m_TrayNotify, uMsg, wParam, lParam); - if (g_TaskbarSettings.sr.AutoHide) + if (IsAutoHideState()) { SetTimer(TIMER_ID_MOUSETRACK, MOUSETRACK_INTERVAL, NULL); } @@ -3288,6 +3282,25 @@ HandleTrayContextMenu: return 0; } + // WM_ACTIVATE + LRESULT OnActivate(INT code, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + OnAppBarActivationChange2(m_hWnd, m_Position); + if (!wParam) // !(Activate || Minimized) + { + SendMessage(WM_CHANGEUISTATE, MAKELONG(UIS_SET, UISF_HIDEACCEL | UISF_HIDEFOCUS), 0); + IUnknown_UIActivateIO(m_TrayBandSite, FALSE, NULL); + } + return 0; + } + + // WM_SETFOCUS + LRESULT OnSetFocus(INT code, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + IUnknown_UIActivateIO(m_TrayBandSite, TRUE, NULL); + return 0; + } + LRESULT OnRebarAutoSize(INT code, LPNMHDR nmhdr, BOOL& bHandled) { #if 0 @@ -3348,27 +3361,13 @@ HandleTrayContextMenu: ::SendMessageW(m_TrayNotify, uMsg, wParam, lParam); /* Toggle autohide */ - if (newSettings->sr.AutoHide != g_TaskbarSettings.sr.AutoHide) - { - g_TaskbarSettings.sr.AutoHide = newSettings->sr.AutoHide; - memset(&m_AutoHideOffset, 0, sizeof(m_AutoHideOffset)); - m_AutoHideState = AUTOHIDE_SHOWN; - if (!newSettings->sr.AutoHide) - SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER); - else - SetTimer(TIMER_ID_MOUSETRACK, MOUSETRACK_INTERVAL, NULL); - } + SetAutoHideState(newSettings->sr.AutoHide); /* Toggle lock state */ Lock(newSettings->bLock); /* Toggle OnTop state */ - if (newSettings->sr.AlwaysOnTop != g_TaskbarSettings.sr.AlwaysOnTop) - { - g_TaskbarSettings.sr.AlwaysOnTop = newSettings->sr.AlwaysOnTop; - HWND hWndInsertAfter = newSettings->sr.AlwaysOnTop ? HWND_TOPMOST : HWND_BOTTOM; - SetWindowPos(hWndInsertAfter, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); - } + UpdateAlwaysOnTop(newSettings->sr.AlwaysOnTop); /* Adjust taskbar size */ CheckTrayWndPosition(); @@ -3436,10 +3435,13 @@ HandleTrayContextMenu: MESSAGE_HANDLER(WM_HOTKEY, OnHotkey) MESSAGE_HANDLER(WM_NCCALCSIZE, OnNcCalcSize) MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup) + MESSAGE_HANDLER(WM_ACTIVATE, OnActivate) + MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) MESSAGE_HANDLER(TWM_SETTINGSCHANGED, OnTaskbarSettingsChanged) MESSAGE_HANDLER(TWM_OPENSTARTMENU, OnOpenStartMenu) MESSAGE_HANDLER(TWM_DOEXITWINDOWS, OnDoExitWindows) MESSAGE_HANDLER(TWM_GETTASKSWITCH, OnGetTaskSwitch) + MESSAGE_HANDLER(TWM_SETZORDER, OnSetZOrder) MESSAGE_HANDLER(TWM_PULSE, OnPulse) ALT_MSG_MAP(1) END_MSG_MAP() @@ -3576,16 +3578,36 @@ protected: // See also: appbar.cpp // TODO: freedesktop _NET_WM_STRUT integration // TODO: find when a fullscreen app is in the foreground and send FULLSCREENAPP notifications - // TODO: detect changes in the screen size and send ABN_POSCHANGED ? // TODO: multiple monitor support BOOL IsAutoHideState() const override { return g_TaskbarSettings.sr.AutoHide; } BOOL IsHidingState() const override { return m_AutoHideState == AUTOHIDE_HIDING; } - HMONITOR GetMonitor() const override { return m_Monitor; } - HMONITOR GetPreviousMonitor() const override { return m_PreviousMonitor; } + BOOL IsAlwaysOnTop() const override { return g_TaskbarSettings.sr.AlwaysOnTop; } + HMONITOR& GetMonitor() override { return m_Monitor; } + HMONITOR& GetPreviousMonitor() override { return m_PreviousMonitor; } INT GetPosition() const override { return m_Position; } const RECT* GetTrayRect() override { return &m_TrayRects[m_Position]; } + HWND GetTrayWnd() const override { return m_hWnd; } HWND GetDesktopWnd() const override { return m_DesktopWnd; } + + void SetAutoHideState(_In_ BOOL bAutoHide) override + { + g_TaskbarSettings.sr.AutoHide = bAutoHide; + ZeroMemory(&m_AutoHideOffset, sizeof(m_AutoHideOffset)); + + m_AutoHideState = AUTOHIDE_SHOWN; + if (bAutoHide) + SetTimer(TIMER_ID_MOUSETRACK, MOUSETRACK_INTERVAL, NULL); + else + SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER); + } + + void UpdateAlwaysOnTop(_In_ BOOL bAlwaysOnTop) override + { + g_TaskbarSettings.sr.AlwaysOnTop = bAlwaysOnTop; + HWND hwndInsertAfter = (bAlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST); + SetWindowPos(hwndInsertAfter, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); + } }; class CTrayWindowCtxMenu :