#include "CMenuToolbars.h"
#include "CMenuBand.h"
+#if DBG
+# undef _ASSERT
+# define _ASSERT(x) DbgAssert(!!(x), __FILE__, __LINE__, #x)
+
+bool DbgAssert(bool x, const char * filename, int line, const char * expr)
+{
+ if (!x)
+ {
+ char szMsg[512];
+ const char *fname;
+
+ fname = strrchr(filename, '\\');
+ if (fname == NULL)
+ {
+ fname = strrchr(filename, '/');
+ }
+
+ if (fname == NULL)
+ fname = filename;
+ else
+ fname++;
+
+ sprintf(szMsg, "%s:%d: Assertion failed: %s\n", fname, line, expr);
+
+ OutputDebugStringA(szMsg);
+
+ __debugbreak();
+ }
+ return x;
+}
+#else
+# undef _ASSERT
+# define _ASSERT(x) (!!(x))
+#endif
+
WINE_DEFAULT_DEBUG_CHANNEL(CMenuFocus);
DWORD CMenuFocusManager::TlsIndex = 0;
return GetManager()->GetMsgHook(nCode, wParam, lParam);
}
-HRESULT CMenuFocusManager::PushToArray(CMenuBand * item)
+HRESULT CMenuFocusManager::PushToArray(StackEntryType type, CMenuBand * mb, HMENU hmenu)
{
if (m_bandCount >= MAX_RECURSE)
return E_OUTOFMEMORY;
- m_bandStack[m_bandCount++] = item;
- return S_OK;
-}
-
-HRESULT CMenuFocusManager::PopFromArray(CMenuBand ** pItem)
-{
- if (pItem)
- *pItem = NULL;
-
- if (m_bandCount <= 0)
- return S_FALSE;
-
- m_bandCount--;
-
- if (pItem)
- *pItem = m_bandStack[m_bandCount];
-
- m_bandStack[m_bandCount] = NULL;
+ m_bandStack[m_bandCount].type = type;
+ m_bandStack[m_bandCount].mb = mb;
+ m_bandStack[m_bandCount].hmenu = hmenu;
+ m_bandCount++;
return S_OK;
}
-HRESULT CMenuFocusManager::PeekArray(CMenuBand ** pItem)
+HRESULT CMenuFocusManager::PopFromArray(StackEntryType * pType, CMenuBand ** pMb, HMENU * pHmenu)
{
- if (!pItem)
- return E_FAIL;
-
- *pItem = NULL;
+ if (pType) *pType = NoEntry;
+ if (pMb) *pMb = NULL;
+ if (pHmenu) *pHmenu = NULL;
if (m_bandCount <= 0)
return S_FALSE;
- *pItem = m_bandStack[m_bandCount - 1];
+ m_bandCount--;
+ if (pType) *pType = m_bandStack[m_bandCount].type;
+ if (*pType == TrackedMenuEntry)
+ {
+ if (pHmenu) *pHmenu = m_bandStack[m_bandCount].hmenu;
+ }
+ else
+ {
+ if (pMb) *pMb = m_bandStack[m_bandCount].mb;
+ }
+
return S_OK;
}
CMenuFocusManager::CMenuFocusManager() :
- m_currentBand(NULL),
- m_currentFocus(NULL),
- m_currentMenu(NULL),
- m_parentToolbar(NULL),
+ m_current(NULL),
+ m_parent(NULL),
m_hMsgFilterHook(NULL),
m_hGetMsgHook(NULL),
m_mouseTrackDisabled(FALSE),
- m_lastMoveFlags(0),
- m_lastMovePos(0),
+ m_captureHwnd(0),
+ m_hwndUnderMouse(NULL),
+ m_entryUnderMouse(NULL),
+ m_selectedMenu(NULL),
+ m_selectedItem(0),
+ m_selectedItemFlags(0),
+ m_isLButtonDown(FALSE),
+ m_movedSinceDown(FALSE),
+ m_windowAtDown(NULL),
m_bandCount(0)
{
+ m_ptPrev.x = 0;
+ m_ptPrev.y = 0;
m_threadId = GetCurrentThreadId();
}
{
}
-void CMenuFocusManager::DisableMouseTrack(HWND enableTo, BOOL disableThis)
+void CMenuFocusManager::DisableMouseTrack(HWND parent, BOOL disableThis)
{
BOOL bDisable = FALSE;
+ BOOL lastDisable = FALSE;
int i = m_bandCount;
while (--i >= 0)
{
- CMenuBand * band = m_bandStack[i];
-
- HWND hwnd;
- HRESULT hr = band->_GetTopLevelWindow(&hwnd);
- if (FAILED_UNEXPECTEDLY(hr))
- break;
+ StackEntry& entry = m_bandStack[i];
- if (hwnd == enableTo)
+ if (entry.type != TrackedMenuEntry)
{
- band->_DisableMouseTrack(disableThis);
- bDisable = TRUE;
- }
- else
- {
- band->_DisableMouseTrack(bDisable);
+ HWND hwnd;
+ HRESULT hr = entry.mb->_GetTopLevelWindow(&hwnd);
+ if (FAILED_UNEXPECTEDLY(hr))
+ break;
+
+ if (hwnd == parent)
+ {
+ lastDisable = disableThis;
+ entry.mb->_DisableMouseTrack(disableThis);
+ bDisable = TRUE;
+ }
+ else
+ {
+ lastDisable = bDisable;
+ entry.mb->_DisableMouseTrack(bDisable);
+ }
}
}
+ m_mouseTrackDisabled = lastDisable;
+}
- if (m_mouseTrackDisabled == bDisable)
+void CMenuFocusManager::SetCapture(HWND child)
+{
+ if (m_captureHwnd != child)
{
- if (bDisable)
+ if (child)
{
- SetCapture(m_currentFocus);
+ ::SetCapture(child);
+ m_captureHwnd = child;
+ TRACE("MouseTrack is now capturing %p\n", child);
}
else
- ReleaseCapture();
+ {
+ ::ReleaseCapture();
+ m_captureHwnd = NULL;
+ TRACE("MouseTrack is now off\n");
+ }
- m_mouseTrackDisabled = bDisable;
}
}
-HRESULT CMenuFocusManager::IsTrackedWindow(HWND hWnd)
+HRESULT CMenuFocusManager::IsTrackedWindow(HWND hWnd, StackEntry ** pentry)
{
- int i = m_bandCount;
- while (--i >= 0)
+ if (pentry)
+ *pentry = NULL;
+
+ for (int i = m_bandCount; --i >= 0;)
{
- CMenuBand * band = m_bandStack[i];
+ StackEntry& entry = m_bandStack[i];
- HWND hwnd;
- HRESULT hr = band->_GetTopLevelWindow(&hwnd);
- if (FAILED_UNEXPECTEDLY(hr))
- return hr;
+ if (entry.type != TrackedMenuEntry)
+ {
+ HRESULT hr = entry.mb->IsWindowOwner(hWnd);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+ if (hr == S_OK)
+ {
+ if (pentry)
+ *pentry = &entry;
+ return S_OK;
+ }
+ }
+ }
- if (hwnd == hWnd)
+ return S_FALSE;
+}
+
+HRESULT CMenuFocusManager::IsTrackedWindowOrParent(HWND hWnd)
+{
+ for (int i = m_bandCount; --i >= 0;)
+ {
+ StackEntry& entry = m_bandStack[i];
+
+ if (entry.type != TrackedMenuEntry)
{
- return band->_IsPopup();
+ HRESULT hr = entry.mb->IsWindowOwner(hWnd);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+ if (hr == S_OK)
+ return S_OK;
+ if (entry.mb->_IsPopup() == S_OK)
+ {
+ CComPtr<IUnknown> site;
+ CComPtr<IOleWindow> pw;
+ hr = entry.mb->GetSite(IID_PPV_ARG(IUnknown, &site));
+ if (FAILED_UNEXPECTEDLY(hr))
+ continue;
+ hr = IUnknown_QueryService(site, SID_SMenuBandParent, IID_PPV_ARG(IOleWindow, &pw));
+ if (FAILED_UNEXPECTEDLY(hr))
+ continue;
+
+ HWND hParent;
+ if (pw->GetWindow(&hParent) == S_OK && hParent == hWnd)
+ return S_OK;
+ }
}
}
LRESULT CMenuFocusManager::ProcessMouseMove(MSG* msg)
{
- HWND parent;
HWND child;
- POINT pt;
- int iHitTestResult;
+ int iHitTestResult = -1;
+
+ POINT pt2 = { GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam) };
+ ClientToScreen(msg->hwnd, &pt2);
+
+ // Don't do anything if the mouse has not been moved
+ POINT pt = msg->pt;
+ if (pt.x == m_ptPrev.x && pt.y == m_ptPrev.y)
+ return TRUE;
+
+ // Don't do anything if another window is capturing the mouse.
+ HWND cCapture = ::GetCapture();
+ if (cCapture && cCapture != m_captureHwnd && m_current->type != TrackedMenuEntry)
+ return TRUE;
+
+
+ m_movedSinceDown = TRUE;
+
+ m_ptPrev = pt;
+
+ child = WindowFromPoint(pt);
+
+ StackEntry * entry = NULL;
+ if (IsTrackedWindow(child, &entry) == S_OK)
+ {
+ TRACE("MouseMove %d\n", m_isLButtonDown);
+ }
+
+ BOOL isTracking = FALSE;
+ if (entry && (entry->type == MenuBarEntry || m_current->type != TrackedMenuEntry))
+ {
+ ScreenToClient(child, &pt);
+ iHitTestResult = SendMessageW(child, TB_HITTEST, 0, (LPARAM) &pt);
+ isTracking = entry->mb->_IsTracking();
+
+ if (SendMessage(child, WM_USER_ISTRACKEDITEM, iHitTestResult, 0) == S_FALSE)
+ {
+ TRACE("Hot item tracking detected a change (capture=%p / cCapture=%p)...\n", m_captureHwnd, cCapture);
+ DisableMouseTrack(NULL, FALSE);
+ if (isTracking && iHitTestResult >= 0 && m_current->type == TrackedMenuEntry)
+ SendMessage(entry->hwnd, WM_CANCELMODE, 0, 0);
+ PostMessage(child, WM_USER_CHANGETRACKEDITEM, iHitTestResult, MAKELPARAM(isTracking, TRUE));
+ if (m_current->type == TrackedMenuEntry)
+ return FALSE;
+ }
+ }
+
+ if (m_entryUnderMouse != entry)
+ {
+ // Mouse moved away from a tracked window
+ if (m_entryUnderMouse)
+ {
+ m_entryUnderMouse->mb->_ChangeHotItem(NULL, -1, HICF_MOUSE);
+ }
+ if (cCapture == m_captureHwnd)
+ SetCapture(NULL);
+ }
+
+ if (m_hwndUnderMouse != child)
+ {
+ if (entry)
+ {
+ // Mouse moved to a tracked window
+ if (m_current->type == MenuPopupEntry)
+ {
+ ScreenToClient(child, &pt2);
+ SendMessage(child, WM_MOUSEMOVE, msg->wParam, MAKELPARAM(pt2.x, pt2.y));
+ }
+ }
+
+ m_hwndUnderMouse = child;
+ m_entryUnderMouse = entry;
+ }
+
+ if (m_current->type == MenuPopupEntry)
+ {
+ HWND parent = GetAncestor(child, GA_ROOT);
+ DisableMouseTrack(parent, FALSE);
+ }
+
+ return TRUE;
+}
+
+LRESULT CMenuFocusManager::ProcessMouseDown(MSG* msg)
+{
+ HWND child;
+ int iHitTestResult = -1;
- pt = msg->pt;
+ TRACE("ProcessMouseDown %d %d %d\n", msg->message, msg->wParam, msg->lParam);
+
+ // Don't do anything if another window is capturing the mouse.
+ HWND cCapture = ::GetCapture();
+ if (cCapture && cCapture != m_captureHwnd && m_current->type != TrackedMenuEntry)
+ return TRUE;
- parent = WindowFromPoint(pt);
- ScreenToClient(parent, &pt);
+ POINT pt = msg->pt;
- child = ChildWindowFromPoint(parent, pt);
+ child = WindowFromPoint(pt);
- if (child != m_parentToolbar)
+ StackEntry * entry = NULL;
+ if (IsTrackedWindow(child, &entry) != S_OK)
return TRUE;
- ScreenToClient(m_parentToolbar, &msg->pt);
+ TRACE("MouseDown %d\n", m_isLButtonDown);
+
+ if (entry)
+ {
+ ScreenToClient(child, &pt);
+ iHitTestResult = SendMessageW(child, TB_HITTEST, 0, (LPARAM) &pt);
+
+ if (iHitTestResult >= 0)
+ {
+ TRACE("MouseDown send %d\n", iHitTestResult);
+ entry->mb->_MenuBarMouseDown(child, iHitTestResult);
+ }
+ }
+
+ msg->message = WM_NULL;
+
+ m_isLButtonDown = TRUE;
+ m_movedSinceDown = FALSE;
+ m_windowAtDown = child;
+
+ TRACE("MouseDown end %d\n", m_isLButtonDown);
+
+ return TRUE;
+}
+
+LRESULT CMenuFocusManager::ProcessMouseUp(MSG* msg)
+{
+ HWND child;
+ int iHitTestResult = -1;
+
+ TRACE("ProcessMouseUp %d %d %d\n", msg->message, msg->wParam, msg->lParam);
- /* Don't do anything if the mouse has not been moved */
- if (msg->pt.x == m_ptPrev.x && msg->pt.y == m_ptPrev.y)
+ // Don't do anything if another window is capturing the mouse.
+ HWND cCapture = ::GetCapture();
+ if (cCapture && cCapture != m_captureHwnd && m_current->type != TrackedMenuEntry)
return TRUE;
- m_ptPrev = msg->pt;
+ if (!m_isLButtonDown)
+ return TRUE;
+
+ m_isLButtonDown = FALSE;
+
+ POINT pt = msg->pt;
- iHitTestResult = SendMessageW(m_parentToolbar, TB_HITTEST, 0, (LPARAM) &msg->pt);
+ child = WindowFromPoint(pt);
+
+ StackEntry * entry = NULL;
+ if (IsTrackedWindow(child, &entry) != S_OK)
+ return TRUE;
- /* Make sure that iHitTestResult is one of the menu items and that it is not the current menu item */
- if (iHitTestResult >= 0)
+ TRACE("MouseUp %d\n", m_isLButtonDown);
+
+ if (entry)
{
- HWND hwndToolbar = m_parentToolbar;
- if (SendMessage(hwndToolbar, WM_USER_ISTRACKEDITEM, iHitTestResult, 0))
+ ScreenToClient(child, &pt);
+ iHitTestResult = SendMessageW(child, TB_HITTEST, 0, (LPARAM) &pt);
+
+ if (iHitTestResult >= 0)
{
- DbgPrint("Hot item tracking detected a change...\n");
- if (m_currentMenu)
- SendMessage(m_currentFocus, WM_CANCELMODE, 0, 0);
- else
- m_currentBand->_MenuItemHotTrack(MPOS_CANCELLEVEL);
- DbgPrint("Active popup cancelled, notifying of change...\n");
- PostMessage(hwndToolbar, WM_USER_CHANGETRACKEDITEM, iHitTestResult, iHitTestResult);
- return FALSE;
+ TRACE("MouseUp send %d\n", iHitTestResult);
+ entry->mb->_MenuBarMouseUp(child, iHitTestResult);
}
}
return TRUE;
}
-LRESULT CMenuFocusManager::MsgFilterHook(INT nCode, WPARAM wParam, LPARAM lParam)
+LRESULT CMenuFocusManager::MsgFilterHook(INT nCode, WPARAM hookWParam, LPARAM hookLParam)
{
if (nCode < 0)
- return CallNextHookEx(m_hMsgFilterHook, nCode, wParam, lParam);
+ return CallNextHookEx(m_hMsgFilterHook, nCode, hookWParam, hookLParam);
if (nCode == MSGF_MENU)
{
BOOL callNext = TRUE;
- MSG* msg = reinterpret_cast<MSG*>(lParam);
-
- // Do whatever is necessary here
+ MSG* msg = reinterpret_cast<MSG*>(hookLParam);
switch (msg->message)
{
+ case WM_NCLBUTTONDOWN:
+ case WM_LBUTTONDOWN:
+ case WM_NCRBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ if (m_menuBar)
+ {
+ POINT pt = msg->pt;
+ HWND child = WindowFromPoint(pt);
+ BOOL hoveringMenuBar = m_menuBar->mb->IsWindowOwner(child) == S_OK;
+ if (hoveringMenuBar)
+ {
+ m_menuBar->mb->_DisableMouseTrack(TRUE);
+ if (m_current->type == TrackedMenuEntry)
+ {
+ SendMessage(m_parent->hwnd, WM_CANCELMODE, 0, 0);
+ msg->message = WM_NULL;
+ }
+ }
+ }
+ break;
+ case WM_NCLBUTTONUP:
+ case WM_LBUTTONUP:
+ case WM_NCRBUTTONUP:
+ case WM_RBUTTONUP:
+ if (m_current && m_current->type != TrackedMenuEntry)
+ {
+ msg->message = WM_NULL;
+ }
+ break;
case WM_MOUSEMOVE:
callNext = ProcessMouseMove(msg);
break;
+ case WM_INITMENUPOPUP:
+ TRACE("WM_INITMENUPOPUP %p %p\n", msg->wParam, msg->lParam);
+ m_selectedMenu = reinterpret_cast<HMENU>(msg->lParam);
+ m_selectedItem = -1;
+ m_selectedItemFlags = 0;
+ break;
+ case WM_MENUSELECT:
+ TRACE("WM_MENUSELECT %p %p\n", msg->wParam, msg->lParam);
+ m_selectedMenu = reinterpret_cast<HMENU>(msg->lParam);
+ m_selectedItem = GET_X_LPARAM(msg->wParam);
+ m_selectedItemFlags = HIWORD(msg->wParam);
+ break;
+ case WM_KEYDOWN:
+ switch (msg->wParam)
+ {
+ case VK_LEFT:
+ if (m_current->hmenu == m_selectedMenu)
+ {
+ m_parent->mb->_MenuItemHotTrack(VK_LEFT);
+ }
+ break;
+ case VK_RIGHT:
+ if (m_selectedItem < 0 || !(m_selectedItemFlags & MF_POPUP))
+ {
+ m_parent->mb->_MenuItemHotTrack(VK_RIGHT);
+ }
+ break;
+ }
+ break;
}
if (!callNext)
- return 0;
+ return 1;
}
- return CallNextHookEx(m_hMsgFilterHook, nCode, wParam, lParam);
+ return CallNextHookEx(m_hMsgFilterHook, nCode, hookWParam, hookLParam);
}
-LRESULT CMenuFocusManager::GetMsgHook(INT nCode, WPARAM wParam, LPARAM lParam)
+LRESULT CMenuFocusManager::GetMsgHook(INT nCode, WPARAM hookWParam, LPARAM hookLParam)
{
+ BOOL isLButton = FALSE;
if (nCode < 0)
- return CallNextHookEx(m_hGetMsgHook, nCode, wParam, lParam);
-
- LPARAM pos = (LPARAM) GetMessagePos();
-
+ return CallNextHookEx(m_hGetMsgHook, nCode, hookWParam, hookLParam);
+
if (nCode == HC_ACTION)
{
BOOL callNext = TRUE;
- MSG* msg = reinterpret_cast<MSG*>(lParam);
-
- // Do whatever is necessary here
+ MSG* msg = reinterpret_cast<MSG*>(hookLParam);
+ POINT pt = msg->pt;
switch (msg->message)
{
- case WM_CLOSE:
- break;
-
case WM_NCLBUTTONDOWN:
case WM_LBUTTONDOWN:
- {
- POINT pt = { GET_X_LPARAM(pos), GET_Y_LPARAM(pos) };
-
- HWND window = GetAncestor(WindowFromPoint(pt), GA_ROOT);
+ isLButton = TRUE;
- if (IsTrackedWindow(window) != S_OK)
+ // fallthrough;
+ case WM_NCRBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ if (m_current->type == MenuPopupEntry)
{
- DisableMouseTrack(NULL, FALSE);
- m_currentBand->_MenuItemHotTrack(MPOS_FULLCANCEL);
- }
-
- break;
- }
- case WM_MOUSEMOVE:
- if (m_lastMoveFlags != wParam || m_lastMovePos != pos)
- {
- m_lastMoveFlags = wParam;
- m_lastMovePos = pos;
-
- POINT pt = { GET_X_LPARAM(pos), GET_Y_LPARAM(pos) };
+ HWND child = WindowFromPoint(pt);
- HWND window = WindowFromPoint(pt);
-
- if (IsTrackedWindow(window) == S_OK)
- {
- DisableMouseTrack(window, FALSE);
- }
- else
+ if (IsTrackedWindowOrParent(child) != S_OK)
{
- DisableMouseTrack(NULL, FALSE);
+ SetCapture(NULL);
+ m_current->mb->_MenuItemHotTrack(MPOS_FULLCANCEL);
+ break;
}
}
+
+ if (isLButton)
+ {
+ ProcessMouseDown(msg);
+ }
+ break;
+ case WM_NCLBUTTONUP:
+ case WM_LBUTTONUP:
+ ProcessMouseUp(msg);
+ break;
+ case WM_MOUSEMOVE:
callNext = ProcessMouseMove(msg);
break;
+ case WM_MOUSELEAVE:
+ callNext = ProcessMouseMove(msg);
+ //callNext = ProcessMouseLeave(msg);
+ break;
case WM_SYSKEYDOWN:
case WM_KEYDOWN:
- //if (!m_currentMenu)
+ if (m_current->type == MenuPopupEntry)
{
- DisableMouseTrack(m_currentFocus, TRUE);
+ DisableMouseTrack(m_current->hwnd, TRUE);
switch (msg->wParam)
{
+ case VK_ESCAPE:
case VK_MENU:
case VK_LMENU:
case VK_RMENU:
- m_currentBand->_MenuItemHotTrack(MPOS_FULLCANCEL);
+ m_current->mb->_MenuItemHotTrack(MPOS_FULLCANCEL);
+ break;
+ case VK_RETURN:
+ m_current->mb->_MenuItemHotTrack(MPOS_EXECUTE);
break;
case VK_LEFT:
- m_currentBand->_MenuItemHotTrack(MPOS_SELECTLEFT);
+ m_current->mb->_MenuItemHotTrack(VK_LEFT);
break;
case VK_RIGHT:
- m_currentBand->_MenuItemHotTrack(MPOS_SELECTRIGHT);
+ m_current->mb->_MenuItemHotTrack(VK_RIGHT);
break;
case VK_UP:
- m_currentBand->_MenuItemHotTrack(VK_UP);
+ m_current->mb->_MenuItemHotTrack(VK_UP);
break;
case VK_DOWN:
- m_currentBand->_MenuItemHotTrack(VK_DOWN);
+ m_current->mb->_MenuItemHotTrack(VK_DOWN);
break;
}
+ msg->message = WM_NULL;
+ msg->lParam = 0;
+ msg->wParam = 0;
}
break;
}
if (!callNext)
- return 0;
+ return 1;
}
- return CallNextHookEx(m_hGetMsgHook, nCode, wParam, lParam);
+ return CallNextHookEx(m_hGetMsgHook, nCode, hookWParam, hookLParam);
}
HRESULT CMenuFocusManager::PlaceHooks()
{
- //SetCapture(window);
- if (m_currentMenu)
+ if (m_hMsgFilterHook)
+ {
+ WARN("GETMESSAGE hook already placed!\n");
+ return S_OK;
+ }
+ if (m_hMsgFilterHook)
+ {
+ WARN("MSGFILTER hook already placed!\n");
+ return S_OK;
+ }
+ if (m_current->type == TrackedMenuEntry)
{
- DbgPrint("Entering MSGFILTER hook...\n");
+ TRACE("Entering MSGFILTER hook...\n");
m_hMsgFilterHook = SetWindowsHookEx(WH_MSGFILTER, s_MsgFilterHook, NULL, m_threadId);
}
else
{
- DbgPrint("Entering GETMESSAGE hook...\n");
+ TRACE("Entering GETMESSAGE hook...\n");
m_hGetMsgHook = SetWindowsHookEx(WH_GETMESSAGE, s_GetMsgHook, NULL, m_threadId);
}
return S_OK;
HRESULT CMenuFocusManager::RemoveHooks()
{
- DbgPrint("Removing all hooks...\n");
+ TRACE("Removing all hooks...\n");
if (m_hMsgFilterHook)
UnhookWindowsHookEx(m_hMsgFilterHook);
if (m_hGetMsgHook)
return S_OK;
}
-HRESULT CMenuFocusManager::UpdateFocus(CMenuBand * newBand, HMENU popupToTrack)
+HRESULT CMenuFocusManager::UpdateFocus()
{
HRESULT hr;
- HWND newFocus = NULL;
- HWND oldFocus = m_currentFocus;
- HMENU oldMenu = m_currentMenu;
+ StackEntry * old = m_current;
- if (newBand)
+ TRACE("UpdateFocus\n");
+
+ if (old)
+ SetCapture(NULL);
+
+ if (m_bandCount > 0)
+ m_current = &(m_bandStack[m_bandCount - 1]);
+ else
+ m_current = NULL;
+
+ if (m_current && m_current->type != TrackedMenuEntry)
{
- hr = newBand->_GetTopLevelWindow(&newFocus);
+ hr = m_current->mb->_GetTopLevelWindow(&(m_current->hwnd));
if (FAILED_UNEXPECTEDLY(hr))
return hr;
}
- m_currentBand = newBand;
- m_currentMenu = popupToTrack;
- m_currentFocus = newFocus;
- m_parentToolbar = NULL;
- if (popupToTrack)
+ if (m_bandCount >= 2)
{
- m_currentBand->GetWindow(&m_parentToolbar);
+ m_parent = &(m_bandStack[m_bandCount - 2]);
+ _ASSERT(m_parent->type != TrackedMenuEntry);
}
- else if (m_bandCount >= 2)
+ else
{
- m_bandStack[m_bandCount - 2]->GetWindow(&m_parentToolbar);
+ m_parent = NULL;
}
- if (oldFocus && (!newFocus || (oldMenu != popupToTrack)))
+ if (m_bandCount >= 1 && m_bandStack[0].type == MenuBarEntry)
{
- DisableMouseTrack(NULL, FALSE);
+ m_menuBar = &(m_bandStack[0]);
+ }
+ else
+ {
+ m_menuBar = NULL;
+ }
+
+ if (old && (!m_current || old->type != m_current->type))
+ {
+ if (m_current && m_current->type != TrackedMenuEntry)
+ {
+ DisableMouseTrack(m_current->hwnd, FALSE);
+ }
hr = RemoveHooks();
if (FAILED_UNEXPECTEDLY(hr))
return hr;
}
-
- if (newFocus && (!oldFocus || (oldMenu != popupToTrack)))
+
+ if (m_current && (!old || old->type != m_current->type))
{
hr = PlaceHooks();
if (FAILED_UNEXPECTEDLY(hr))
return hr;
}
+ if (m_parent)
+ {
+ DisableMouseTrack(m_parent->hwnd, TRUE);
+ }
+
+ if ((m_current && m_current->type == MenuPopupEntry) &&
+ (!m_parent || m_parent->type == MenuBarEntry))
+ {
+ // When the mouse moves, it should set itself to the proper band
+ SetCapture(m_current->hwnd);
+
+ if (old && old->type == TrackedMenuEntry)
+ {
+ // FIXME: Debugging code, probably not right
+ POINT pt2;
+ RECT rc2;
+ GetCursorPos(&pt2);
+ ScreenToClient(m_current->hwnd, &pt2);
+ GetClientRect(m_current->hwnd, &rc2);
+ if (PtInRect(&rc2, pt2))
+ SendMessage(m_current->hwnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt2.x, pt2.y));
+ else
+ SendMessage(m_current->hwnd, WM_MOUSELEAVE, 0, 0);
+ }
+ }
+
+ _ASSERT(!m_parent || m_parent->type != TrackedMenuEntry);
return S_OK;
}
-HRESULT CMenuFocusManager::PushMenu(CMenuBand * mb)
+HRESULT CMenuFocusManager::PushMenuBar(CMenuBand * mb)
{
- HRESULT hr;
+ DbgPrint("PushMenuBar %p\n", mb);
- CMenuBand * mbParent = m_currentBand;
+ mb->AddRef();
- hr = PushToArray(mb);
+ _ASSERT(m_bandCount == 0);
+
+ HRESULT hr = PushToArray(MenuBarEntry, mb, NULL);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ return UpdateFocus();
+}
+
+HRESULT CMenuFocusManager::PushMenuPopup(CMenuBand * mb)
+{
+ DbgPrint("PushTrackedPopup %p\n", mb);
+
+ mb->AddRef();
+
+ _ASSERT(!m_current || m_current->type != TrackedMenuEntry);
+
+ HRESULT hr = PushToArray(MenuPopupEntry, mb, NULL);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
- if (mbParent)
+ hr = UpdateFocus();
+
+ if (m_parent && m_parent->type != TrackedMenuEntry)
{
- mbParent->_SetChildBand(mb);
- mb->_SetParentBand(mbParent);
+ m_parent->mb->_SetChildBand(mb);
+ mb->_SetParentBand(m_parent->mb);
}
- return UpdateFocus(mb);
+ return hr;
}
-HRESULT CMenuFocusManager::PopMenu(CMenuBand * mb)
+HRESULT CMenuFocusManager::PushTrackedPopup(HMENU popup)
{
+ DbgPrint("PushTrackedPopup %p\n", popup);
+
+ _ASSERT(m_bandCount > 0);
+ _ASSERT(!m_current || m_current->type != TrackedMenuEntry);
+
+ HRESULT hr = PushToArray(TrackedMenuEntry, NULL, popup);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ DbgPrint("PushTrackedPopup %p\n", popup);
+ m_selectedMenu = popup;
+ m_selectedItem = -1;
+ m_selectedItemFlags = 0;
+
+ return UpdateFocus();
+}
+
+HRESULT CMenuFocusManager::PopMenuBar(CMenuBand * mb)
+{
+ StackEntryType type;
CMenuBand * mbc;
HRESULT hr;
- if (m_currentBand)
+ DbgPrint("PopMenuBar %p\n", mb);
+
+ if (m_current == m_entryUnderMouse)
{
- m_currentBand->_SetParentBand(NULL);
+ m_entryUnderMouse = NULL;
}
- HWND newFocus;
- hr = mb->_GetTopLevelWindow(&newFocus);
+ hr = PopFromArray(&type, &mbc, NULL);
if (FAILED_UNEXPECTEDLY(hr))
+ {
+ UpdateFocus();
return hr;
-
- DbgPrint("Trying to pop %08p, hwnd=%08x\n", mb, newFocus);
-
- do {
- hr = PopFromArray(&mbc);
- if (FAILED_UNEXPECTEDLY(hr))
- {
- UpdateFocus(NULL);
- return hr;
- }
}
- while (mbc && mb != mbc);
+
+ _ASSERT(type == MenuBarEntry);
+ if (type != MenuBarEntry)
+ return E_FAIL;
if (!mbc)
return E_FAIL;
-
- hr = PeekArray(&mb);
- if (FAILED_UNEXPECTEDLY(hr))
- return hr;
- hr = UpdateFocus(mb);
+ mbc->_SetParentBand(NULL);
+
+ mbc->Release();
+
+ hr = UpdateFocus();
if (FAILED_UNEXPECTEDLY(hr))
return hr;
- if (mb)
+ if (m_current)
{
- mb->_SetChildBand(NULL);
+ _ASSERT(m_current->type != TrackedMenuEntry);
+ m_current->mb->_SetChildBand(NULL);
}
return S_OK;
}
-HRESULT CMenuFocusManager::PushTrackedPopup(CMenuBand * mb, HMENU popup)
+HRESULT CMenuFocusManager::PopMenuPopup(CMenuBand * mb)
{
+ StackEntryType type;
+ CMenuBand * mbc;
HRESULT hr;
- hr = PushToArray(mb);
+ DbgPrint("PopMenuPopup %p\n", mb);
+
+ if (m_current == m_entryUnderMouse)
+ {
+ m_entryUnderMouse = NULL;
+ }
+
+ hr = PopFromArray(&type, &mbc, NULL);
if (FAILED_UNEXPECTEDLY(hr))
+ {
+ UpdateFocus();
return hr;
+ }
- return UpdateFocus(mb, popup);
-}
+ _ASSERT(type == MenuPopupEntry);
+ if (type != MenuPopupEntry)
+ return E_FAIL;
-HRESULT CMenuFocusManager::PopTrackedPopup(CMenuBand * mb, HMENU popup)
-{
- CMenuBand * mbc;
- HRESULT hr;
+ if (!mbc)
+ return E_FAIL;
- HWND newFocus;
- hr = mb->_GetTopLevelWindow(&newFocus);
+ mbc->_SetParentBand(NULL);
+
+ mbc->Release();
+
+ hr = UpdateFocus();
if (FAILED_UNEXPECTEDLY(hr))
return hr;
- DbgPrint("Trying to pop %08p, hwnd=%08x\n", mb, newFocus);
+ if (m_current)
+ {
+ _ASSERT(m_current->type != TrackedMenuEntry);
+ m_current->mb->_SetChildBand(NULL);
+ }
- do {
- hr = PopFromArray(&mbc);
- if (FAILED_UNEXPECTEDLY(hr))
- {
- UpdateFocus(NULL);
- return hr;
- }
- } while (mbc && mb != mbc);
+ return S_OK;
+}
- if (!mbc)
- return E_FAIL;
+HRESULT CMenuFocusManager::PopTrackedPopup(HMENU popup)
+{
+ StackEntryType type;
+ HMENU hmenu;
+ HRESULT hr;
+
+ DbgPrint("PopTrackedPopup %p\n", popup);
- hr = PeekArray(&mb);
+ hr = PopFromArray(&type, NULL, &hmenu);
if (FAILED_UNEXPECTEDLY(hr))
+ {
+ UpdateFocus();
return hr;
+ }
+
+ _ASSERT(type == TrackedMenuEntry);
+ if (type != TrackedMenuEntry)
+ return E_FAIL;
+
+ if (hmenu != popup)
+ return E_FAIL;
- hr = UpdateFocus(mb);
+ hr = UpdateFocus();
if (FAILED_UNEXPECTEDLY(hr))
return hr;