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