1 /*
2 * Shell Menu Band
3 *
4 * Copyright 2014 David Quintana
5 *
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.
10 *
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.
15 *
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
19 */
20 #pragma once
21 
22 class CMenuBand;
23 
24 class CMenuFocusManager :
25     public CComCoClass<CMenuFocusManager>,
26     public CComObjectRootEx<CComMultiThreadModelNoCS>
27 {
28 private:
29     static DWORD TlsIndex;
30 
31     static CMenuFocusManager * GetManager();
32 
33     enum StackEntryType
34     {
35         NoEntry,
36         MenuBarEntry,
37         MenuPopupEntry,
38         TrackedMenuEntry
39     };
40 
41     struct StackEntry
42     {
43         StackEntryType type;
44         CMenuBand *    mb;
45         HMENU          hmenu;
46         HWND           hwnd;
47     };
48 
49 public:
50     static CMenuFocusManager * AcquireManager();
51 
52     static void ReleaseManager(CMenuFocusManager * obj);
53 
54 private:
55     static LRESULT CALLBACK s_MsgFilterHook(INT nCode, WPARAM wParam, LPARAM lParam);
56     static LRESULT CALLBACK s_GetMsgHook(INT nCode, WPARAM wParam, LPARAM lParam);
57 
58 private:
59     StackEntry * m_current;
60     StackEntry * m_parent;
61     StackEntry * m_menuBar;
62 
63     HHOOK m_hMsgFilterHook;
64     HHOOK m_hGetMsgHook;
65     DWORD m_threadId;
66 
67     BOOL m_mouseTrackDisabled;
68 
69     POINT m_ptPrev;
70 
71     HWND m_captureHwnd;
72 
73     HWND m_hwndUnderMouse;
74     StackEntry * m_entryUnderMouse;
75 
76     HMENU m_selectedMenu;
77     INT   m_selectedItem;
78     DWORD m_selectedItemFlags;
79 
80     BOOL m_isLButtonDown;
81     BOOL m_movedSinceDown;
82     HWND m_windowAtDown;
83 
84     HWND m_PreviousForeground;
85 
86     // TODO: make dynamic
87 #define MAX_RECURSE 20
88     StackEntry m_bandStack[MAX_RECURSE];
89     int m_bandCount;
90     int m_menuDepth;
91 
92     HRESULT PushToArray(StackEntryType type, CMenuBand * mb, HMENU hmenu);
93     HRESULT PopFromArray(StackEntryType * pType, CMenuBand ** pMb, HMENU * pHmenu);
94 
95 protected:
96     CMenuFocusManager();
97     ~CMenuFocusManager();
98 
99 public:
100 
101     DECLARE_NOT_AGGREGATABLE(CMenuFocusManager)
102     DECLARE_PROTECT_FINAL_CONSTRUCT()
103     BEGIN_COM_MAP(CMenuFocusManager)
104     END_COM_MAP()
105 
106 private:
107     LRESULT GetMsgHook(INT nCode, WPARAM wParam, LPARAM lParam);
108     LRESULT MsgFilterHook(INT nCode, WPARAM wParam, LPARAM lParam);
109     HRESULT PlaceHooks();
110     HRESULT RemoveHooks();
111     HRESULT UpdateFocus();
112     HRESULT IsTrackedWindow(HWND hWnd, StackEntry ** pentry = NULL);
113     HRESULT IsTrackedWindowOrParent(HWND hWnd);
114 
115     void DisableMouseTrack(HWND parent, BOOL disableThis);
116     void SetMenuCapture(HWND child);
117 
118     LRESULT ProcessMouseMove(MSG* msg);
119     LRESULT ProcessMouseDown(MSG* msg, BOOL isLButton);
120     LRESULT ProcessMouseUp(MSG* msg, BOOL isLButton);
121 public:
122     HRESULT PushMenuBar(CMenuBand * mb);
123     HRESULT PushMenuPopup(CMenuBand * mb);
124     HRESULT PushTrackedPopup(HMENU popup);
125     HRESULT PopMenuBar(CMenuBand * mb);
126     HRESULT PopMenuPopup(CMenuBand * mb);
127     HRESULT PopTrackedPopup(HMENU popup);
128 };
129