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.
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
));
817 hr
= bandSite
->QueryService(SID_SMenuPopup
, IID_PPV_ARG(IOleWindow
, &deskBar
));
819 CComPtr
<IOleWindow
> deskBarSite
;
820 hr
= IUnknown_GetSite(deskBar
, IID_PPV_ARG(IOleWindow
, &deskBarSite
));
822 // FIXME: Find the correct place for this
824 deskBarSite
->GetWindow(&hWndOwner
);
826 m_PreviousForeground
= ::GetForegroundWindow();
827 if (m_PreviousForeground
!= hWndOwner
)
828 ::SetForegroundWindow(hWndOwner
);
830 m_PreviousForeground
= NULL
;
832 // Get the HWND of the top-level window
834 hr
= deskBar
->GetWindow(&hWndSite
);
835 SetMenuCapture(hWndSite
);
839 if (!m_parent
|| m_parent
->type
== MenuBarEntry
)
841 if (old
&& old
->type
== TrackedMenuEntry
)
843 // FIXME: Debugging code, probably not right
847 ScreenToClient(m_current
->hwnd
, &pt2
);
848 GetClientRect(m_current
->hwnd
, &rc2
);
849 if (PtInRect(&rc2
, pt2
))
850 SendMessage(m_current
->hwnd
, WM_MOUSEMOVE
, 0, MAKELPARAM(pt2
.x
, pt2
.y
));
852 SendMessage(m_current
->hwnd
, WM_MOUSELEAVE
, 0, 0);
857 _ASSERT(!m_parent
|| m_parent
->type
!= TrackedMenuEntry
);
862 // Begin tracking top-level menu bar (for file browser windows)
863 HRESULT
CMenuFocusManager::PushMenuBar(CMenuBand
* mb
)
865 TRACE("PushMenuBar %p\n", mb
);
869 _ASSERT(m_bandCount
== 0);
871 HRESULT hr
= PushToArray(MenuBarEntry
, mb
, NULL
);
872 if (FAILED_UNEXPECTEDLY(hr
))
875 return UpdateFocus();
878 // Begin tracking a shell menu popup (start menu or submenus)
879 HRESULT
CMenuFocusManager::PushMenuPopup(CMenuBand
* mb
)
881 TRACE("PushTrackedPopup %p\n", mb
);
885 _ASSERT(!m_current
|| m_current
->type
!= TrackedMenuEntry
);
887 HRESULT hr
= PushToArray(MenuPopupEntry
, mb
, NULL
);
888 if (FAILED_UNEXPECTEDLY(hr
))
895 if (m_parent
&& m_parent
->type
!= TrackedMenuEntry
)
897 m_parent
->mb
->_SetChildBand(mb
);
898 mb
->_SetParentBand(m_parent
->mb
);
904 // Begin tracking a system popup submenu (submenu of the file browser windows)
905 HRESULT
CMenuFocusManager::PushTrackedPopup(HMENU popup
)
907 TRACE("PushTrackedPopup %p\n", popup
);
909 _ASSERT(m_bandCount
> 0);
910 _ASSERT(!m_current
|| m_current
->type
!= TrackedMenuEntry
);
912 HRESULT hr
= PushToArray(TrackedMenuEntry
, NULL
, popup
);
913 if (FAILED_UNEXPECTEDLY(hr
))
916 TRACE("PushTrackedPopup %p\n", popup
);
917 m_selectedMenu
= popup
;
919 m_selectedItemFlags
= 0;
921 return UpdateFocus();
924 // Stop tracking the menubar
925 HRESULT
CMenuFocusManager::PopMenuBar(CMenuBand
* mb
)
931 TRACE("PopMenuBar %p\n", mb
);
933 if (m_current
== m_entryUnderMouse
)
935 m_entryUnderMouse
= NULL
;
938 hr
= PopFromArray(&type
, &mbc
, NULL
);
939 if (FAILED_UNEXPECTEDLY(hr
))
945 _ASSERT(type
== MenuBarEntry
);
946 if (type
!= MenuBarEntry
)
952 mbc
->_SetParentBand(NULL
);
957 if (FAILED_UNEXPECTEDLY(hr
))
962 _ASSERT(m_current
->type
!= TrackedMenuEntry
);
963 m_current
->mb
->_SetChildBand(NULL
);
969 // Stop tracking a shell menu
970 HRESULT
CMenuFocusManager::PopMenuPopup(CMenuBand
* mb
)
976 TRACE("PopMenuPopup %p\n", mb
);
978 if (m_current
== m_entryUnderMouse
)
980 m_entryUnderMouse
= NULL
;
985 hr
= PopFromArray(&type
, &mbc
, NULL
);
986 if (FAILED_UNEXPECTEDLY(hr
))
992 _ASSERT(type
== MenuPopupEntry
);
993 if (type
!= MenuPopupEntry
)
999 mbc
->_SetParentBand(NULL
);
1004 if (FAILED_UNEXPECTEDLY(hr
))
1009 _ASSERT(m_current
->type
!= TrackedMenuEntry
);
1010 m_current
->mb
->_SetChildBand(NULL
);
1016 // Stop tracking a system popup submenu
1017 HRESULT
CMenuFocusManager::PopTrackedPopup(HMENU popup
)
1019 StackEntryType type
;
1023 TRACE("PopTrackedPopup %p\n", popup
);
1025 hr
= PopFromArray(&type
, NULL
, &hmenu
);
1026 if (FAILED_UNEXPECTEDLY(hr
))
1032 _ASSERT(type
== TrackedMenuEntry
);
1033 if (type
!= TrackedMenuEntry
)
1040 if (FAILED_UNEXPECTEDLY(hr
))