ReactOS 0.4.16-dev-1142-g8029339
appbar.cpp
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Explorer
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4 * PURPOSE: AppBar implementation
5 * COPYRIGHT: Copyright 2008 Vincent Povirk for CodeWeavers
6 * Copyright 2025 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
7 */
8
9#include "precomp.h"
10#include "appbar.h"
11
13 : m_hAppBarDPA(NULL)
14{
15}
16
18{
20}
21
23{
24 if (!m_hAppBarDPA)
25 return NULL;
26
28 while (--nItems >= 0)
29 {
31 if (pAppBar && hwndAppBar == pAppBar->hWnd)
32 return pAppBar;
33 }
34
35 return NULL;
36}
37
39{
42}
43
45{
46 if (!m_hAppBarDPA)
47 return;
48
50 while (--nItems >= 0)
51 {
53 }
54
57}
58
59// ABM_NEW
61{
62 HWND hWnd = (HWND)UlongToHandle(pData->abd.hWnd32);
63
64 if (m_hAppBarDPA)
65 {
66 if (FindAppBar(hWnd))
67 {
68 ERR("Already exists: %p\n", hWnd);
69 return FALSE;
70 }
71 }
72 else
73 {
74 const UINT c_nGrow = 4;
75 m_hAppBarDPA = DPA_Create(c_nGrow);
76 if (!m_hAppBarDPA)
77 {
78 ERR("Out of memory\n");
79 return FALSE;
80 }
81 }
82
83 PAPPBAR pAppBar = (PAPPBAR)::LocalAlloc(LPTR, sizeof(*pAppBar));
84 if (pAppBar)
85 {
86 pAppBar->hWnd = hWnd;
87 pAppBar->uEdge = UINT_MAX;
88 pAppBar->uCallbackMessage = pData->abd.uCallbackMessage;
89 if (DPA_InsertPtr(m_hAppBarDPA, INT_MAX, pAppBar) >= 0)
90 return TRUE; // Success!
91
92 ::LocalFree(pAppBar);
93 }
94
95 ERR("Out of memory\n");
96 return FALSE;
97}
98
99// ABM_REMOVE
101{
102 if (!m_hAppBarDPA)
103 return;
104
105 HWND hWnd = (HWND)UlongToHandle(pData->abd.hWnd32);
107 while (--nItems >= 0)
108 {
110 if (!pAppBar)
111 continue;
112
113 if (pAppBar->hWnd == hWnd)
114 {
115 RECT rcOld = pAppBar->rc;
117 StuckAppChange(hWnd, &rcOld, NULL, FALSE);
118 }
119 }
120}
121
122// ABM_QUERYPOS
124{
125 HWND hWnd = (HWND)UlongToHandle(pData->abd.hWnd32);
126 PAPPBAR pAppBar1 = FindAppBar(hWnd);
127 if (!pAppBar1)
128 {
129 ERR("Not found: %p\n", hWnd);
130 return;
131 }
132
134 if (!pOutput)
135 {
136 ERR("!pOutput: %d\n", pData->dwProcessId);
137 return;
138 }
139 pOutput->rc = pData->abd.rc;
140
141 if (::IsRectEmpty(&pOutput->rc))
142 ERR("IsRectEmpty\n");
143
144 HMONITOR hMon1 = ::MonitorFromRect(&pOutput->rc, MONITOR_DEFAULTTOPRIMARY);
145 ASSERT(hMon1 != NULL);
146
147 // Subtract tray rectangle from pOutput->rc if necessary
148 if (hMon1 == GetMonitor() && !IsAutoHideState())
149 {
150 APPBAR dummyAppBar;
151 dummyAppBar.uEdge = GetPosition();
152 GetDockedRect(&dummyAppBar.rc);
153 AppBarSubtractRect(&dummyAppBar, &pOutput->rc);
154 }
155
156 // Subtract area from pOutput->rc
157 UINT uEdge = pData->abd.uEdge;
159 while (--nItems >= 0)
160 {
162 if (!pAppBar2 || pAppBar1->hWnd == pAppBar2->hWnd)
163 continue;
164
165 if ((Edge_IsVertical(uEdge) || !Edge_IsVertical(pAppBar2->uEdge)) &&
166 (pAppBar1->uEdge != uEdge || !AppBarOutsideOf(pAppBar1, pAppBar2)))
167 {
168 if (pAppBar1->uEdge == uEdge || pAppBar2->uEdge != uEdge)
169 continue;
170 }
171
172 HMONITOR hMon2 = ::MonitorFromRect(&pAppBar2->rc, MONITOR_DEFAULTTONULL);
173 if (hMon1 == hMon2)
174 AppBarSubtractRect(pAppBar2, &pOutput->rc);
175 }
176
177 AppBar_UnLockOutput(pOutput);
178}
179
180// ABM_SETPOS
182{
183 HWND hWnd = (HWND)UlongToHandle(pData->abd.hWnd32);
184 PAPPBAR pAppBar = FindAppBar(hWnd);
185 if (!pAppBar)
186 return;
187
189
191 if (!pOutput)
192 return;
193
194 RECT rcOld = pAppBar->rc, rcNew = pData->abd.rc;
195 BOOL bChanged = !::EqualRect(&rcOld, &rcNew);
196
197 pAppBar->rc = rcNew;
198 pAppBar->uEdge = pData->abd.uEdge;
199
200 AppBar_UnLockOutput(pOutput);
201
202 if (bChanged)
203 StuckAppChange(hWnd, &rcOld, &rcNew, FALSE);
204}
205
207 _In_opt_ HMONITOR hMon,
208 _In_opt_ HWND hwndIgnore,
209 _In_ DWORD dwNotify,
211{
212 TRACE("%p, %p, 0x%X, %p\n", hMon, hwndIgnore, dwNotify, lParam);
213
214 if (!m_hAppBarDPA)
215 return;
216
218 while (--nItems >= 0)
219 {
221 if (!pAppBar || pAppBar->hWnd == hwndIgnore)
222 continue;
223
224 HWND hwndAppBar = pAppBar->hWnd;
225 if (!::IsWindow(hwndAppBar))
226 {
228 continue;
229 }
230
231 if (!hMon || hMon == ::MonitorFromWindow(hwndAppBar, MONITOR_DEFAULTTONULL))
232 ::PostMessageW(hwndAppBar, pAppBar->uCallbackMessage, dwNotify, lParam);
233 }
234}
235
239{
240 switch (pAppBar->uEdge)
241 {
242 case ABE_LEFT: prc->left = max(prc->left, pAppBar->rc.right); break;
243 case ABE_TOP: prc->top = max(prc->top, pAppBar->rc.bottom); break;
244 case ABE_RIGHT: prc->right = min(prc->right, pAppBar->rc.left); break;
245 case ABE_BOTTOM: prc->bottom = min(prc->bottom, pAppBar->rc.top); break;
246 default:
247 ASSERT(FALSE);
248 break;
249 }
250}
251
252// Is pAppBar1 outside of pAppBar2?
254 _In_ const APPBAR *pAppBar1,
255 _In_ const APPBAR *pAppBar2)
256{
257 if (pAppBar1->uEdge != pAppBar2->uEdge)
258 return FALSE;
259
260 switch (pAppBar2->uEdge)
261 {
262 case ABE_LEFT: return pAppBar1->rc.left >= pAppBar2->rc.left;
263 case ABE_TOP: return pAppBar1->rc.top >= pAppBar2->rc.top;
264 case ABE_RIGHT: return pAppBar1->rc.right <= pAppBar2->rc.right;
265 case ABE_BOTTOM: return pAppBar1->rc.bottom <= pAppBar2->rc.bottom;
266 default:
267 ASSERT(FALSE);
268 return FALSE;
269 }
270}
271
275{
276 *prcDocked = *GetTrayRect();
278 ComputeHiddenRect(prcDocked, GetPosition());
279}
280
285{
286 MONITORINFO mi = { sizeof(mi) };
287 HMONITOR hMonitor = ::MonitorFromRect(prc, MONITOR_DEFAULTTONULL);
288 if (!::GetMonitorInfoW(hMonitor, &mi))
289 return;
290 RECT rcMon = mi.rcMonitor;
291
292 INT cxy = Edge_IsVertical(uSide) ? (prc->bottom - prc->top) : (prc->right - prc->left);
293 switch (uSide)
294 {
295 case ABE_LEFT:
296 prc->right = rcMon.left + GetSystemMetrics(SM_CXFRAME) / 2;
297 prc->left = prc->right - cxy;
298 break;
299 case ABE_TOP:
300 prc->bottom = rcMon.top + GetSystemMetrics(SM_CYFRAME) / 2;
301 prc->top = prc->bottom - cxy;
302 break;
303 case ABE_RIGHT:
304 prc->left = rcMon.right - GetSystemMetrics(SM_CXFRAME) / 2;
305 prc->right = prc->left + cxy;
306 break;
307 case ABE_BOTTOM:
308 prc->top = rcMon.bottom - GetSystemMetrics(SM_CYFRAME) / 2;
309 prc->bottom = prc->top + cxy;
310 break;
311 default:
312 ASSERT(FALSE);
313 break;
314 }
315}
316
322void
324 _In_opt_ HWND hwndTarget,
325 _In_opt_ const RECT *prcOld,
326 _In_opt_ const RECT *prcNew,
327 _In_ BOOL bTray)
328{
329 RECT rcWorkArea1, rcWorkArea2;
330 HMONITOR hMon1 = NULL;
331 UINT flags = 0;
332 enum { SET_WORKAREA_1 = 1, SET_WORKAREA_2 = 2, NEED_SIZING = 4 }; // for flags
333
334 if (prcOld)
335 {
336 hMon1 = (bTray ? GetPreviousMonitor() : ::MonitorFromRect(prcOld, MONITOR_DEFAULTTONEAREST));
337 if (hMon1)
338 {
339 WORKAREA_TYPE type1 = RecomputeWorkArea(GetTrayRect(), hMon1, &rcWorkArea1);
340 if (type1 == WORKAREA_IS_NOT_MONITOR)
341 flags = SET_WORKAREA_1;
342 if (type1 == WORKAREA_SAME_AS_MONITOR)
343 flags = NEED_SIZING;
344 }
345 }
346
347 if (prcNew)
348 {
349 HMONITOR hMon2 = ::MonitorFromRect(prcNew, MONITOR_DEFAULTTONULL);
350 if (hMon2 && hMon2 != hMon1)
351 {
352 WORKAREA_TYPE type2 = RecomputeWorkArea(GetTrayRect(), hMon2, &rcWorkArea2);
353 if (type2 == WORKAREA_IS_NOT_MONITOR)
354 flags |= SET_WORKAREA_2;
355 else if (type2 == WORKAREA_SAME_AS_MONITOR && !flags)
356 flags = NEED_SIZING;
357 }
358 }
359
360 if (flags & SET_WORKAREA_1)
361 {
362 UINT fWinIni = ((flags == SET_WORKAREA_1 && GetDesktopWnd()) ? SPIF_SENDCHANGE : 0);
363 ::SystemParametersInfoW(SPI_SETWORKAREA, TRUE, &rcWorkArea1, fWinIni);
364 RedrawDesktop(GetDesktopWnd(), &rcWorkArea1);
365 }
366
367 if (flags & SET_WORKAREA_2)
368 {
369 UINT fWinIni = (GetDesktopWnd() ? SPIF_SENDCHANGE : 0);
370 ::SystemParametersInfoW(SPI_SETWORKAREA, TRUE, &rcWorkArea2, fWinIni);
371 RedrawDesktop(GetDesktopWnd(), &rcWorkArea2);
372 }
373
374 if (bTray || flags == NEED_SIZING)
376
377 // Post ABN_POSCHANGED messages to AppBar windows
379}
380
382{
383 if (!hwndDesktop)
384 return;
385 ::MapWindowPoints(NULL, hwndDesktop, (POINT*)prc, sizeof(*prc) / sizeof(POINT));
387}
388
395 _In_ const RECT *prcTray,
396 _In_ HMONITOR hMonitor,
397 _Out_ PRECT prcWorkArea)
398{
399 MONITORINFO mi = { sizeof(mi) };
400 if (!::GetMonitorInfoW(hMonitor, &mi))
402
403 if (IsAutoHideState())
404 *prcWorkArea = mi.rcMonitor;
405 else
406 ::SubtractRect(prcWorkArea, &mi.rcMonitor, prcTray);
407
408 if (m_hAppBarDPA)
409 {
411 while (--nItems >= 0)
412 {
414 if (pAppBar && hMonitor == ::MonitorFromRect(&pAppBar->rc, MONITOR_DEFAULTTONULL))
415 AppBarSubtractRect(pAppBar, prcWorkArea);
416 }
417 }
418
419 if (!::EqualRect(prcWorkArea, &mi.rcWork))
421
422 if (IsAutoHideState() || ::IsRectEmpty(prcTray))
424
426}
427
430 _In_ HMONITOR hMonitor,
431 _In_ HDC hDC,
434{
437
438 RECT rcWorkArea;
439 if (pThis->RecomputeWorkArea(prc, hMonitor, &rcWorkArea) != WORKAREA_IS_NOT_MONITOR)
440 return TRUE;
441
442 HWND hwndDesktop = pThis->GetDesktopWnd();
443 ::SystemParametersInfoW(SPI_SETWORKAREA, 0, &rcWorkArea, hwndDesktop ? SPIF_SENDCHANGE : 0);
444 pThis->RedrawDesktop(hwndDesktop, &rcWorkArea);
445 return TRUE;
446}
447
449{
451}
452
455{
456 PAPPBAR_COMMAND pData = (PAPPBAR_COMMAND)pCopyData->lpData;
457
458 if (pCopyData->cbData != sizeof(*pData) ||
459 pData->abd.cbSize != sizeof(pData->abd))
460 {
461 ERR("Invalid AppBar message\n");
462 return NULL;
463 }
464
465 return pData;
466}
467
468// WM_COPYDATA TABDMC_APPBAR
470{
472 if (!pData)
473 return 0;
474
475 switch (pData->dwMessage)
476 {
477 case ABM_NEW:
478 return OnAppBarNew(pData);
479 case ABM_REMOVE:
481 break;
482 case ABM_QUERYPOS:
484 break;
485 case ABM_SETPOS:
487 break;
488 default:
489 {
490 FIXME("0x%X\n", pData->dwMessage);
491 return FALSE;
492 }
493 }
494 return TRUE;
495}
static HDC hDC
Definition: 3dtext.c:33
static BOOL Edge_IsVertical(_In_ UINT uEdge)
Definition: appbar.h:31
static PAPPBARDATAINTEROP AppBar_LockOutput(_In_ PAPPBAR_COMMAND pData)
Definition: appbar.h:19
WORKAREA_TYPE
Definition: appbar.h:38
@ WORKAREA_IS_NOT_MONITOR
Definition: appbar.h:40
@ WORKAREA_SAME_AS_MONITOR
Definition: appbar.h:41
@ WORKAREA_NO_TRAY_AREA
Definition: appbar.h:39
static VOID AppBar_UnLockOutput(_Out_ PAPPBARDATAINTEROP pOutput)
Definition: appbar.h:25
struct tagAPPBAR * PAPPBAR
int nItems
Definition: appswitch.c:56
HWND hWnd
Definition: settings.c:17
#define FIXME(fmt,...)
Definition: precomp.h:53
#define ERR(fmt,...)
Definition: precomp.h:57
#define UlongToHandle(ul)
Definition: basetsd.h:97
void AppBarSubtractRect(_In_ PAPPBAR pAppBar, _Inout_ PRECT prc)
Definition: appbar.cpp:238
void EliminateAppBar(_In_ INT iItem)
Definition: appbar.cpp:38
HDPA m_hAppBarDPA
Definition: appbar.h:53
void ComputeHiddenRect(_Inout_ PRECT prc, _In_ UINT uSide)
Definition: appbar.cpp:284
void OnAppBarRemove(_In_ const APPBAR_COMMAND *pData)
Definition: appbar.cpp:100
static BOOL CALLBACK MonitorEnumProc(_In_ HMONITOR hMonitor, _In_ HDC hDC, _In_ LPRECT prc, _Inout_ LPARAM lParam)
Definition: appbar.cpp:429
virtual BOOL IsAutoHideState() const =0
void DestroyAppBarDPA()
Definition: appbar.cpp:44
void StuckAppChange(_In_opt_ HWND hwndTarget, _In_opt_ const RECT *prcOld, _In_opt_ const RECT *prcNew, _In_ BOOL bTray)
Definition: appbar.cpp:323
void OnAppBarSetPos(_Inout_ PAPPBAR_COMMAND pData)
Definition: appbar.cpp:181
PAPPBAR FindAppBar(_In_ HWND hwndAppBar) const
Definition: appbar.cpp:22
BOOL AppBarOutsideOf(_In_ const APPBAR *pAppBar1, _In_ const APPBAR *pAppBar2)
Definition: appbar.cpp:253
void GetDockedRect(_Out_ PRECT prcDocked)
Definition: appbar.cpp:274
virtual const RECT * GetTrayRect()=0
void OnAppBarNotifyAll(_In_opt_ HMONITOR hMon, _In_opt_ HWND hwndIgnore, _In_ DWORD dwNotify, _In_opt_ LPARAM lParam)
Definition: appbar.cpp:206
void RecomputeAllWorkareas()
Definition: appbar.cpp:448
virtual INT GetPosition() const =0
virtual BOOL IsHidingState() const =0
virtual HMONITOR GetMonitor() const =0
virtual ~CAppBarManager()
Definition: appbar.cpp:17
PAPPBAR_COMMAND GetAppBarMessage(_Inout_ PCOPYDATASTRUCT pCopyData)
Definition: appbar.cpp:454
virtual HWND GetDesktopWnd() const =0
void OnAppBarQueryPos(_Inout_ PAPPBAR_COMMAND pData)
Definition: appbar.cpp:123
WORKAREA_TYPE RecomputeWorkArea(_In_ const RECT *prcTray, _In_ HMONITOR hMonitor, _Out_ PRECT prcWorkArea)
Definition: appbar.cpp:394
void RedrawDesktop(_In_ HWND hwndDesktop, _Inout_ PRECT prc)
Definition: appbar.cpp:381
virtual HMONITOR GetPreviousMonitor() const =0
LRESULT OnAppBarMessage(_Inout_ PCOPYDATASTRUCT pCopyData)
Definition: appbar.cpp:469
BOOL OnAppBarNew(_In_ const APPBAR_COMMAND *pData)
Definition: appbar.cpp:60
LPARAM lParam
Definition: combotst.c:139
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
LPVOID WINAPI DPA_DeletePtr(HDPA hdpa, INT i)
Definition: dpa.c:677
BOOL WINAPI DPA_Destroy(HDPA hdpa)
Definition: dpa.c:396
HDPA WINAPI DPA_Create(INT nGrow)
Definition: dpa.c:950
INT WINAPI DPA_InsertPtr(HDPA hdpa, INT i, LPVOID p)
Definition: dpa.c:591
HANDLE HWND
Definition: compat.h:19
#define CALLBACK
Definition: compat.h:35
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLbitfield flags
Definition: glext.h:7161
HLOCAL NTAPI LocalAlloc(UINT uFlags, SIZE_T dwBytes)
Definition: heapmem.c:1390
HLOCAL NTAPI LocalFree(HLOCAL hMem)
Definition: heapmem.c:1594
#define INT_MAX
Definition: intsafe.h:150
#define UINT_MAX
Definition: intsafe.h:152
if(dx< 0)
Definition: linetemp.h:194
#define ASSERT(a)
Definition: mode.c:44
static HDC
Definition: imagelist.c:88
static MONITORINFO mi
Definition: win.c:7338
#define min(a, b)
Definition: monoChain.cc:55
HMONITOR WINAPI MonitorFromRect(LPCRECT, DWORD)
HMONITOR WINAPI MonitorFromWindow(HWND, DWORD)
unsigned int UINT
Definition: ndis.h:50
#define _Inout_
Definition: no_sal2.h:162
#define _Out_
Definition: no_sal2.h:160
#define _In_
Definition: no_sal2.h:158
#define _In_opt_
Definition: no_sal2.h:212
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:325
_Out_ LPRECT prc
Definition: ntgdi.h:1658
#define DPA_GetPtrCount(hdpa)
Definition: commctrl.h:4960
#define DPA_GetPtr
Definition: commctrl.h:5
#define ABE_BOTTOM
Definition: shellapi.h:20
#define ABE_RIGHT
Definition: shellapi.h:19
#define ABE_TOP
Definition: shellapi.h:18
#define ABM_SETPOS
Definition: shellapi.h:65
#define ABE_LEFT
Definition: shellapi.h:17
#define ABM_REMOVE
Definition: shellapi.h:63
#define ABM_NEW
Definition: shellapi.h:62
#define ABN_POSCHANGED
Definition: shellapi.h:74
#define ABM_QUERYPOS
Definition: shellapi.h:64
#define TRACE(s)
Definition: solgame.cpp:4
UINT uEdge
Definition: appbar.h:14
RECT rc
Definition: appbar.h:15
HWND hWnd
Definition: appbar.h:12
UINT uCallbackMessage
Definition: appbar.h:13
RECT rcMonitor
Definition: winuser.h:3796
LONG right
Definition: windef.h:308
LONG bottom
Definition: windef.h:309
LONG top
Definition: windef.h:307
LONG left
Definition: windef.h:306
#define max(a, b)
Definition: svc.c:63
TW_UINT32 TW_UINT16 TW_UINT16 TW_MEMREF pData
Definition: twain.h:1830
int32_t INT
Definition: typedefs.h:58
struct tagAPPBAR_COMMAND * PAPPBAR_COMMAND
#define LPTR
Definition: winbase.h:407
LONG_PTR LPARAM
Definition: windef.h:208
LONG_PTR LRESULT
Definition: windef.h:209
BOOL WINAPI IsWindow(_In_opt_ HWND)
BOOL WINAPI RedrawWindow(_In_opt_ HWND, _In_opt_ LPCRECT, _In_opt_ HRGN, _In_ UINT)
BOOL WINAPI PostMessageW(_In_opt_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define WM_SIZE
Definition: winuser.h:1622
#define SM_CXFRAME
Definition: winuser.h:1005
BOOL WINAPI IsRectEmpty(_In_ LPCRECT)
BOOL WINAPI EnumDisplayMonitors(_In_opt_ HDC, _In_opt_ LPCRECT, _In_ MONITORENUMPROC, _In_ LPARAM)
#define RDW_ERASE
Definition: winuser.h:1222
int WINAPI MapWindowPoints(_In_opt_ HWND hWndFrom, _In_opt_ HWND hWndTo, _Inout_updates_(cPoints) LPPOINT lpPoints, _In_ UINT cPoints)
#define SM_CYFRAME
Definition: winuser.h:1007
#define SPIF_SENDCHANGE
Definition: winuser.h:1583
#define RDW_ALLCHILDREN
Definition: winuser.h:1232
BOOL WINAPI SystemParametersInfoW(_In_ UINT uiAction, _In_ UINT uiParam, _Inout_opt_ PVOID pvParam, _In_ UINT fWinIni)
BOOL WINAPI GetMonitorInfoW(_In_ HMONITOR, _Inout_ LPMONITORINFO)
BOOL WINAPI EqualRect(_In_ LPCRECT, _In_ LPCRECT)
int WINAPI GetSystemMetrics(_In_ int)
#define RDW_INVALIDATE
Definition: winuser.h:1225
LRESULT WINAPI SendMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
BOOL WINAPI SubtractRect(_Out_ LPRECT, _In_ LPCRECT, _In_ LPCRECT)