3ab28908b51a041f8b6594d3e3999ca9174172ad
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 #include <CommonControls.h>
23 #include <shlwapi_undoc.h>
25 #include "CMenuFocusManager.h"
26 #include "CMenuBand.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(CMenuFocus
);
30 DWORD
CMenuFocusManager::TlsIndex
= 0;
32 CMenuFocusManager
* CMenuFocusManager::GetManager()
34 return reinterpret_cast<CMenuFocusManager
*>(TlsGetValue(TlsIndex
));
37 CMenuFocusManager
* CMenuFocusManager::AcquireManager()
39 CMenuFocusManager
* obj
= NULL
;
43 if ((TlsIndex
= TlsAlloc()) == TLS_OUT_OF_INDEXES
)
51 obj
= new CComObject
<CMenuFocusManager
>();
52 TlsSetValue(TlsIndex
, obj
);
60 void CMenuFocusManager::ReleaseManager(CMenuFocusManager
* obj
)
64 TlsSetValue(TlsIndex
, NULL
);
68 LRESULT CALLBACK
CMenuFocusManager::s_GetMsgHook(INT nCode
, WPARAM wParam
, LPARAM lParam
)
70 return GetManager()->GetMsgHook(nCode
, wParam
, lParam
);
73 HRESULT
CMenuFocusManager::PushToArray(CMenuBand
* item
)
75 if (m_bandCount
>= MAX_RECURSE
)
78 m_bandStack
[m_bandCount
++] = item
;
82 HRESULT
CMenuFocusManager::PopFromArray(CMenuBand
** pItem
)
93 *pItem
= m_bandStack
[m_bandCount
];
95 m_bandStack
[m_bandCount
] = NULL
;
100 HRESULT
CMenuFocusManager::PeekArray(CMenuBand
** pItem
)
107 if (m_bandCount
<= 0)
110 *pItem
= m_bandStack
[m_bandCount
- 1];
115 CMenuFocusManager::CMenuFocusManager() :
117 m_currentFocus(NULL
),
118 m_mouseTrackDisabled(FALSE
),
123 m_threadId
= GetCurrentThreadId();
126 CMenuFocusManager::~CMenuFocusManager()
130 void CMenuFocusManager::DisableMouseTrack(HWND enableTo
, BOOL disableThis
)
132 BOOL bDisable
= FALSE
;
137 CMenuBand
* band
= m_bandStack
[i
];
140 HRESULT hr
= band
->_GetTopLevelWindow(&hwnd
);
141 if (FAILED_UNEXPECTEDLY(hr
))
144 if (hwnd
== enableTo
)
146 band
->_DisableMouseTrack(disableThis
);
151 band
->_DisableMouseTrack(bDisable
);
155 if (m_mouseTrackDisabled
== bDisable
)
159 SetCapture(m_currentFocus
);
164 m_mouseTrackDisabled
= bDisable
;
168 HRESULT
CMenuFocusManager::IsTrackedWindow(HWND hWnd
)
170 if (hWnd
== m_currentFocus
)
173 int i
= m_bandCount
- 1;
176 CMenuBand
* band
= m_bandStack
[i
];
179 HRESULT hr
= band
->_GetTopLevelWindow(&hwnd
);
180 if (FAILED_UNEXPECTEDLY(hr
))
190 LRESULT
CMenuFocusManager::GetMsgHook(INT nCode
, WPARAM wParam
, LPARAM lParam
)
193 return CallNextHookEx(m_hHook
, nCode
, wParam
, lParam
);
195 LPARAM pos
= (LPARAM
) GetMessagePos();
197 if (nCode
== HC_ACTION
)
199 BOOL callNext
= TRUE
;
200 MSG
* msg
= reinterpret_cast<MSG
*>(lParam
);
202 // Do whatever is necessary here
204 switch (msg
->message
)
206 case WM_ACTIVATE
: // does not trigger
207 ActivationChange(msg
->hwnd
);
212 POINT pt
= { GET_X_LPARAM(pos
), GET_Y_LPARAM(pos
) };
214 HWND window
= WindowFromPoint(pt
);
216 if (IsTrackedWindow(window
) != S_OK
)
218 DisableMouseTrack(NULL
, FALSE
);
219 m_currentBand
->_MenuItemHotTrack(MPOS_FULLCANCEL
);
225 if (m_lastMoveFlags
!= wParam
|| m_lastMovePos
!= pos
)
227 m_lastMoveFlags
= wParam
;
230 POINT pt
= { GET_X_LPARAM(pos
), GET_Y_LPARAM(pos
) };
232 HWND window
= WindowFromPoint(pt
);
234 if (IsTrackedWindow(window
) == S_OK
)
236 DisableMouseTrack(window
, FALSE
);
240 DisableMouseTrack(NULL
, FALSE
);
246 //if (!m_currentMenu)
248 DisableMouseTrack(m_currentFocus
, TRUE
);
254 m_currentBand
->_MenuItemHotTrack(MPOS_FULLCANCEL
);
257 m_currentBand
->_MenuItemHotTrack(MPOS_SELECTLEFT
);
260 m_currentBand
->_MenuItemHotTrack(MPOS_SELECTRIGHT
);
263 m_currentBand
->_MenuItemHotTrack(VK_UP
);
266 m_currentBand
->_MenuItemHotTrack(VK_DOWN
);
277 return CallNextHookEx(m_hHook
, nCode
, wParam
, lParam
);
280 HRESULT
CMenuFocusManager::PlaceHooks(HWND window
)
282 //SetCapture(window);
283 m_hHook
= SetWindowsHookEx(WH_GETMESSAGE
, s_GetMsgHook
, NULL
, m_threadId
);
287 HRESULT
CMenuFocusManager::RemoveHooks(HWND window
)
289 UnhookWindowsHookEx(m_hHook
);
294 HRESULT
CMenuFocusManager::ActivationChange(HWND newHwnd
)
297 CMenuBand
* newBand
= NULL
;
302 while (m_bandCount
>= 0)
305 hr
= band
->_GetTopLevelWindow(&hwnd
);
306 if (FAILED_UNEXPECTEDLY(hr
))
321 return UpdateFocus(newBand
);
324 HRESULT
CMenuFocusManager::UpdateFocus(CMenuBand
* newBand
, HMENU popupToTrack
)
331 DisableMouseTrack(NULL
, FALSE
);
333 hr
= RemoveHooks(m_currentFocus
);
334 m_currentFocus
= NULL
;
335 m_currentBand
= NULL
;
336 m_currentMenu
= NULL
;
340 hr
= newBand
->_GetTopLevelWindow(&newFocus
);
341 if (FAILED_UNEXPECTEDLY(hr
))
346 hr
= PlaceHooks(newFocus
);
347 if (FAILED_UNEXPECTEDLY(hr
))
352 GetWindowTextA(newFocus
, title
, 1024);
354 DbgPrint("Focus is now at %08p, hwnd=%08x, title='%s'. m_bandCount=%d\n", newBand
, newFocus
, title
, m_bandCount
);
356 m_currentFocus
= newFocus
;
357 m_currentBand
= newBand
;
358 m_currentMenu
= popupToTrack
;
363 HRESULT
CMenuFocusManager::PushMenu(CMenuBand
* mb
)
367 hr
= PushToArray(mb
);
368 if (FAILED_UNEXPECTEDLY(hr
))
371 return UpdateFocus(mb
);
374 HRESULT
CMenuFocusManager::PopMenu(CMenuBand
* mb
)
380 hr
= mb
->_GetTopLevelWindow(&newFocus
);
381 if (FAILED_UNEXPECTEDLY(hr
))
384 DbgPrint("Trying to pop %08p, hwnd=%08x\n", mb
, newFocus
);
387 hr
= PopFromArray(&mbc
);
388 if (FAILED_UNEXPECTEDLY(hr
))
394 while (mbc
&& mb
!= mbc
);
397 if (FAILED_UNEXPECTEDLY(hr
))
400 hr
= UpdateFocus(mb
);
401 if (FAILED_UNEXPECTEDLY(hr
))
410 HRESULT
CMenuFocusManager::PushTrackedPopup(CMenuBand
* mb
, HMENU popup
)
414 hr
= PushToArray(mb
);
415 if (FAILED_UNEXPECTEDLY(hr
))
418 return UpdateFocus(mb
, popup
);
421 HRESULT
CMenuFocusManager::PopTrackedPopup(CMenuBand
* mb
, HMENU popup
)