#include "CMenuToolbars.h"
#include "CMenuBand.h"
-#undef _ASSERT
-#define _ASSERT(x) DbgAssert(!!(x), __FILE__, __LINE__, #x)
+#if DBG
+# undef _ASSERT
+# define _ASSERT(x) DbgAssert(!!(x), __FILE__, __LINE__, #x)
bool DbgAssert(bool x, const char * filename, int line, const char * expr)
{
}
return x;
}
+#else
+# undef _ASSERT
+# define _ASSERT(x) (!!(x))
+#endif
WINE_DEFAULT_DEBUG_CHANNEL(CMenuFocus);
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;
entry.mb->_DisableMouseTrack(bDisable);
}
}
- //else
- //{
- // continue;
- //}
}
m_mouseTrackDisabled = lastDisable;
}
{
::SetCapture(child);
m_captureHwnd = child;
- DbgPrint("MouseTrack is now capturing %p\n", child);
+ TRACE("MouseTrack is now capturing %p\n", child);
}
else
{
::ReleaseCapture();
m_captureHwnd = NULL;
- DbgPrint("MouseTrack is now off\n");
+ TRACE("MouseTrack is now off\n");
}
}
return S_FALSE;
}
+HRESULT CMenuFocusManager::IsTrackedWindowOrParent(HWND hWnd)
+{
+ for (int i = m_bandCount; --i >= 0;)
+ {
+ StackEntry& entry = m_bandStack[i];
+
+ if (entry.type != TrackedMenuEntry)
+ {
+ 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;
+ }
+ }
+ }
+
+ return S_FALSE;
+}
+
LRESULT CMenuFocusManager::ProcessMouseMove(MSG* msg)
{
HWND child;
- int iHitTestResult;
+ int iHitTestResult = -1;
POINT pt2 = { GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam) };
ClientToScreen(msg->hwnd, &pt2);
if (cCapture && cCapture != m_captureHwnd && m_current->type != TrackedMenuEntry)
return TRUE;
+
+ m_movedSinceDown = TRUE;
+
m_ptPrev = pt;
child = WindowFromPoint(pt);
StackEntry * entry = NULL;
- IsTrackedWindow(child, &entry);
-
- if (m_hwndUnderMouse != child)
+ if (IsTrackedWindow(child, &entry) == S_OK)
{
- WCHAR cn[1024];
- GetClassName(child, cn, 1023);
- DbgPrint("Mouse moved to %p (%S)\n", child, cn);
-
- if (!entry)
- {
- if (m_entryUnderMouse)
- {
- m_entryUnderMouse->mb->_ChangeHotItem(NULL, -1, HICF_MOUSE);
- }
- if (cCapture == m_captureHwnd)
- SetCapture(NULL);
- }
-
+ TRACE("MouseMove %d\n", m_isLButtonDown);
}
- if (entry)
+ 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();
- BOOL isTracking = entry->mb->_IsTracking();
-
- if (iHitTestResult >= 0 &&
- SendMessage(child, WM_USER_ISTRACKEDITEM, iHitTestResult, 0) == S_FALSE)
+ if (SendMessage(child, WM_USER_ISTRACKEDITEM, iHitTestResult, 0) == S_FALSE)
{
- DbgPrint("Hot item tracking detected a change (capture=%p)...\n", m_captureHwnd);
+ TRACE("Hot item tracking detected a change (capture=%p / cCapture=%p)...\n", m_captureHwnd, cCapture);
DisableMouseTrack(NULL, FALSE);
- if (m_current->type == TrackedMenuEntry)
+ if (isTracking && iHitTestResult >= 0 && m_current->type == TrackedMenuEntry)
SendMessage(entry->hwnd, WM_CANCELMODE, 0, 0);
- PostMessage(child, WM_USER_CHANGETRACKEDITEM, iHitTestResult, isTracking);
+ 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)
{
- //SetCapture(child);
-
ScreenToClient(child, &pt2);
SendMessage(child, WM_MOUSEMOVE, msg->wParam, MAKELPARAM(pt2.x, pt2.y));
}
return TRUE;
}
-LRESULT CMenuFocusManager::MsgFilterHook(INT nCode, WPARAM wParam, LPARAM lParam)
+LRESULT CMenuFocusManager::ProcessMouseDown(MSG* msg)
+{
+ HWND child;
+ int iHitTestResult = -1;
+
+ 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;
+
+
+ POINT pt = msg->pt;
+
+ child = WindowFromPoint(pt);
+
+ StackEntry * entry = NULL;
+ if (IsTrackedWindow(child, &entry) != S_OK)
+ return TRUE;
+
+ 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 another window is capturing the mouse.
+ HWND cCapture = ::GetCapture();
+ if (cCapture && cCapture != m_captureHwnd && m_current->type != TrackedMenuEntry)
+ return TRUE;
+
+ if (!m_isLButtonDown)
+ return TRUE;
+
+ m_isLButtonDown = FALSE;
+
+ POINT pt = msg->pt;
+
+ child = WindowFromPoint(pt);
+
+ StackEntry * entry = NULL;
+ if (IsTrackedWindow(child, &entry) != S_OK)
+ return TRUE;
+
+ TRACE("MouseUp %d\n", m_isLButtonDown);
+
+ if (entry)
+ {
+ ScreenToClient(child, &pt);
+ iHitTestResult = SendMessageW(child, TB_HITTEST, 0, (LPARAM) &pt);
+
+ if (iHitTestResult >= 0)
+ {
+ TRACE("MouseUp send %d\n", iHitTestResult);
+ entry->mb->_MenuBarMouseUp(child, iHitTestResult);
+ }
+ }
+
+ return TRUE;
+}
+
+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);
+ 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;
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 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);
+ return CallNextHookEx(m_hGetMsgHook, nCode, hookWParam, hookLParam);
if (nCode == HC_ACTION)
{
BOOL callNext = TRUE;
- MSG* msg = reinterpret_cast<MSG*>(lParam);
+ MSG* msg = reinterpret_cast<MSG*>(hookLParam);
POINT pt = msg->pt;
switch (msg->message)
{
case WM_NCLBUTTONDOWN:
case WM_LBUTTONDOWN:
+ isLButton = TRUE;
+
+ // fallthrough;
+ case WM_NCRBUTTONDOWN:
+ case WM_RBUTTONDOWN:
if (m_current->type == MenuPopupEntry)
{
HWND child = WindowFromPoint(pt);
- if (IsTrackedWindow(child) != S_OK)
+ if (IsTrackedWindowOrParent(child) != S_OK)
{
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);
case VK_RMENU:
m_current->mb->_MenuItemHotTrack(MPOS_FULLCANCEL);
break;
+ case VK_RETURN:
+ m_current->mb->_MenuItemHotTrack(MPOS_EXECUTE);
+ break;
case VK_LEFT:
m_current->mb->_MenuItemHotTrack(VK_LEFT);
break;
m_current->mb->_MenuItemHotTrack(VK_DOWN);
break;
}
+ msg->message = WM_NULL;
+ msg->lParam = 0;
+ msg->wParam = 0;
}
break;
}
return 1;
}
- return CallNextHookEx(m_hGetMsgHook, nCode, wParam, lParam);
+ return CallNextHookEx(m_hGetMsgHook, nCode, hookWParam, hookLParam);
}
HRESULT CMenuFocusManager::PlaceHooks()
{
+ 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)
HRESULT hr;
StackEntry * old = m_current;
+ TRACE("UpdateFocus\n");
+
if (old)
SetCapture(NULL);
// When the mouse moves, it should set itself to the proper band
SetCapture(m_current->hwnd);
- //// FIXME: Debugging code, probably not right
- //POINT pt2;
- //GetCursorPos(&pt2);
- //ScreenToClient(m_current->hwnd, &pt2);
- //SendMessage(m_current->hwnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt2.x, pt2.y));
+ 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);
HRESULT CMenuFocusManager::PushMenuBar(CMenuBand * mb)
{
+ DbgPrint("PushMenuBar %p\n", mb);
+
+ mb->AddRef();
+
_ASSERT(m_bandCount == 0);
HRESULT hr = PushToArray(MenuBarEntry, mb, NULL);
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);
HRESULT CMenuFocusManager::PushTrackedPopup(HMENU popup)
{
+ DbgPrint("PushTrackedPopup %p\n", popup);
+
_ASSERT(m_bandCount > 0);
_ASSERT(!m_current || m_current->type != TrackedMenuEntry);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
+ DbgPrint("PushTrackedPopup %p\n", popup);
+ m_selectedMenu = popup;
+ m_selectedItem = -1;
+ m_selectedItemFlags = 0;
+
return UpdateFocus();
}
CMenuBand * mbc;
HRESULT hr;
+ DbgPrint("PopMenuBar %p\n", mb);
+
+ if (m_current == m_entryUnderMouse)
+ {
+ m_entryUnderMouse = NULL;
+ }
+
hr = PopFromArray(&type, &mbc, NULL);
if (FAILED_UNEXPECTEDLY(hr))
{
mbc->_SetParentBand(NULL);
+ mbc->Release();
+
hr = UpdateFocus();
if (FAILED_UNEXPECTEDLY(hr))
return hr;
CMenuBand * mbc;
HRESULT hr;
+ DbgPrint("PopMenuPopup %p\n", mb);
+
+ if (m_current == m_entryUnderMouse)
+ {
+ m_entryUnderMouse = NULL;
+ }
+
hr = PopFromArray(&type, &mbc, NULL);
if (FAILED_UNEXPECTEDLY(hr))
{
mbc->_SetParentBand(NULL);
+ mbc->Release();
+
hr = UpdateFocus();
if (FAILED_UNEXPECTEDLY(hr))
return hr;
HMENU hmenu;
HRESULT hr;
+ DbgPrint("PopTrackedPopup %p\n", popup);
+
hr = PopFromArray(&type, NULL, &hmenu);
if (FAILED_UNEXPECTEDLY(hr))
{