4 * Copyright 2014 David Quintana
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 This file implements the CMenuFocusManager class.
24 This class manages the shell menus, by overriding the hot-tracking behaviour.
26 For the shell menus, it uses a GetMessage hook,
27 where it intercepts messages directed to the menu windows.
29 In order to show submenus using system popups, it also has a MessageFilter hook.
31 The menu is tracked using a stack structure. When a CMenuBand wants to open a submenu,
32 it pushes the submenu band, or HMENU to track in case of system popups,
33 and when the menu has closed, it pops the same pointer or handle.
35 While a shell menu is open, it overrides the menu toolbar's hottracking behaviour,
36 using its own logic to track both the active menu item, and the opened submenu's parent item.
38 While a system popup is open, it tracks the mouse movements so that it can cancel the popup,
39 and switch to another submenu when the mouse goes over another item from the parent.
42 #include "shellmenu.h"
44 #include <commoncontrols.h>
45 #include <shlwapi_undoc.h>
47 #include "CMenuFocusManager.h"
48 #include "CMenuToolbars.h"
49 #include "CMenuBand.h"
53 # define _ASSERT(x) DbgAssert(!!(x), __FILE__, __LINE__, #x)
55 bool DbgAssert(bool x
, const char * filename
, int line
, const char * expr
)
62 fname
= strrchr(filename
, '\\');
65 fname
= strrchr(filename
, '/');
73 sprintf(szMsg
, "%s:%d: Assertion failed: %s\n", fname
, line
, expr
);
75 OutputDebugStringA(szMsg
);
83 # define _ASSERT(x) (!!(x))
86 WINE_DEFAULT_DEBUG_CHANNEL(CMenuFocus
);
88 DWORD
CMenuFocusManager::TlsIndex
= 0;
90 // Gets the thread's assigned manager without refcounting
91 CMenuFocusManager
* CMenuFocusManager::GetManager()
93 return reinterpret_cast<CMenuFocusManager
*>(TlsGetValue(TlsIndex
));
96 // Obtains a manager for the thread, with refcounting
97 CMenuFocusManager
* CMenuFocusManager::AcquireManager()
99 CMenuFocusManager
* obj
= NULL
;
103 if ((TlsIndex
= TlsAlloc()) == TLS_OUT_OF_INDEXES
)
111 obj
= new CComObject
<CMenuFocusManager
>();
112 TlsSetValue(TlsIndex
, obj
);
120 // Releases a previously acquired manager, and deletes it if the refcount reaches 0
121 void CMenuFocusManager::ReleaseManager(CMenuFocusManager
* obj
)
125 TlsSetValue(TlsIndex
, NULL
);
129 LRESULT CALLBACK
CMenuFocusManager::s_MsgFilterHook(INT nCode
, WPARAM wParam
, LPARAM lParam
)
131 return GetManager()->MsgFilterHook(nCode
, wParam
, lParam
);
134 LRESULT CALLBACK
CMenuFocusManager::s_GetMsgHook(INT nCode
, WPARAM wParam
, LPARAM lParam
)
136 return GetManager()->GetMsgHook(nCode
, wParam
, lParam
);
139 HRESULT
CMenuFocusManager::PushToArray(StackEntryType type
, CMenuBand
* mb
, HMENU hmenu
)
141 if (m_bandCount
>= MAX_RECURSE
)
142 return E_OUTOFMEMORY
;
144 m_bandStack
[m_bandCount
].type
= type
;
145 m_bandStack
[m_bandCount
].mb
= mb
;
146 m_bandStack
[m_bandCount
].hmenu
= hmenu
;
152 HRESULT
CMenuFocusManager::PopFromArray(StackEntryType
* pType
, CMenuBand
** pMb
, HMENU
* pHmenu
)
154 if (pType
) *pType
= NoEntry
;
155 if (pMb
) *pMb
= NULL
;
156 if (pHmenu
) *pHmenu
= NULL
;
158 if (m_bandCount
<= 0)
163 if (pType
) *pType
= m_bandStack
[m_bandCount
].type
;
164 if (*pType
== TrackedMenuEntry
)
166 if (pHmenu
) *pHmenu
= m_bandStack
[m_bandCount
].hmenu
;
170 if (pMb
) *pMb
= m_bandStack
[m_bandCount
].mb
;
176 CMenuFocusManager::CMenuFocusManager() :
179 m_hMsgFilterHook(NULL
),
181 m_mouseTrackDisabled(FALSE
),
183 m_hwndUnderMouse(NULL
),
184 m_entryUnderMouse(NULL
),
185 m_selectedMenu(NULL
),
187 m_selectedItemFlags(0),
188 m_isLButtonDown(FALSE
),
189 m_movedSinceDown(FALSE
),
190 m_windowAtDown(NULL
),
191 m_PreviousForeground(NULL
),
197 m_threadId
= GetCurrentThreadId();
200 CMenuFocusManager::~CMenuFocusManager()
204 // Used so that the toolbar can properly ignore mouse events, when the menu is being used with the keyboard
205 void CMenuFocusManager::DisableMouseTrack(HWND parent
, BOOL disableThis
)
207 BOOL bDisable
= FALSE
;
208 BOOL lastDisable
= FALSE
;
213 StackEntry
& entry
= m_bandStack
[i
];
215 if (entry
.type
!= TrackedMenuEntry
)
218 HRESULT hr
= entry
.mb
->_GetTopLevelWindow(&hwnd
);
219 if (FAILED_UNEXPECTEDLY(hr
))
224 lastDisable
= disableThis
;
225 entry
.mb
->_DisableMouseTrack(disableThis
);
230 lastDisable
= bDisable
;
231 entry
.mb
->_DisableMouseTrack(bDisable
);
235 m_mouseTrackDisabled
= lastDisable
;
238 void CMenuFocusManager::SetMenuCapture(HWND child
)
240 if (m_captureHwnd
!= child
)
245 m_captureHwnd
= child
;
246 TRACE("Capturing %p\n", child
);
251 m_captureHwnd
= NULL
;
252 TRACE("Capture is now off\n");
258 HRESULT
CMenuFocusManager::IsTrackedWindow(HWND hWnd
, StackEntry
** pentry
)
263 for (int i
= m_bandCount
; --i
>= 0;)
265 StackEntry
& entry
= m_bandStack
[i
];
267 if (entry
.type
!= TrackedMenuEntry
)
269 HRESULT hr
= entry
.mb
->IsWindowOwner(hWnd
);
270 if (FAILED_UNEXPECTEDLY(hr
))
284 HRESULT
CMenuFocusManager::IsTrackedWindowOrParent(HWND hWnd
)
286 for (int i
= m_bandCount
; --i
>= 0;)
288 StackEntry
& entry
= m_bandStack
[i
];
290 if (entry
.type
!= TrackedMenuEntry
)
292 HRESULT hr
= entry
.mb
->IsWindowOwner(hWnd
);
293 if (FAILED_UNEXPECTEDLY(hr
))
297 if (entry
.mb
->_IsPopup() == S_OK
)
299 CComPtr
<IUnknown
> site
;
300 CComPtr
<IOleWindow
> pw
;
301 hr
= entry
.mb
->GetSite(IID_PPV_ARG(IUnknown
, &site
));
302 if (FAILED_UNEXPECTEDLY(hr
))
304 hr
= IUnknown_QueryService(site
, SID_SMenuBandParent
, IID_PPV_ARG(IOleWindow
, &pw
));
305 if (FAILED_UNEXPECTEDLY(hr
))
309 if (pw
->GetWindow(&hParent
) == S_OK
&& hParent
== hWnd
)
318 LRESULT
CMenuFocusManager::ProcessMouseMove(MSG
* msg
)
321 int iHitTestResult
= -1;
323 POINT pt2
= { GET_X_LPARAM(msg
->lParam
), GET_Y_LPARAM(msg
->lParam
) };
324 ClientToScreen(msg
->hwnd
, &pt2
);
326 // Don't do anything if the mouse has not been moved
328 if (pt
.x
== m_ptPrev
.x
&& pt
.y
== m_ptPrev
.y
)
331 // Don't do anything if another window is capturing the mouse.
332 HWND cCapture
= ::GetCapture();
333 if (cCapture
&& cCapture
!= m_captureHwnd
&& m_current
->type
!= TrackedMenuEntry
)
336 m_movedSinceDown
= TRUE
;
340 child
= WindowFromPoint(pt
);
342 StackEntry
* entry
= NULL
;
343 if (IsTrackedWindow(child
, &entry
) == S_OK
)
345 TRACE("MouseMove %d\n", m_isLButtonDown
);
348 BOOL isTracking
= FALSE
;
349 if (entry
&& (entry
->type
== MenuBarEntry
|| m_current
->type
!= TrackedMenuEntry
))
351 ScreenToClient(child
, &pt
);
352 iHitTestResult
= SendMessageW(child
, TB_HITTEST
, 0, (LPARAM
) &pt
);
353 isTracking
= entry
->mb
->_IsTracking();
355 if (SendMessage(child
, WM_USER_ISTRACKEDITEM
, iHitTestResult
, 0) == S_FALSE
)
357 // The current tracked item has changed, notify the toolbar
359 TRACE("Hot item tracking detected a change (capture=%p / cCapture=%p)...\n", m_captureHwnd
, cCapture
);
360 DisableMouseTrack(NULL
, FALSE
);
361 if (isTracking
&& iHitTestResult
>= 0 && m_current
->type
== TrackedMenuEntry
)
362 SendMessage(entry
->hwnd
, WM_CANCELMODE
, 0, 0);
363 PostMessage(child
, WM_USER_CHANGETRACKEDITEM
, iHitTestResult
, MAKELPARAM(isTracking
, TRUE
));
364 if (m_current
->type
== TrackedMenuEntry
)
369 if (m_entryUnderMouse
!= entry
)
371 // Mouse moved away from a tracked window
372 if (m_entryUnderMouse
)
374 m_entryUnderMouse
->mb
->_ChangeHotItem(NULL
, -1, HICF_MOUSE
);
378 if (m_hwndUnderMouse
!= child
)
382 // Mouse moved to a tracked window
383 if (m_current
->type
== MenuPopupEntry
)
385 ScreenToClient(child
, &pt2
);
386 SendMessage(child
, WM_MOUSEMOVE
, msg
->wParam
, MAKELPARAM(pt2
.x
, pt2
.y
));
390 m_hwndUnderMouse
= child
;
391 m_entryUnderMouse
= entry
;
394 if (m_current
->type
== MenuPopupEntry
)
396 HWND parent
= GetAncestor(child
, GA_ROOT
);
397 DisableMouseTrack(parent
, FALSE
);
403 LRESULT
CMenuFocusManager::ProcessMouseDown(MSG
* msg
, BOOL isLButton
)
406 int iHitTestResult
= -1;
408 TRACE("ProcessMouseDown %d %d %d\n", msg
->message
, msg
->wParam
, msg
->lParam
);
410 // Don't do anything if another window is capturing the mouse.
411 HWND cCapture
= ::GetCapture();
412 if (cCapture
&& cCapture
!= m_captureHwnd
&& m_current
->type
!= TrackedMenuEntry
)
414 TRACE("Foreign capture active.\n");
420 child
= WindowFromPoint(pt
);
422 StackEntry
* entry
= NULL
;
423 if (IsTrackedWindow(child
, &entry
) != S_OK
)
425 TRACE("Foreign window detected.\n");
429 TRACE("MouseDown %d\n", m_isLButtonDown
);
431 if (entry
->type
== MenuBarEntry
)
433 if (entry
!= m_current
)
435 TRACE("Menubar with popup active.\n");
442 ScreenToClient(child
, &pt
);
443 iHitTestResult
= SendMessageW(child
, TB_HITTEST
, 0, (LPARAM
) &pt
);
445 if (iHitTestResult
>= 0)
447 TRACE("MouseDown send %d\n", iHitTestResult
);
448 entry
->mb
->_MenuBarMouseDown(child
, iHitTestResult
, isLButton
);
452 msg
->message
= WM_NULL
;
454 m_isLButtonDown
= TRUE
;
455 m_movedSinceDown
= FALSE
;
456 m_windowAtDown
= child
;
458 TRACE("MouseDown end %d\n", m_isLButtonDown
);
463 LRESULT
CMenuFocusManager::ProcessMouseUp(MSG
* msg
)
466 int iHitTestResult
= -1;
468 TRACE("ProcessMouseUp %d %d %d\n", msg
->message
, msg
->wParam
, msg
->lParam
);
470 // Don't do anything if another window is capturing the mouse.
471 HWND cCapture
= ::GetCapture();
472 if (cCapture
&& cCapture
!= m_captureHwnd
&& m_current
->type
!= TrackedMenuEntry
)
475 if (!m_isLButtonDown
)
478 m_isLButtonDown
= FALSE
;
482 child
= WindowFromPoint(pt
);
484 StackEntry
* entry
= NULL
;
485 if (IsTrackedWindow(child
, &entry
) != S_OK
)
488 TRACE("MouseUp %d\n", m_isLButtonDown
);
492 ScreenToClient(child
, &pt
);
493 iHitTestResult
= SendMessageW(child
, TB_HITTEST
, 0, (LPARAM
) &pt
);
495 if (iHitTestResult
>= 0)
497 TRACE("MouseUp send %d\n", iHitTestResult
);
498 entry
->mb
->_MenuBarMouseUp(child
, iHitTestResult
);
505 LRESULT
CMenuFocusManager::MsgFilterHook(INT nCode
, WPARAM hookWParam
, LPARAM hookLParam
)
508 return CallNextHookEx(m_hMsgFilterHook
, nCode
, hookWParam
, hookLParam
);
510 if (nCode
== MSGF_MENU
)
512 BOOL callNext
= TRUE
;
513 MSG
* msg
= reinterpret_cast<MSG
*>(hookLParam
);
515 switch (msg
->message
)
519 if (m_menuBar
&& m_current
->type
== TrackedMenuEntry
)
522 HWND child
= WindowFromPoint(pt
);
523 BOOL hoveringMenuBar
= m_menuBar
->mb
->IsWindowOwner(child
) == S_OK
;
526 m_menuBar
->mb
->_BeforeCancelPopup();
531 callNext
= ProcessMouseMove(msg
);
533 case WM_INITMENUPOPUP
:
534 TRACE("WM_INITMENUPOPUP %p %p\n", msg
->wParam
, msg
->lParam
);
535 m_selectedMenu
= reinterpret_cast<HMENU
>(msg
->lParam
);
537 m_selectedItemFlags
= 0;
540 TRACE("WM_MENUSELECT %p %p\n", msg
->wParam
, msg
->lParam
);
541 m_selectedMenu
= reinterpret_cast<HMENU
>(msg
->lParam
);
542 m_selectedItem
= GET_X_LPARAM(msg
->wParam
);
543 m_selectedItemFlags
= HIWORD(msg
->wParam
);
549 if (m_current
->hmenu
== m_selectedMenu
)
551 m_parent
->mb
->_MenuItemSelect(VK_LEFT
);
555 if (m_selectedItem
< 0 || !(m_selectedItemFlags
& MF_POPUP
))
557 m_parent
->mb
->_MenuItemSelect(VK_RIGHT
);
568 return CallNextHookEx(m_hMsgFilterHook
, nCode
, hookWParam
, hookLParam
);
571 LRESULT
CMenuFocusManager::GetMsgHook(INT nCode
, WPARAM hookWParam
, LPARAM hookLParam
)
573 BOOL isLButton
= FALSE
;
575 return CallNextHookEx(m_hGetMsgHook
, nCode
, hookWParam
, hookLParam
);
577 if (nCode
== HC_ACTION
)
579 BOOL callNext
= TRUE
;
580 MSG
* msg
= reinterpret_cast<MSG
*>(hookLParam
);
583 switch (msg
->message
)
585 case WM_CAPTURECHANGED
:
588 TRACE("Capture lost.\n");
589 m_captureHwnd
= NULL
;
593 case WM_NCLBUTTONDOWN
:
599 case WM_NCRBUTTONDOWN
:
601 if (m_menuBar
&& m_current
->type
== MenuPopupEntry
)
604 HWND child
= WindowFromPoint(pt
);
605 BOOL hoveringMenuBar
= m_menuBar
->mb
->IsWindowOwner(child
) == S_OK
;
608 m_current
->mb
->_MenuItemSelect(MPOS_FULLCANCEL
);
613 if (m_current
->type
== MenuPopupEntry
)
615 HWND child
= WindowFromPoint(pt
);
617 if (IsTrackedWindowOrParent(child
) != S_OK
)
619 m_current
->mb
->_MenuItemSelect(MPOS_FULLCANCEL
);
624 ProcessMouseDown(msg
, isLButton
);
632 callNext
= ProcessMouseMove(msg
);
635 callNext
= ProcessMouseMove(msg
);
636 //callNext = ProcessMouseLeave(msg);
640 if (m_current
->type
== MenuPopupEntry
)
642 DisableMouseTrack(m_current
->hwnd
, TRUE
);
649 m_current
->mb
->_MenuItemSelect(MPOS_FULLCANCEL
);
652 m_current
->mb
->_MenuItemSelect(MPOS_EXECUTE
);
655 m_current
->mb
->_MenuItemSelect(VK_LEFT
);
658 m_current
->mb
->_MenuItemSelect(VK_RIGHT
);
661 m_current
->mb
->_MenuItemSelect(VK_UP
);
664 m_current
->mb
->_MenuItemSelect(VK_DOWN
);
667 msg
->message
= WM_NULL
;
678 return CallNextHookEx(m_hGetMsgHook
, nCode
, hookWParam
, hookLParam
);
681 HRESULT
CMenuFocusManager::PlaceHooks()
683 if (m_hMsgFilterHook
)
685 WARN("GETMESSAGE hook already placed!\n");
688 if (m_hMsgFilterHook
)
690 WARN("MSGFILTER hook already placed!\n");
693 if (m_current
->type
== TrackedMenuEntry
)
695 TRACE("Entering MSGFILTER hook...\n");
696 m_hMsgFilterHook
= SetWindowsHookEx(WH_MSGFILTER
, s_MsgFilterHook
, NULL
, m_threadId
);
700 TRACE("Entering GETMESSAGE hook...\n");
701 m_hGetMsgHook
= SetWindowsHookEx(WH_GETMESSAGE
, s_GetMsgHook
, NULL
, m_threadId
);
706 HRESULT
CMenuFocusManager::RemoveHooks()
708 if (m_hMsgFilterHook
)
710 TRACE("Removing MSGFILTER hook...\n");
711 UnhookWindowsHookEx(m_hMsgFilterHook
);
712 m_hMsgFilterHook
= NULL
;
716 TRACE("Removing GETMESSAGE hook...\n");
717 UnhookWindowsHookEx(m_hGetMsgHook
);
718 m_hGetMsgHook
= NULL
;
723 // Used to update the tracking info to account for a change in the top-level menu
724 HRESULT
CMenuFocusManager::UpdateFocus()
727 StackEntry
* old
= m_current
;
729 TRACE("UpdateFocus\n");
731 // Assign the new current item
733 m_current
= &(m_bandStack
[m_bandCount
- 1]);
737 // Remove the menu capture if necesary
738 if (!m_current
|| m_current
->type
!= MenuPopupEntry
)
740 SetMenuCapture(NULL
);
741 if (old
&& old
->type
== MenuPopupEntry
&& m_PreviousForeground
)
743 ::SetForegroundWindow(m_PreviousForeground
);
744 m_PreviousForeground
= NULL
;
748 // Obtain the top-level window for the new active menu
749 if (m_current
&& m_current
->type
!= TrackedMenuEntry
)
751 hr
= m_current
->mb
->_GetTopLevelWindow(&(m_current
->hwnd
));
752 if (FAILED_UNEXPECTEDLY(hr
))
756 // Refresh the parent pointer
757 if (m_bandCount
>= 2)
759 m_parent
= &(m_bandStack
[m_bandCount
- 2]);
760 _ASSERT(m_parent
->type
!= TrackedMenuEntry
);
767 // Refresh the menubar pointer, if applicable
768 if (m_bandCount
>= 1 && m_bandStack
[0].type
== MenuBarEntry
)
770 m_menuBar
= &(m_bandStack
[0]);
777 // Remove the old hooks if the menu type changed, or we don't have a menu anymore
778 if (old
&& (!m_current
|| old
->type
!= m_current
->type
))
780 if (m_current
&& m_current
->type
!= TrackedMenuEntry
)
782 DisableMouseTrack(m_current
->hwnd
, FALSE
);
786 if (FAILED_UNEXPECTEDLY(hr
))
790 // And place new ones if necessary
791 if (m_current
&& (!old
|| old
->type
!= m_current
->type
))
794 if (FAILED_UNEXPECTEDLY(hr
))
798 // Give the user a chance to move the mouse to the new menu
801 DisableMouseTrack(m_parent
->hwnd
, TRUE
);
804 if (m_current
&& m_current
->type
== MenuPopupEntry
)
806 if (m_captureHwnd
== NULL
)
808 // We need to restore the capture after a non-shell submenu or context menu is shown
809 StackEntry
* topMenu
= m_bandStack
;
810 if (topMenu
->type
== MenuBarEntry
)
813 // Get the top-level window from the top popup
814 CComPtr
<IServiceProvider
> bandSite
;
815 CComPtr
<IOleWindow
> deskBar
;
816 hr
= topMenu
->mb
->GetSite(IID_PPV_ARG(IServiceProvider
, &bandSite
));
819 hr
= bandSite
->QueryService(SID_SMenuPopup
, IID_PPV_ARG(IOleWindow
, &deskBar
));
823 CComPtr
<IOleWindow
> deskBarSite
;
824 hr
= IUnknown_GetSite(deskBar
, IID_PPV_ARG(IOleWindow
, &deskBarSite
));
828 // FIXME: Find the correct place for this
830 hr
= deskBarSite
->GetWindow(&hWndOwner
);
834 m_PreviousForeground
= ::GetForegroundWindow();
835 if (m_PreviousForeground
!= hWndOwner
)
836 ::SetForegroundWindow(hWndOwner
);
838 m_PreviousForeground
= NULL
;
840 // Get the HWND of the top-level window
842 hr
= deskBar
->GetWindow(&hWndSite
);
845 SetMenuCapture(hWndSite
);
849 if (!m_parent
|| m_parent
->type
== MenuBarEntry
)
851 if (old
&& old
->type
== TrackedMenuEntry
)
853 // FIXME: Debugging code, probably not right
857 ScreenToClient(m_current
->hwnd
, &pt2
);
858 GetClientRect(m_current
->hwnd
, &rc2
);
859 if (PtInRect(&rc2
, pt2
))
860 SendMessage(m_current
->hwnd
, WM_MOUSEMOVE
, 0, MAKELPARAM(pt2
.x
, pt2
.y
));
862 SendMessage(m_current
->hwnd
, WM_MOUSELEAVE
, 0, 0);
867 _ASSERT(!m_parent
|| m_parent
->type
!= TrackedMenuEntry
);
872 // Begin tracking top-level menu bar (for file browser windows)
873 HRESULT
CMenuFocusManager::PushMenuBar(CMenuBand
* mb
)
875 TRACE("PushMenuBar %p\n", mb
);
879 _ASSERT(m_bandCount
== 0);
881 HRESULT hr
= PushToArray(MenuBarEntry
, mb
, NULL
);
882 if (FAILED_UNEXPECTEDLY(hr
))
885 return UpdateFocus();
888 // Begin tracking a shell menu popup (start menu or submenus)
889 HRESULT
CMenuFocusManager::PushMenuPopup(CMenuBand
* mb
)
891 TRACE("PushTrackedPopup %p\n", mb
);
895 _ASSERT(!m_current
|| m_current
->type
!= TrackedMenuEntry
);
897 HRESULT hr
= PushToArray(MenuPopupEntry
, mb
, NULL
);
898 if (FAILED_UNEXPECTEDLY(hr
))
905 if (m_parent
&& m_parent
->type
!= TrackedMenuEntry
)
907 m_parent
->mb
->_SetChildBand(mb
);
908 mb
->_SetParentBand(m_parent
->mb
);
914 // Begin tracking a system popup submenu (submenu of the file browser windows)
915 HRESULT
CMenuFocusManager::PushTrackedPopup(HMENU popup
)
917 TRACE("PushTrackedPopup %p\n", popup
);
919 _ASSERT(m_bandCount
> 0);
920 _ASSERT(!m_current
|| m_current
->type
!= TrackedMenuEntry
);
922 HRESULT hr
= PushToArray(TrackedMenuEntry
, NULL
, popup
);
923 if (FAILED_UNEXPECTEDLY(hr
))
926 TRACE("PushTrackedPopup %p\n", popup
);
927 m_selectedMenu
= popup
;
929 m_selectedItemFlags
= 0;
931 return UpdateFocus();
934 // Stop tracking the menubar
935 HRESULT
CMenuFocusManager::PopMenuBar(CMenuBand
* mb
)
941 TRACE("PopMenuBar %p\n", mb
);
943 if (m_current
== m_entryUnderMouse
)
945 m_entryUnderMouse
= NULL
;
948 hr
= PopFromArray(&type
, &mbc
, NULL
);
949 if (FAILED_UNEXPECTEDLY(hr
))
955 _ASSERT(type
== MenuBarEntry
);
956 if (type
!= MenuBarEntry
)
962 mbc
->_SetParentBand(NULL
);
967 if (FAILED_UNEXPECTEDLY(hr
))
972 _ASSERT(m_current
->type
!= TrackedMenuEntry
);
973 m_current
->mb
->_SetChildBand(NULL
);
979 // Stop tracking a shell menu
980 HRESULT
CMenuFocusManager::PopMenuPopup(CMenuBand
* mb
)
986 TRACE("PopMenuPopup %p\n", mb
);
988 if (m_current
== m_entryUnderMouse
)
990 m_entryUnderMouse
= NULL
;
995 hr
= PopFromArray(&type
, &mbc
, NULL
);
996 if (FAILED_UNEXPECTEDLY(hr
))
1002 _ASSERT(type
== MenuPopupEntry
);
1003 if (type
!= MenuPopupEntry
)
1009 mbc
->_SetParentBand(NULL
);
1014 if (FAILED_UNEXPECTEDLY(hr
))
1019 _ASSERT(m_current
->type
!= TrackedMenuEntry
);
1020 m_current
->mb
->_SetChildBand(NULL
);
1026 // Stop tracking a system popup submenu
1027 HRESULT
CMenuFocusManager::PopTrackedPopup(HMENU popup
)
1029 StackEntryType type
;
1033 TRACE("PopTrackedPopup %p\n", popup
);
1035 hr
= PopFromArray(&type
, NULL
, &hmenu
);
1036 if (FAILED_UNEXPECTEDLY(hr
))
1042 _ASSERT(type
== TrackedMenuEntry
);
1043 if (type
!= TrackedMenuEntry
)
1050 if (FAILED_UNEXPECTEDLY(hr
))