[EXPLORER]: Simplify the creation of the tray band site and the tasks band.
[reactos.git] / reactos / base / shell / explorer / taskband.cpp
1 /*
2 * ReactOS Explorer
3 *
4 * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include "precomp.h"
22
23 /*****************************************************************************
24 ** CTaskBand ****************************************************************
25 *****************************************************************************/
26
27 const GUID CLSID_ITaskBand = { 0x68284FAA, 0x6A48, 0x11D0, { 0x8C, 0x78, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xB4 } };
28
29 class CTaskBand :
30 public CComCoClass<CTaskBand>,
31 public CComObjectRootEx<CComMultiThreadModelNoCS>,
32 public IObjectWithSite,
33 public IDeskBand,
34 public IDeskBar,
35 public IPersistStream,
36 public IWinEventHandler,
37 public IOleCommandTarget
38 {
39 CComPtr<ITrayWindow> m_Tray;
40 CComPtr<IUnknown> m_Site;
41
42 HWND m_hWnd;
43 DWORD m_BandID;
44
45 public:
46 CTaskBand() :
47 m_hWnd(NULL),
48 m_BandID(0)
49 {
50
51 }
52
53 virtual ~CTaskBand() { }
54
55 /*****************************************************************************/
56
57 virtual HRESULT STDMETHODCALLTYPE GetWindow(OUT HWND *phwnd)
58 {
59 if (!m_hWnd)
60 return E_FAIL;
61 if (!phwnd)
62 return E_INVALIDARG;
63 *phwnd = m_hWnd;
64 return S_OK;
65 }
66
67 virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(
68 IN BOOL fEnterMode)
69 {
70 /* FIXME: Implement */
71 return E_NOTIMPL;
72 }
73
74 virtual HRESULT STDMETHODCALLTYPE ShowDW(
75 IN BOOL bShow)
76 {
77 /* We don't do anything... */
78 return S_OK;
79 }
80
81 virtual HRESULT STDMETHODCALLTYPE CloseDW(
82 IN DWORD dwReserved)
83 {
84 /* We don't do anything... */
85 return S_OK;
86 }
87
88 virtual HRESULT STDMETHODCALLTYPE ResizeBorderDW(
89 LPCRECT prcBorder,
90 IUnknown *punkToolbarSite,
91 BOOL fReserved)
92 {
93 /* No need to implement this method */
94 return E_NOTIMPL;
95 }
96
97 virtual HRESULT STDMETHODCALLTYPE GetBandInfo(
98 IN DWORD dwBandID,
99 IN DWORD dwViewMode,
100 IN OUT DESKBANDINFO *pdbi)
101 {
102 TRACE("CTaskBand::GetBandInfo(0x%x,0x%x,0x%p) hWnd=0x%p\n", dwBandID, dwViewMode, pdbi, m_hWnd);
103
104 if (m_hWnd != NULL)
105 {
106 /* The task band never has a title */
107 pdbi->dwMask &= ~DBIM_TITLE;
108
109 /* NOTE: We don't return DBIMF_UNDELETEABLE here, the band site will
110 handle us differently and add this flag for us. The reason for
111 this is future changes that might allow it to be deletable.
112 We want the band site to be in charge of this decision rather
113 the band itself! */
114 /* FIXME: What about DBIMF_NOGRIPPER and DBIMF_ALWAYSGRIPPER */
115 pdbi->dwModeFlags = DBIMF_VARIABLEHEIGHT;
116
117 if (dwViewMode & DBIF_VIEWMODE_VERTICAL)
118 {
119 pdbi->ptIntegral.y = 1;
120 pdbi->ptMinSize.y = 1;
121 /* FIXME: Get the button metrics from the task bar object!!! */
122 pdbi->ptMinSize.x = (3 * GetSystemMetrics(SM_CXEDGE) / 2) + /* FIXME: Might be wrong if only one column! */
123 GetSystemMetrics(SM_CXSIZE) + (2 * GetSystemMetrics(SM_CXEDGE)); /* FIXME: Min button size, query!!! */
124 }
125 else
126 {
127 pdbi->ptMinSize.y = GetSystemMetrics(SM_CYSIZE) + (2 * GetSystemMetrics(SM_CYEDGE)); /* FIXME: Query */
128 pdbi->ptIntegral.y = pdbi->ptMinSize.y + (3 * GetSystemMetrics(SM_CYEDGE) / 2); /* FIXME: Query metrics */
129 /* We're not going to allow task bands where not even the minimum button size fits into the band */
130 pdbi->ptMinSize.x = pdbi->ptIntegral.y;
131 }
132
133 /* Ignored: pdbi->ptMaxSize.x */
134 pdbi->ptMaxSize.y = -1;
135
136 /* FIXME: We should query the height from the task bar object!!! */
137 pdbi->ptActual.y = GetSystemMetrics(SM_CYSIZE) + (2 * GetSystemMetrics(SM_CYEDGE));
138
139 /* Save the band ID for future use in case we need to check whether a given band
140 is the task band */
141 m_BandID = dwBandID;
142
143 TRACE("H: %d, Min: %d,%d, Integral.y: %d Actual: %d,%d\n", (dwViewMode & DBIF_VIEWMODE_VERTICAL) == 0,
144 pdbi->ptMinSize.x, pdbi->ptMinSize.y, pdbi->ptIntegral.y,
145 pdbi->ptActual.x, pdbi->ptActual.y);
146
147 return S_OK;
148 }
149
150 return E_FAIL;
151 }
152
153 /*****************************************************************************/
154 // *** IOleCommandTarget methods ***
155 virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText)
156 {
157 UNIMPLEMENTED;
158 return E_NOTIMPL;
159 }
160
161 virtual HRESULT STDMETHODCALLTYPE Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
162 {
163 if (IsEqualIID(*pguidCmdGroup, IID_IBandSite))
164 {
165 return S_OK;
166 }
167
168 if (IsEqualIID(*pguidCmdGroup, IID_IDeskBand))
169 {
170 return S_OK;
171 }
172
173 UNIMPLEMENTED;
174 return E_NOTIMPL;
175 }
176
177 /*****************************************************************************/
178
179 virtual HRESULT STDMETHODCALLTYPE SetClient(
180 IN IUnknown *punkClient)
181 {
182 TRACE("IDeskBar::SetClient(0x%p)\n", punkClient);
183 return E_NOTIMPL;
184 }
185
186 virtual HRESULT STDMETHODCALLTYPE GetClient(
187 OUT IUnknown **ppunkClient)
188 {
189 TRACE("IDeskBar::GetClient(0x%p)\n", ppunkClient);
190 return E_NOTIMPL;
191 }
192
193 virtual HRESULT STDMETHODCALLTYPE OnPosRectChangeDB(
194 IN RECT *prc)
195 {
196 TRACE("IDeskBar::OnPosRectChangeDB(0x%p=(%d,%d,%d,%d))\n", prc, prc->left, prc->top, prc->right, prc->bottom);
197 if (prc->bottom - prc->top == 0)
198 return S_OK;
199
200 return S_FALSE;
201 }
202
203 /*****************************************************************************/
204
205 virtual HRESULT STDMETHODCALLTYPE GetClassID(
206 OUT CLSID *pClassID)
207 {
208 TRACE("CTaskBand::GetClassID(0x%p)\n", pClassID);
209 /* We're going to return the (internal!) CLSID of the task band interface */
210 *pClassID = CLSID_ITaskBand;
211 return S_OK;
212 }
213
214 virtual HRESULT STDMETHODCALLTYPE IsDirty()
215 {
216 /* The object hasn't changed since the last save! */
217 return S_FALSE;
218 }
219
220 virtual HRESULT STDMETHODCALLTYPE Load(
221 IN IStream *pStm)
222 {
223 TRACE("CTaskBand::Load called\n");
224 /* Nothing to do */
225 return S_OK;
226 }
227
228 virtual HRESULT STDMETHODCALLTYPE Save(
229 IN IStream *pStm,
230 IN BOOL fClearDirty)
231 {
232 /* Nothing to do */
233 return S_OK;
234 }
235
236 virtual HRESULT STDMETHODCALLTYPE GetSizeMax(
237 OUT ULARGE_INTEGER *pcbSize)
238 {
239 TRACE("CTaskBand::GetSizeMax called\n");
240 /* We don't need any space for the task band */
241 pcbSize->QuadPart = 0;
242 return S_OK;
243 }
244
245 /*****************************************************************************/
246
247 virtual HRESULT STDMETHODCALLTYPE SetSite(IUnknown *pUnkSite)
248 {
249 HRESULT hRet;
250 HWND hwndSite;
251
252 TRACE("CTaskBand::SetSite(0x%p)\n", pUnkSite);
253
254 hRet = IUnknown_GetWindow(pUnkSite, &hwndSite);
255 if (FAILED(hRet))
256 {
257 TRACE("Querying site window failed: 0x%x\n", hRet);
258 return hRet;
259 }
260
261 TRACE("CreateTaskSwitchWnd(Parent: 0x%p)\n", hwndSite);
262
263 HWND hwndTaskSwitch = CreateTaskSwitchWnd(hwndSite, m_Tray);
264 if (!hwndTaskSwitch)
265 {
266 ERR("CreateTaskSwitchWnd failed");
267 return E_FAIL;
268 }
269
270 m_Site = pUnkSite;
271 m_hWnd = hwndTaskSwitch;
272
273 return S_OK;
274 }
275
276 virtual HRESULT STDMETHODCALLTYPE GetSite(
277 IN REFIID riid,
278 OUT VOID **ppvSite)
279 {
280 TRACE("CTaskBand::GetSite(0x%p,0x%p)\n", riid, ppvSite);
281
282 if (m_Site != NULL)
283 {
284 return m_Site->QueryInterface(riid, ppvSite);
285 }
286
287 *ppvSite = NULL;
288 return E_FAIL;
289 }
290
291 /*****************************************************************************/
292
293 virtual HRESULT STDMETHODCALLTYPE ProcessMessage(
294 IN HWND hWnd,
295 IN UINT uMsg,
296 IN WPARAM wParam,
297 IN LPARAM lParam,
298 OUT LRESULT *plrResult)
299 {
300 TRACE("CTaskBand: IWinEventHandler::ProcessMessage(0x%p, 0x%x, 0x%p, 0x%p, 0x%p)\n", hWnd, uMsg, wParam, lParam, plrResult);
301 return E_NOTIMPL;
302 }
303
304 virtual HRESULT STDMETHODCALLTYPE ContainsWindow(
305 IN HWND hWnd)
306 {
307 if (hWnd == m_hWnd ||
308 IsChild(m_hWnd, hWnd))
309 {
310 TRACE("CTaskBand::ContainsWindow(0x%p) returns S_OK\n", hWnd);
311 return S_OK;
312 }
313
314 return S_FALSE;
315 }
316
317 virtual HRESULT STDMETHODCALLTYPE OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
318 {
319 UNIMPLEMENTED;
320 return E_NOTIMPL;
321 }
322
323 virtual HRESULT STDMETHODCALLTYPE IsWindowOwner(HWND hWnd)
324 {
325 return (hWnd == m_hWnd) ? S_OK : S_FALSE;
326 }
327
328 /*****************************************************************************/
329
330 HRESULT STDMETHODCALLTYPE Initialize(IN OUT ITrayWindow *tray)
331 {
332 m_Tray = tray;
333 m_BandID = (DWORD) -1;
334 return S_OK;
335 }
336
337 DECLARE_NOT_AGGREGATABLE(CTaskBand)
338
339 DECLARE_PROTECT_FINAL_CONSTRUCT()
340 BEGIN_COM_MAP(CTaskBand)
341 COM_INTERFACE_ENTRY2_IID(IID_IOleWindow, IOleWindow, IDeskBand)
342 COM_INTERFACE_ENTRY_IID(IID_IDeskBand, IDeskBand)
343 COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite)
344 COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist)
345 COM_INTERFACE_ENTRY_IID(IID_IPersistStream, IPersistStream)
346 COM_INTERFACE_ENTRY_IID(IID_IWinEventHandler, IWinEventHandler)
347 COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget)
348 END_COM_MAP()
349 };
350
351 HRESULT CTaskBand_CreateInstance(IN ITrayWindow *Tray, REFIID riid, void **ppv)
352 {
353 return ShellObjectCreatorInit<CTaskBand>(Tray, riid, ppv);
354 }