From 8676a39ebcaecb08b638172ffccbdaeba8ce1c1c Mon Sep 17 00:00:00 2001 From: David Quintana Date: Wed, 26 Mar 2014 11:33:52 +0000 Subject: [PATCH] [RSHELL] * Redesigned large portions of the focus manager. All the mouse interactions seem to work now CORE-7586. svn path=/branches/shell-experiments/; revision=62567 --- base/shell/rshell/CMenuBand.cpp | 42 +- base/shell/rshell/CMenuDeskBar.cpp | 40 +- base/shell/rshell/CMenuFocusManager.cpp | 502 ++++++++++++++---------- base/shell/rshell/CMenuFocusManager.h | 50 ++- base/shell/rshell/CMenuToolbars.cpp | 40 +- base/shell/rshell/misc.cpp | 2 +- base/shell/rshell/precomp.h | 6 +- 7 files changed, 404 insertions(+), 278 deletions(-) diff --git a/base/shell/rshell/CMenuBand.cpp b/base/shell/rshell/CMenuBand.cpp index c0914628650..4374417e496 100644 --- a/base/shell/rshell/CMenuBand.cpp +++ b/base/shell/rshell/CMenuBand.cpp @@ -284,17 +284,17 @@ HRESULT STDMETHODCALLTYPE CMenuBand::OnPosRectChangeDB(RECT *prc) if (m_SFToolbar) { m_SFToolbar->SetPosSize( - prc->left, - prc->top, - prc->right - prc->left, + prc->left, + prc->top, + prc->right - prc->left, syShlFld); } if (m_staticToolbar) { m_staticToolbar->SetPosSize( - prc->left, - prc->top + syShlFld, - prc->right - prc->left, + prc->left, + prc->top + syShlFld, + prc->right - prc->left, syStatic); } @@ -360,10 +360,20 @@ HRESULT STDMETHODCALLTYPE CMenuBand::ShowDW(BOOL fShow) m_parentBand->SetClient(NULL); } - if (fShow) - hr = m_focusManager->PushMenu(this); + if (_IsPopup() == S_OK) + { + if (fShow) + hr = m_focusManager->PushMenuPopup(this); + else + hr = m_focusManager->PopMenuPopup(this); + } else - hr = m_focusManager->PopMenu(this); + { + if (fShow) + hr = m_focusManager->PushMenuBar(this); + else + hr = m_focusManager->PopMenuBar(this); + } return S_OK; } @@ -510,15 +520,15 @@ HRESULT CMenuBand::_IsPopup() HRESULT STDMETHODCALLTYPE CMenuBand::SetClient(IUnknown *punkClient) { - if (m_subMenuChild) - m_subMenuChild = NULL; + m_subMenuChild = NULL; + if (!punkClient) { if (m_staticToolbar) m_staticToolbar->OnPopupItemChanged(NULL, -1); if (m_SFToolbar) m_SFToolbar->OnPopupItemChanged(NULL, -1); return S_OK; } - HRESULT hr = punkClient->QueryInterface(IID_PPV_ARG(IMenuPopup, &m_subMenuChild)); + HRESULT hr = punkClient->QueryInterface(IID_PPV_ARG(IMenuPopup, &m_subMenuChild)); m_trackingPopup = m_subMenuChild != NULL; DbgPrint("Tracking: %d\n", m_trackingPopup); return hr; @@ -596,7 +606,7 @@ HRESULT STDMETHODCALLTYPE CMenuBand::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wPa { return m_SFToolbar->OnWinEvent(hWnd, uMsg, wParam, lParam, theResult); } - + return S_FALSE; } @@ -659,7 +669,7 @@ HRESULT CMenuBand::_TrackSubMenuUsingTrackPopupMenu(HMENU popup, INT x, INT y, R m_trackingPopup = TRUE; DbgPrint("Tracking: %d\n", m_trackingPopup); - m_focusManager->PushTrackedPopup(this, popup); + m_focusManager->PushTrackedPopup(popup); if (m_menuOwner) { ::TrackPopupMenuEx(popup, flags, x, y, m_menuOwner, ¶ms); @@ -668,7 +678,7 @@ HRESULT CMenuBand::_TrackSubMenuUsingTrackPopupMenu(HMENU popup, INT x, INT y, R { ::TrackPopupMenuEx(popup, flags, x, y, m_topLevelWindow, ¶ms); } - m_focusManager->PopTrackedPopup(this, popup); + m_focusManager->PopTrackedPopup(popup); m_trackingPopup = FALSE; DbgPrint("Tracking: %d\n", m_trackingPopup); @@ -1008,7 +1018,7 @@ HRESULT STDMETHODCALLTYPE CMenuBand::GetClassID(CLSID *pClassID) return S_OK; } -HRESULT STDMETHODCALLTYPE CMenuBand::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText) +HRESULT STDMETHODCALLTYPE CMenuBand::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText) { UNIMPLEMENTED; return S_OK; diff --git a/base/shell/rshell/CMenuDeskBar.cpp b/base/shell/rshell/CMenuDeskBar.cpp index 94340cdf453..88428b7e88c 100644 --- a/base/shell/rshell/CMenuDeskBar.cpp +++ b/base/shell/rshell/CMenuDeskBar.cpp @@ -133,7 +133,7 @@ HRESULT STDMETHODCALLTYPE CMenuDeskBar::QueryService(REFGUID guidService, REFIID { return this->QueryInterface(riid, ppvObject); } - + if (IsEqualGUID(guidService, SID_SMenuBandBottom) || IsEqualGUID(guidService, SID_SMenuBandBottomSelected) || IsEqualGUID(guidService, SID_SMenuBandChild)) @@ -299,7 +299,7 @@ HRESULT STDMETHODCALLTYPE CMenuDeskBar::Popup(POINTL *ppt, RECTL *prcExclude, MP ::GetObject(m_Banner, sizeof(bm), &bm); rc.right += bm.bmWidth; } - + int x, y, cx, cy; RECT rcWorkArea; @@ -350,7 +350,7 @@ HRESULT STDMETHODCALLTYPE CMenuDeskBar::Popup(POINTL *ppt, RECTL *prcExclude, MP { cy = waHeight; } - + if (y + cy > rcWorkArea.bottom) { y = rcWorkArea.bottom - cy; @@ -438,23 +438,23 @@ HRESULT STDMETHODCALLTYPE CMenuDeskBar::SetSubMenu(IMenuPopup *pmp, BOOL fSet) HRESULT STDMETHODCALLTYPE CMenuDeskBar::OnSelect(DWORD dwSelectType) { /* As far as I can tell, the submenu hierarchy looks like this: - - The DeskBar's Child is the Band it contains. - The DeskBar's Parent is the SID_SMenuPopup of the Site. - - The Band's Child is the IMenuPopup of the child submenu. - The Band's Parent is the SID_SMenuPopup of the Site (the DeskBar). - - When the DeskBar receives a selection event: - If it requires closing the window, it will notify the Child (Band) using CancelLevel. - If it has to spread upwards (everything but CancelLevel), it will notify the Parent. - - When the Band receives a selection event, this is where it gets fuzzy: - In which cases does it call the Parent? Probably not CancelLevel. - In which cases does it call the Child? - How does it react to calls? - - */ + * + * The DeskBar's Child is the Band it contains. + * The DeskBar's Parent is the SID_SMenuPopup of the Site. + * + * The Band's Child is the IMenuPopup of the child submenu. + * The Band's Parent is the SID_SMenuPopup of the Site (the DeskBar). + * + * When the DeskBar receives a selection event: + * If it requires closing the window, it will notify the Child (Band) using CancelLevel. + * If it has to spread upwards (everything but CancelLevel), it will notify the Parent. + * + * When the Band receives a selection event, this is where it gets fuzzy: + * In which cases does it call the Parent? Probably not CancelLevel. + * In which cases does it call the Child? + * How does it react to calls? + * + */ switch (dwSelectType) { diff --git a/base/shell/rshell/CMenuFocusManager.cpp b/base/shell/rshell/CMenuFocusManager.cpp index ca1a64dfe95..78f7736e889 100644 --- a/base/shell/rshell/CMenuFocusManager.cpp +++ b/base/shell/rshell/CMenuFocusManager.cpp @@ -26,6 +26,36 @@ #include "CMenuToolbars.h" #include "CMenuBand.h" +#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; +} + WINE_DEFAULT_DEBUG_CHANNEL(CMenuFocus); DWORD CMenuFocusManager::TlsIndex = 0; @@ -76,60 +106,56 @@ LRESULT CALLBACK CMenuFocusManager::s_GetMsgHook(INT nCode, WPARAM wParam, LPARA 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; + 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::PopFromArray(CMenuBand ** pItem) +HRESULT CMenuFocusManager::PopFromArray(StackEntryType * pType, CMenuBand ** pMb, HMENU * pHmenu) { - if (pItem) - *pItem = NULL; + if (pType) *pType = NoEntry; + if (pMb) *pMb = NULL; + if (pHmenu) *pHmenu = NULL; if (m_bandCount <= 0) return S_FALSE; m_bandCount--; - if (pItem) - *pItem = m_bandStack[m_bandCount]; - - m_bandStack[m_bandCount] = NULL; - - return S_OK; -} - -HRESULT CMenuFocusManager::PeekArray(CMenuBand ** pItem) -{ - if (!pItem) - return E_FAIL; - - *pItem = NULL; - - if (m_bandCount <= 0) - return S_FALSE; - - *pItem = m_bandStack[m_bandCount - 1]; - + 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_bandCount(0) { + m_ptPrev.x = 0; + m_ptPrev.y = 0; m_threadId = GetCurrentThreadId(); } @@ -137,41 +163,60 @@ CMenuFocusManager::~CMenuFocusManager() { } -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 == MenuPopupEntry) { - band->_DisableMouseTrack(disableThis); - bDisable = TRUE; + 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); + } } else { - band->_DisableMouseTrack(bDisable); + continue; } } + 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; + DbgPrint("MouseTrack is now capturing %p\n", child); } else - ReleaseCapture(); + { + ::ReleaseCapture(); + m_captureHwnd = NULL; + DbgPrint("MouseTrack is now off\n"); + } - m_mouseTrackDisabled = bDisable; } } @@ -180,16 +225,15 @@ HRESULT CMenuFocusManager::IsTrackedWindow(HWND hWnd) int i = m_bandCount; while (--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 (hwnd == hWnd) + if (entry.type == MenuPopupEntry) { - return band->_IsPopup(); + HRESULT hr = entry.mb->IsWindowOwner(hWnd); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + if (hr == S_OK) + return S_OK; } } @@ -198,23 +242,21 @@ HRESULT CMenuFocusManager::IsTrackedWindow(HWND hWnd) LRESULT CMenuFocusManager::ProcessMouseMove(MSG* msg) { - HWND parent; HWND child; POINT pt; int iHitTestResult; pt = msg->pt; - parent = WindowFromPoint(pt); + child = WindowFromPoint(pt); - ScreenToClient(parent, &pt); - - child = ChildWindowFromPoint(parent, pt); - - if (child != m_parentToolbar) + if (!m_parent) return TRUE; - ScreenToClient(m_parentToolbar, &msg->pt); + if (m_parent->mb->IsWindowOwner(child) != S_OK) + return TRUE; + + ScreenToClient(child, &msg->pt); /* Don't do anything if the mouse has not been moved */ if (msg->pt.x == m_ptPrev.x && msg->pt.y == m_ptPrev.y) @@ -222,20 +264,19 @@ LRESULT CMenuFocusManager::ProcessMouseMove(MSG* msg) m_ptPrev = msg->pt; - iHitTestResult = SendMessageW(m_parentToolbar, TB_HITTEST, 0, (LPARAM) &msg->pt); + iHitTestResult = SendMessageW(child, TB_HITTEST, 0, (LPARAM) &msg->pt); /* Make sure that iHitTestResult is one of the menu items and that it is not the current menu item */ if (iHitTestResult >= 0) { - HWND hwndToolbar = m_parentToolbar; + HWND hwndToolbar = child; if (SendMessage(hwndToolbar, WM_USER_ISTRACKEDITEM, iHitTestResult, 0)) { DbgPrint("Hot item tracking detected a change...\n"); - if (m_currentMenu) - SendMessage(m_currentFocus, WM_CANCELMODE, 0, 0); + if (m_current->type == TrackedMenuEntry) + SendMessage(m_parent->hwnd, WM_CANCELMODE, 0, 0); else - m_currentBand->_MenuItemHotTrack(MPOS_CANCELLEVEL); - DbgPrint("Active popup cancelled, notifying of change...\n"); + m_current->mb->_MenuItemHotTrack(MPOS_CANCELLEVEL); PostMessage(hwndToolbar, WM_USER_CHANGETRACKEDITEM, iHitTestResult, iHitTestResult); return FALSE; } @@ -253,9 +294,7 @@ LRESULT CMenuFocusManager::MsgFilterHook(INT nCode, WPARAM wParam, LPARAM lParam { BOOL callNext = TRUE; MSG* msg = reinterpret_cast(lParam); - - // Do whatever is necessary here - + switch (msg->message) { case WM_MOUSEMOVE: @@ -281,9 +320,7 @@ LRESULT CMenuFocusManager::GetMsgHook(INT nCode, WPARAM wParam, LPARAM lParam) { BOOL callNext = TRUE; MSG* msg = reinterpret_cast(lParam); - - // Do whatever is necessary here - + switch (msg->message) { case WM_CLOSE: @@ -291,65 +328,78 @@ LRESULT CMenuFocusManager::GetMsgHook(INT nCode, WPARAM wParam, LPARAM lParam) case WM_NCLBUTTONDOWN: case WM_LBUTTONDOWN: - { - POINT pt = { GET_X_LPARAM(pos), GET_Y_LPARAM(pos) }; - - HWND window = GetAncestor(WindowFromPoint(pt), GA_ROOT); - - if (IsTrackedWindow(window) != S_OK) + 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 window = WindowFromPoint(pt); - - if (IsTrackedWindow(window) == S_OK) + HWND child = WindowFromPoint(pt); + HWND window = GetAncestor(child, GA_ROOT); + + if (IsTrackedWindow(window) != S_OK) { - DisableMouseTrack(window, FALSE); - } - else - { - DisableMouseTrack(NULL, FALSE); + m_current->mb->_MenuItemHotTrack(MPOS_FULLCANCEL); } } - callNext = ProcessMouseMove(msg); + break; + case WM_MOUSEMOVE: + if ((m_parent && m_parent->type==MenuPopupEntry) || ProcessMouseMove(msg)) + { + if (m_current->type == MenuPopupEntry) + { + 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 = GetAncestor(child, GA_ROOT); + + if (m_parent && m_parent->mb->IsWindowOwner(child) == S_OK) + { + DisableMouseTrack(window, FALSE); + } + else if (IsTrackedWindow(child) == S_OK) + { + DisableMouseTrack(window, FALSE); + SetCapture(child); + } + else + { + DisableMouseTrack(NULL, FALSE); + SetCapture(NULL); + } + } + } + } + else + { + callNext = FALSE; + } break; case WM_SYSKEYDOWN: case WM_KEYDOWN: - //if (!m_currentMenu) + DisableMouseTrack(m_current->hwnd, TRUE); + switch (msg->wParam) { - DisableMouseTrack(m_currentFocus, TRUE); - switch (msg->wParam) - { - case VK_MENU: - case VK_LMENU: - case VK_RMENU: - m_currentBand->_MenuItemHotTrack(MPOS_FULLCANCEL); - break; - case VK_LEFT: - m_currentBand->_MenuItemHotTrack(MPOS_SELECTLEFT); - break; - case VK_RIGHT: - m_currentBand->_MenuItemHotTrack(MPOS_SELECTRIGHT); - break; - case VK_UP: - m_currentBand->_MenuItemHotTrack(VK_UP); - break; - case VK_DOWN: - m_currentBand->_MenuItemHotTrack(VK_DOWN); - break; - } + case VK_MENU: + case VK_LMENU: + case VK_RMENU: + m_current->mb->_MenuItemHotTrack(MPOS_FULLCANCEL); + break; + case VK_LEFT: + m_current->mb->_MenuItemHotTrack(MPOS_SELECTLEFT); + break; + case VK_RIGHT: + m_current->mb->_MenuItemHotTrack(MPOS_SELECTRIGHT); + break; + case VK_UP: + m_current->mb->_MenuItemHotTrack(VK_UP); + break; + case VK_DOWN: + m_current->mb->_MenuItemHotTrack(VK_DOWN); + break; } break; } @@ -363,8 +413,7 @@ LRESULT CMenuFocusManager::GetMsgHook(INT nCode, WPARAM wParam, LPARAM lParam) HRESULT CMenuFocusManager::PlaceHooks() { - //SetCapture(window); - if (m_currentMenu) + if (m_current->hmenu) { DbgPrint("Entering MSGFILTER hook...\n"); m_hMsgFilterHook = SetWindowsHookEx(WH_MSGFILTER, s_MsgFilterHook, NULL, m_threadId); @@ -389,34 +438,37 @@ HRESULT CMenuFocusManager::RemoveHooks() 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) + 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 (old && (!m_current || old->type != m_current->type)) { DisableMouseTrack(NULL, FALSE); @@ -424,123 +476,161 @@ HRESULT CMenuFocusManager::UpdateFocus(CMenuBand * newBand, HMENU popupToTrack) 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_current && m_current->type == MenuPopupEntry) && + (!m_parent || m_parent->type == MenuBarEntry)) + { + DisableMouseTrack(m_current->hwnd, FALSE); + + // When the mouse moves, it should set itself to the proper band + SetCapture(m_current->hwnd); + } + + _ASSERT(!m_parent || m_parent->type != TrackedMenuEntry); return S_OK; } -HRESULT CMenuFocusManager::PushMenu(CMenuBand * mb) +HRESULT CMenuFocusManager::PushMenuBar(CMenuBand * mb) { - HRESULT hr; + _ASSERT(m_bandCount == 0); - CMenuBand * mbParent = m_currentBand; - - hr = PushToArray(mb); + HRESULT hr = PushToArray(MenuBarEntry, mb, NULL); if (FAILED_UNEXPECTEDLY(hr)) return hr; - if (mbParent) - { - mbParent->_SetChildBand(mb); - mb->_SetParentBand(mbParent); - } - - return UpdateFocus(mb); + return UpdateFocus(); } -HRESULT CMenuFocusManager::PopMenu(CMenuBand * mb) +HRESULT CMenuFocusManager::PushMenuPopup(CMenuBand * mb) { + _ASSERT(!m_current || m_current->type != TrackedMenuEntry); + + HRESULT hr = PushToArray(MenuPopupEntry, mb, NULL); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + hr = UpdateFocus(); + + if (m_parent && m_parent->type != TrackedMenuEntry) + { + m_parent->mb->_SetChildBand(mb); + mb->_SetParentBand(m_parent->mb); + } + + return hr; +} + +HRESULT CMenuFocusManager::PushTrackedPopup(HMENU popup) +{ + _ASSERT(m_bandCount > 0); + _ASSERT(!m_current || m_current->type != TrackedMenuEntry); + + HRESULT hr = PushToArray(TrackedMenuEntry, NULL, popup); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + return UpdateFocus(); +} + +HRESULT CMenuFocusManager::PopMenuBar(CMenuBand * mb) +{ + StackEntryType type; CMenuBand * mbc; HRESULT hr; - if (m_currentBand) - { - m_currentBand->_SetParentBand(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); + + mbc->_SetParentBand(NULL); + + hr = UpdateFocus(); if (FAILED_UNEXPECTEDLY(hr)) return hr; - hr = UpdateFocus(mb); - 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 hr; - - hr = PushToArray(mb); - if (FAILED_UNEXPECTEDLY(hr)) - return hr; - - return UpdateFocus(mb, popup); -} - -HRESULT CMenuFocusManager::PopTrackedPopup(CMenuBand * mb, HMENU popup) +HRESULT CMenuFocusManager::PopMenuPopup(CMenuBand * mb) { + StackEntryType type; CMenuBand * mbc; HRESULT hr; - 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 == MenuPopupEntry); + if (type != MenuPopupEntry) + return E_FAIL; if (!mbc) return E_FAIL; - hr = PeekArray(&mb); + mbc->_SetParentBand(NULL); + + hr = UpdateFocus(); if (FAILED_UNEXPECTEDLY(hr)) return hr; - hr = UpdateFocus(mb); + if (m_current) + { + _ASSERT(m_current->type != TrackedMenuEntry); + m_current->mb->_SetChildBand(NULL); + } + + return S_OK; +} + +HRESULT CMenuFocusManager::PopTrackedPopup(HMENU popup) +{ + StackEntryType type; + HMENU hmenu; + HRESULT hr; + + 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(); if (FAILED_UNEXPECTEDLY(hr)) return hr; diff --git a/base/shell/rshell/CMenuFocusManager.h b/base/shell/rshell/CMenuFocusManager.h index 1815f028f34..9212cbadc94 100644 --- a/base/shell/rshell/CMenuFocusManager.h +++ b/base/shell/rshell/CMenuFocusManager.h @@ -30,6 +30,22 @@ private: static CMenuFocusManager * GetManager(); + enum StackEntryType + { + NoEntry, + MenuBarEntry, + MenuPopupEntry, + TrackedMenuEntry + }; + + struct StackEntry + { + StackEntryType type; + CMenuBand * mb; + HMENU hmenu; + HWND hwnd; + }; + public: static CMenuFocusManager * AcquireManager(); @@ -40,26 +56,29 @@ private: static LRESULT CALLBACK s_GetMsgHook(INT nCode, WPARAM wParam, LPARAM lParam); private: - CMenuBand * m_currentBand; - HWND m_currentFocus; - HMENU m_currentMenu; - HWND m_parentToolbar; + StackEntry * m_current; + StackEntry * m_parent; + HHOOK m_hMsgFilterHook; HHOOK m_hGetMsgHook; DWORD m_threadId; + BOOL m_mouseTrackDisabled; + WPARAM m_lastMoveFlags; LPARAM m_lastMovePos; + POINT m_ptPrev; + HWND m_captureHwnd; + // TODO: make dynamic #define MAX_RECURSE 20 - CMenuBand* m_bandStack[MAX_RECURSE]; + StackEntry m_bandStack[MAX_RECURSE]; int m_bandCount; - HRESULT PushToArray(CMenuBand * item); - HRESULT PopFromArray(CMenuBand ** pItem); - HRESULT PeekArray(CMenuBand ** pItem); + HRESULT PushToArray(StackEntryType type, CMenuBand * mb, HMENU hmenu); + HRESULT PopFromArray(StackEntryType * pType, CMenuBand ** pMb, HMENU * pHmenu); protected: CMenuFocusManager(); @@ -77,15 +96,18 @@ private: LRESULT MsgFilterHook(INT nCode, WPARAM wParam, LPARAM lParam); HRESULT PlaceHooks(); HRESULT RemoveHooks(); - HRESULT UpdateFocus(CMenuBand * newBand, HMENU popupToTrack = NULL); + HRESULT UpdateFocus(); HRESULT IsTrackedWindow(HWND hWnd); - void DisableMouseTrack(HWND enableTo, BOOL disableThis); + void DisableMouseTrack(HWND parent, BOOL disableThis); + void SetCapture(HWND child); LRESULT ProcessMouseMove(MSG* msg); public: - HRESULT PushMenu(CMenuBand * mb); - HRESULT PopMenu(CMenuBand * mb); - HRESULT PushTrackedPopup(CMenuBand * mb, HMENU popup); - HRESULT PopTrackedPopup(CMenuBand * mb, HMENU popup); + HRESULT PushMenuBar(CMenuBand * mb); + HRESULT PushMenuPopup(CMenuBand * mb); + HRESULT PushTrackedPopup(HMENU popup); + HRESULT PopMenuBar(CMenuBand * mb); + HRESULT PopMenuPopup(CMenuBand * mb); + HRESULT PopTrackedPopup(HMENU popup); }; diff --git a/base/shell/rshell/CMenuToolbars.cpp b/base/shell/rshell/CMenuToolbars.cpp index 49ddf49247c..77739a968ac 100644 --- a/base/shell/rshell/CMenuToolbars.cpp +++ b/base/shell/rshell/CMenuToolbars.cpp @@ -121,9 +121,9 @@ HRESULT CMenuToolbarBase::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM default: DbgPrint("WM_NOTIFY unknown code %d, %d\n", hdr->code, hdr->idFrom); - break; + return S_OK; } - return S_OK; + return S_FALSE; } return S_FALSE; @@ -195,7 +195,7 @@ HRESULT CMenuToolbarBase::OnCustomDraw(LPNMTBCUSTOMDRAW cdraw, LRESULT * theResu if (btni.fsStyle & BTNS_DROPDOWN) { SelectObject(cdraw->nmcd.hdc, m_marlett); - WCHAR text[] = L"8"; + WCHAR text [] = L"8"; SetBkMode(cdraw->nmcd.hdc, TRANSPARENT); RECT rc = cdraw->nmcd.rc; rc.right += 1; @@ -210,7 +210,7 @@ HRESULT CMenuToolbarBase::OnCustomDraw(LPNMTBCUSTOMDRAW cdraw, LRESULT * theResu CMenuToolbarBase::CMenuToolbarBase(CMenuBand *menuBand, BOOL usePager) : m_hwnd(NULL), m_useFlatMenus(FALSE), - m_SubclassOld(NULL), + m_SubclassOld(NULL), m_disableMouseTrack(FALSE), m_menuBand(menuBand), m_hwndToolbar(NULL), @@ -235,7 +235,7 @@ CMenuToolbarBase::~CMenuToolbarBase() HRESULT CMenuToolbarBase::IsWindowOwner(HWND hwnd) { return (m_hwnd && m_hwnd == hwnd) || - (m_hwndToolbar && m_hwndToolbar == hwnd) ? S_OK : S_FALSE; + (m_hwndToolbar && m_hwndToolbar == hwnd) ? S_OK : S_FALSE; } void CMenuToolbarBase::InvalidateDraw() @@ -256,7 +256,7 @@ HRESULT CMenuToolbarBase::ShowWindow(BOOL fShow) HRESULT CMenuToolbarBase::UpdateImageLists() { - if ((m_toolbarFlags & (SMINIT_TOPLEVEL| SMINIT_VERTICAL)) == SMINIT_TOPLEVEL) // not vertical. + if ((m_toolbarFlags & (SMINIT_TOPLEVEL | SMINIT_VERTICAL)) == SMINIT_TOPLEVEL) // not vertical. { /* Hide the placeholders for the button images */ SendMessageW(m_hwnd, TB_SETIMAGELIST, 0, 0); @@ -358,7 +358,7 @@ HRESULT CMenuToolbarBase::CreateToolbar(HWND hwndParent, DWORD dwFlags) m_hwndToolbar = hwndToolbar; m_hwnd = hwndToolbar; } - + /* Identify the version of the used Common Controls DLL by sending the size of the TBBUTTON structure */ SendMessageW(hwndToolbar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0); @@ -441,9 +441,13 @@ LRESULT CMenuToolbarBase::SubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPAR { KillTimer(hWnd, TIMERID_HOTTRACK); + DbgPrint("Closing previous submenu...\n"); + m_menuBand->_OnPopupSubMenu(NULL, NULL, NULL, NULL, -1); - PopupItem(m_hotItem); + DbgPrint("Opening new submenu...\n"); + + PopupItem(m_hotItem); } } @@ -474,11 +478,9 @@ HRESULT CMenuToolbarBase::OnHotItemChange(const NMTBHOTITEM * hot, LRESULT * the return S_OK; } - + if (m_hotItem != hot->idNew) { - DbgPrint("Hot item is now %d\n", hot->idNew); - if (hot->dwFlags & HICF_MOUSE && m_toolbarFlags & SMINIT_VERTICAL) { @@ -531,7 +533,7 @@ HRESULT CMenuToolbarBase::OnPopupItemChanged(CMenuToolbarBase * toolbar, INT ite { SendMessage(m_hwndToolbar, TB_CHECKBUTTON, m_popupItem, FALSE); m_isTracking = FALSE; - DbgPrint("Is Tracking: %d\n", m_isTracking); + DbgPrint("%s -- Is Tracking: %d\n", __FUNCTION__, m_isTracking); } m_popupBar = toolbar; m_popupItem = item; @@ -558,13 +560,16 @@ HRESULT CMenuToolbarBase::ChangeTrackedItem(INT index) TBBUTTON btn; SendMessage(m_hwndToolbar, TB_GETBUTTON, index, reinterpret_cast(&btn)); + DbgPrint("Changing tracked item to %d...\n", index); + if (m_hotItem != btn.idCommand) { m_isTracking = TRUE; - DbgPrint("Is Tracking: %d\n", m_isTracking); + DbgPrint("%s -- Is Tracking: %d\n", __FUNCTION__, m_isTracking); SendMessage(m_hwndToolbar, TB_SETHOTITEM, index, 0); } + return S_OK; } @@ -595,7 +600,7 @@ HRESULT CMenuToolbarBase::PopupSubMenu(UINT uItem, UINT index, IShellMenu* child POINTL pt = { a.x, b.y }; RECTL rcl = { c.x, c.y, d.x, d.y }; - if(m_toolbarFlags & SMINIT_VERTICAL) + if (m_toolbarFlags & SMINIT_VERTICAL) { pt.x = b.x - 3; pt.y = a.y - 3; @@ -647,7 +652,7 @@ HRESULT CMenuToolbarBase::PopupSubMenu(UINT uItem, UINT index, IShellMenu* child return hr; m_isTracking = TRUE; - DbgPrint("Is Tracking: %d\n", m_isTracking); + DbgPrint("%s -- Is Tracking: %d\n", __FUNCTION__, m_isTracking); m_menuBand->_OnPopupSubMenu(popup, &pt, &rcl, this, uItem); @@ -686,14 +691,14 @@ HRESULT CMenuToolbarBase::PopupSubMenu(UINT uItem, UINT index, HMENU menu) HMENU popup = GetSubMenu(menu, index); m_isTracking = TRUE; - DbgPrint("Is Tracking: %d\n", m_isTracking); + DbgPrint("%s -- Is Tracking: %d\n", __FUNCTION__, m_isTracking); m_menuBand->_TrackSubMenuUsingTrackPopupMenu(popup, pt.x, pt.y, rcl); SendMessage(m_hwndToolbar, TB_CHECKBUTTON, uItem, FALSE); m_isTracking = FALSE; - DbgPrint("Is Tracking: %d\n", m_isTracking); + DbgPrint("%s -- Is Tracking: %d\n", __FUNCTION__, m_isTracking); return S_OK; } @@ -1095,6 +1100,7 @@ HRESULT CMenuStaticToolbar::InternalHasSubMenu(INT uItem, INT index, DWORD_PTR d return ::GetSubMenu(m_hmenu, index) ? S_OK : S_FALSE; } + CMenuSFToolbar::CMenuSFToolbar(CMenuBand * menuBand) : CMenuToolbarBase(menuBand, TRUE), m_shellFolder(NULL), diff --git a/base/shell/rshell/misc.cpp b/base/shell/rshell/misc.cpp index 8f9e63e382b..33bfac2c447 100644 --- a/base/shell/rshell/misc.cpp +++ b/base/shell/rshell/misc.cpp @@ -50,7 +50,7 @@ STDAPI_(BOOL) DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID fImpLoad) new (&_AtlComModule) CAtlComModule; gModule.Init(NULL, hInstance, NULL); - DisableThreadLibraryCalls (hInstance); + DisableThreadLibraryCalls(hInstance); } else if (dwReason == DLL_PROCESS_DETACH) { diff --git a/base/shell/rshell/precomp.h b/base/shell/rshell/precomp.h index 2f8e877ea9a..06ee9bc4fa2 100644 --- a/base/shell/rshell/precomp.h +++ b/base/shell/rshell/precomp.h @@ -65,14 +65,12 @@ Win32DbgPrint(const char *filename, int line, const char *lpFormat, ...) if (fname == NULL) { fname = strrchr(filename, '/'); - if (fname != NULL) - fname++; } - else - fname++; if (fname == NULL) fname = filename; + else + fname++; szMsgStart = szMsg + sprintf(szMsg, "%s:%d: ", fname, line);