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_movedSinceDown;
81     HWND m_windowAtDown;
82 
83     HWND m_PreviousForeground;
84 
85     // TODO: make dynamic
86 #define MAX_RECURSE 20
87     StackEntry m_bandStack[MAX_RECURSE];
88     int m_bandCount;
89     int m_menuDepth;
90 
91     HRESULT PushToArray(StackEntryType type, CMenuBand * mb, HMENU hmenu);
92     HRESULT PopFromArray(StackEntryType * pType, CMenuBand ** pMb, HMENU * pHmenu);
93 
94 protected:
95     CMenuFocusManager();
96     ~CMenuFocusManager();
97 
98 public:
99 
100     DECLARE_NOT_AGGREGATABLE(CMenuFocusManager)
101     DECLARE_PROTECT_FINAL_CONSTRUCT()
102     BEGIN_COM_MAP(CMenuFocusManager)
103     END_COM_MAP()
104 
105 private:
106     LRESULT GetMsgHook(INT nCode, WPARAM wParam, LPARAM lParam);
107     LRESULT MsgFilterHook(INT nCode, WPARAM wParam, LPARAM lParam);
108     HRESULT PlaceHooks();
109     HRESULT RemoveHooks();
110     HRESULT UpdateFocus();
111     HRESULT IsTrackedWindow(HWND hWnd, StackEntry ** pentry = NULL);
112     HRESULT IsTrackedWindowOrParent(HWND hWnd);
113 
114     void DisableMouseTrack(HWND parent, BOOL disableThis);
115     void SetMenuCapture(HWND child);
116 
117     LRESULT ProcessMouseMove(MSG* msg);
118     LRESULT ProcessMouseDown(MSG* msg, BOOL isLButton);
119     LRESULT ProcessMouseUp(MSG* msg, BOOL isLButton);
120 public:
121     HRESULT PushMenuBar(CMenuBand * mb);
122     HRESULT PushMenuPopup(CMenuBand * mb);
123     HRESULT PushTrackedPopup(HMENU popup);
124     HRESULT PopMenuBar(CMenuBand * mb);
125     HRESULT PopMenuPopup(CMenuBand * mb);
126     HRESULT PopTrackedPopup(HMENU popup);
127 };
128