Sync to trunk r65566.
[reactos.git] / 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 ** ITaskBand ****************************************************************
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 ITaskBand,
34 public IDeskBand,
35 public IDeskBar,
36 public IPersistStream,
37 public IWinEventHandler,
38 public IOleCommandTarget
39 {
40 CComPtr<ITrayWindow> Tray;
41 CComPtr<IUnknown> punkSite;
42
43 HWND hWnd;
44 DWORD dwBandID;
45
46 public:
47 CTaskBand() :
48 hWnd(NULL),
49 dwBandID(0)
50 {
51
52 }
53
54 virtual ~CTaskBand() { }
55
56 virtual HRESULT STDMETHODCALLTYPE GetRebarBandID(
57 OUT DWORD *pdwBandID)
58 {
59 if (dwBandID != (DWORD) -1)
60 {
61 if (pdwBandID != NULL)
62 *pdwBandID = dwBandID;
63
64 return S_OK;
65 }
66
67 return E_FAIL;
68 }
69
70 /*****************************************************************************/
71
72 virtual HRESULT STDMETHODCALLTYPE GetWindow(
73 OUT HWND *phwnd)
74 {
75
76 /* NOTE: We have to return the tray window here so that ITaskBarClient
77 knows the parent window of the Rebar control it creates when
78 calling ITaskBarClient::SetDeskBarSite()! However, once we
79 created a window we return the task switch window! */
80 if (hWnd != NULL)
81 *phwnd = hWnd;
82 else
83 *phwnd = Tray->GetHWND();
84
85 TRACE("ITaskBand::GetWindow(0x%p->0x%p)\n", phwnd, *phwnd);
86
87 if (*phwnd != NULL)
88 return S_OK;
89
90 return E_FAIL;
91 }
92
93 virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(
94 IN BOOL fEnterMode)
95 {
96 /* FIXME: Implement */
97 return E_NOTIMPL;
98 }
99
100 virtual HRESULT STDMETHODCALLTYPE ShowDW(
101 IN BOOL bShow)
102 {
103 /* We don't do anything... */
104 return S_OK;
105 }
106
107 virtual HRESULT STDMETHODCALLTYPE CloseDW(
108 IN DWORD dwReserved)
109 {
110 /* We don't do anything... */
111 return S_OK;
112 }
113
114 virtual HRESULT STDMETHODCALLTYPE ResizeBorderDW(
115 LPCRECT prcBorder,
116 IUnknown *punkToolbarSite,
117 BOOL fReserved)
118 {
119 /* No need to implement this method */
120 return E_NOTIMPL;
121 }
122
123 virtual HRESULT STDMETHODCALLTYPE GetBandInfo(
124 IN DWORD dwBandID,
125 IN DWORD dwViewMode,
126 IN OUT DESKBANDINFO *pdbi)
127 {
128 TRACE("ITaskBand::GetBandInfo(0x%x,0x%x,0x%p) hWnd=0x%p\n", dwBandID, dwViewMode, pdbi, hWnd);
129
130 if (hWnd != NULL)
131 {
132 /* The task band never has a title */
133 pdbi->dwMask &= ~DBIM_TITLE;
134
135 /* NOTE: We don't return DBIMF_UNDELETEABLE here, the band site will
136 handle us differently and add this flag for us. The reason for
137 this is future changes that might allow it to be deletable.
138 We want the band site to be in charge of this decision rather
139 the band itself! */
140 /* FIXME: What about DBIMF_NOGRIPPER and DBIMF_ALWAYSGRIPPER */
141 pdbi->dwModeFlags = DBIMF_VARIABLEHEIGHT;
142
143 if (dwViewMode & DBIF_VIEWMODE_VERTICAL)
144 {
145 pdbi->ptIntegral.y = 1;
146 pdbi->ptMinSize.y = 1;
147 /* FIXME: Get the button metrics from the task bar object!!! */
148 pdbi->ptMinSize.x = (3 * GetSystemMetrics(SM_CXEDGE) / 2) + /* FIXME: Might be wrong if only one column! */
149 GetSystemMetrics(SM_CXSIZE) + (2 * GetSystemMetrics(SM_CXEDGE)); /* FIXME: Min button size, query!!! */
150 }
151 else
152 {
153 pdbi->ptMinSize.y = GetSystemMetrics(SM_CYSIZE) + (2 * GetSystemMetrics(SM_CYEDGE)); /* FIXME: Query */
154 pdbi->ptIntegral.y = pdbi->ptMinSize.y + (3 * GetSystemMetrics(SM_CYEDGE) / 2); /* FIXME: Query metrics */
155 /* We're not going to allow task bands where not even the minimum button size fits into the band */
156 pdbi->ptMinSize.x = pdbi->ptIntegral.y;
157 }
158
159 /* Ignored: pdbi->ptMaxSize.x */
160 pdbi->ptMaxSize.y = -1;
161
162 /* FIXME: We should query the height from the task bar object!!! */
163 pdbi->ptActual.y = GetSystemMetrics(SM_CYSIZE) + (2 * GetSystemMetrics(SM_CYEDGE));
164
165 /* Save the band ID for future use in case we need to check whether a given band
166 is the task band */
167 this->dwBandID = dwBandID;
168
169 TRACE("H: %d, Min: %d,%d, Integral.y: %d Actual: %d,%d\n", (dwViewMode & DBIF_VIEWMODE_VERTICAL) == 0,
170 pdbi->ptMinSize.x, pdbi->ptMinSize.y, pdbi->ptIntegral.y,
171 pdbi->ptActual.x, pdbi->ptActual.y);
172
173 return S_OK;
174 }
175
176 return E_FAIL;
177 }
178
179 /*****************************************************************************/
180 // *** IOleCommandTarget methods ***
181 virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText)
182 {
183 UNIMPLEMENTED;
184 return E_NOTIMPL;
185 }
186
187 virtual HRESULT STDMETHODCALLTYPE Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
188 {
189 if (IsEqualIID(*pguidCmdGroup, IID_IBandSite))
190 {
191 return S_OK;
192 }
193
194 if (IsEqualIID(*pguidCmdGroup, IID_IDeskBand))
195 {
196 return S_OK;
197 }
198
199 UNIMPLEMENTED;
200 return E_NOTIMPL;
201 }
202
203 /*****************************************************************************/
204
205 virtual HRESULT STDMETHODCALLTYPE SetClient(
206 IN IUnknown *punkClient)
207 {
208 TRACE("IDeskBar::SetClient(0x%p)\n", punkClient);
209 return E_NOTIMPL;
210 }
211
212 virtual HRESULT STDMETHODCALLTYPE GetClient(
213 OUT IUnknown **ppunkClient)
214 {
215 TRACE("IDeskBar::GetClient(0x%p)\n", ppunkClient);
216 return E_NOTIMPL;
217 }
218
219 virtual HRESULT STDMETHODCALLTYPE OnPosRectChangeDB(
220 IN RECT *prc)
221 {
222 TRACE("IDeskBar::OnPosRectChangeDB(0x%p=(%d,%d,%d,%d))\n", prc, prc->left, prc->top, prc->right, prc->bottom);
223 if (prc->bottom - prc->top == 0)
224 return S_OK;
225
226 return S_FALSE;
227 }
228
229 /*****************************************************************************/
230
231 virtual HRESULT STDMETHODCALLTYPE GetClassID(
232 OUT CLSID *pClassID)
233 {
234 TRACE("ITaskBand::GetClassID(0x%p)\n", pClassID);
235 /* We're going to return the (internal!) CLSID of the task band interface */
236 *pClassID = CLSID_ITaskBand;
237 return S_OK;
238 }
239
240 virtual HRESULT STDMETHODCALLTYPE IsDirty()
241 {
242 /* The object hasn't changed since the last save! */
243 return S_FALSE;
244 }
245
246 virtual HRESULT STDMETHODCALLTYPE Load(
247 IN IStream *pStm)
248 {
249 TRACE("ITaskBand::Load called\n");
250 /* Nothing to do */
251 return S_OK;
252 }
253
254 virtual HRESULT STDMETHODCALLTYPE Save(
255 IN IStream *pStm,
256 IN BOOL fClearDirty)
257 {
258 /* Nothing to do */
259 return S_OK;
260 }
261
262 virtual HRESULT STDMETHODCALLTYPE GetSizeMax(
263 OUT ULARGE_INTEGER *pcbSize)
264 {
265 TRACE("ITaskBand::GetSizeMax called\n");
266 /* We don't need any space for the task band */
267 pcbSize->QuadPart = 0;
268 return S_OK;
269 }
270
271 /*****************************************************************************/
272
273 virtual HRESULT STDMETHODCALLTYPE SetSite(IUnknown *pUnkSite)
274 {
275 HRESULT hRet = E_FAIL;
276
277 TRACE("ITaskBand::SetSite(0x%p)\n", pUnkSite);
278
279 /* Release the current site */
280 if (punkSite != NULL)
281 {
282 punkSite->Release();
283 }
284
285 punkSite = NULL;
286 hWnd = NULL;
287
288 if (pUnkSite != NULL)
289 {
290 IOleWindow *OleWindow;
291
292 /* Check if the site supports IOleWindow */
293 hRet = pUnkSite->QueryInterface(IID_PPV_ARG(IOleWindow, &OleWindow));
294 if (SUCCEEDED(hRet))
295 {
296 HWND hWndParent = NULL;
297
298 hRet = OleWindow->GetWindow(
299 &hWndParent);
300 if (SUCCEEDED(hRet))
301 {
302 /* Attempt to create the task switch window */
303
304 TRACE("CreateTaskSwitchWnd(Parent: 0x%p)\n", hWndParent);
305 hWnd = CreateTaskSwitchWnd(hWndParent, Tray);
306 if (hWnd != NULL)
307 {
308 punkSite = pUnkSite;
309 hRet = S_OK;
310 }
311 else
312 {
313 TRACE("CreateTaskSwitchWnd() failed!\n");
314 OleWindow->Release();
315 hRet = E_FAIL;
316 }
317 }
318 else
319 OleWindow->Release();
320 }
321 else
322 TRACE("Querying IOleWindow failed: 0x%x\n", hRet);
323 }
324
325 return hRet;
326 }
327
328 virtual HRESULT STDMETHODCALLTYPE GetSite(
329 IN REFIID riid,
330 OUT VOID **ppvSite)
331 {
332 TRACE("ITaskBand::GetSite(0x%p,0x%p)\n", riid, ppvSite);
333
334 if (punkSite != NULL)
335 {
336 return punkSite->QueryInterface(riid, ppvSite);
337 }
338
339 *ppvSite = NULL;
340 return E_FAIL;
341 }
342
343 /*****************************************************************************/
344
345 virtual HRESULT STDMETHODCALLTYPE ProcessMessage(
346 IN HWND hWnd,
347 IN UINT uMsg,
348 IN WPARAM wParam,
349 IN LPARAM lParam,
350 OUT LRESULT *plrResult)
351 {
352 TRACE("ITaskBand: IWinEventHandler::ProcessMessage(0x%p, 0x%x, 0x%p, 0x%p, 0x%p)\n", hWnd, uMsg, wParam, lParam, plrResult);
353 return E_NOTIMPL;
354 }
355
356 virtual HRESULT STDMETHODCALLTYPE ContainsWindow(
357 IN HWND hWnd)
358 {
359 if (hWnd == hWnd ||
360 IsChild(hWnd, hWnd))
361 {
362 TRACE("ITaskBand::ContainsWindow(0x%p) returns S_OK\n", hWnd);
363 return S_OK;
364 }
365
366 return S_FALSE;
367 }
368
369 virtual HRESULT STDMETHODCALLTYPE OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
370 {
371 UNIMPLEMENTED;
372 return E_NOTIMPL;
373 }
374
375 virtual HRESULT STDMETHODCALLTYPE IsWindowOwner(HWND hWnd)
376 {
377 return (hWnd == this->hWnd) ? S_OK : S_FALSE;
378 }
379
380 /*****************************************************************************/
381
382 HRESULT STDMETHODCALLTYPE _Init(IN OUT ITrayWindow *tray)
383 {
384 Tray = tray;
385 dwBandID = (DWORD) -1;
386 return S_OK;
387 }
388
389 DECLARE_NOT_AGGREGATABLE(CTaskBand)
390
391 DECLARE_PROTECT_FINAL_CONSTRUCT()
392 BEGIN_COM_MAP(CTaskBand)
393 COM_INTERFACE_ENTRY2_IID(IID_IOleWindow, IOleWindow, IDeskBand)
394 COM_INTERFACE_ENTRY_IID(IID_IDeskBand, IDeskBand)
395 COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite)
396 COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist)
397 COM_INTERFACE_ENTRY_IID(IID_IPersistStream, IPersistStream)
398 COM_INTERFACE_ENTRY_IID(IID_IWinEventHandler, IWinEventHandler)
399 COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget)
400 END_COM_MAP()
401 };
402
403 ITaskBand * CreateTaskBand(IN OUT ITrayWindow *Tray)
404 {
405 HRESULT hr;
406
407 CTaskBand * tb = new CComObject<CTaskBand>();
408
409 if (!tb)
410 return NULL;
411
412 hr = tb->AddRef();
413
414 hr = tb->_Init(Tray);
415
416 if (FAILED_UNEXPECTEDLY(hr))
417 tb->Release();
418
419 return tb;
420 }