[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.
This commit is contained in:
Katayama Hirofumi MZ 2025-06-03 06:59:30 +09:00 committed by GitHub
parent 2543e2179c
commit 2fd0af4f8f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 199 additions and 46 deletions

View file

@ -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);

View file

@ -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(

View file

@ -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;

View file

@ -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 :