Sync to trunk revision 61757.
[reactos.git] / dll / win32 / browseui / brandband.cpp
1 /*
2 * ReactOS Explorer
3 *
4 * Copyright 2009 Andrew Hill <ash77 at domain 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 /*
22 Implements the logo band of a cabinet window. Most remarkable feature is the
23 animation.
24 */
25
26 #include "precomp.h"
27
28 /*
29 TODO:
30 Add Exec command handlers
31 Properly implement GetBandInfo
32 Fix SetSite to revoke brand band service when site is cleared
33 */
34
35 inline void FillSolidRect(HDC dc, const RECT *bounds)
36 {
37 ::ExtTextOut(dc, 0, 0, ETO_OPAQUE, bounds, NULL, 0, NULL);
38 }
39
40 inline void FillSolidRect(HDC dc, const RECT *bounds, COLORREF clr)
41 {
42 ::SetBkColor(dc, clr);
43 ::ExtTextOut(dc, 0, 0, ETO_OPAQUE, bounds, NULL, 0, NULL);
44 }
45
46 long GetScreenDepth()
47 {
48 HDC tempDC;
49 long depth;
50
51 tempDC = GetDC(NULL);
52 depth = GetDeviceCaps(tempDC, BITSPIXEL) * GetDeviceCaps(tempDC, PLANES);
53 ReleaseDC(NULL, tempDC);
54 return depth;
55 }
56
57 static const int gSmallImageSize = 22;
58 static const int gMediumImageSize = 26;
59 static const int gLargeImageSize = 38;
60
61 static const int gTrueColorResourceBase = 240;
62 static const int g256ColorResourceBase = 245;
63
64 CBrandBand::CBrandBand()
65 {
66 fProfferCookie = 0;
67 fCurrentFrame = 0;
68 fMaxFrameCount = 0;
69 fImageBitmap = NULL;
70 fBitmapSize = 0;
71 fAdviseCookie = 0;
72 }
73
74 CBrandBand::~CBrandBand()
75 {
76 DeleteObject(fImageBitmap);
77 }
78
79 void CBrandBand::StartAnimation()
80 {
81 fCurrentFrame = 0;
82 SetTimer(5678, 30, NULL);
83 }
84
85 void CBrandBand::StopAnimation()
86 {
87 KillTimer(5678);
88 fCurrentFrame = 0;
89 Invalidate(FALSE);
90 }
91
92 void CBrandBand::SelectImage()
93 {
94 int screenDepth;
95 RECT clientRect;
96 int clientWidth;
97 int clientHeight;
98 int clientSize;
99 HINSTANCE shell32Instance;
100 BITMAP bitmapInfo;
101 int resourceID;
102
103 screenDepth = GetScreenDepth();
104 GetClientRect(&clientRect);
105 clientWidth = clientRect.right - clientRect.left;
106 clientHeight = clientRect.bottom - clientRect.top;
107 clientSize = min(clientWidth, clientHeight);
108 if (screenDepth > 8)
109 resourceID = gTrueColorResourceBase;
110 else
111 resourceID = g256ColorResourceBase;
112 if (clientSize >= gLargeImageSize)
113 resourceID += 2;
114 else if (clientSize >= gMediumImageSize)
115 resourceID += 1;
116 shell32Instance = GetModuleHandle(L"shell32.dll");
117 fImageBitmap = LoadBitmap(shell32Instance, MAKEINTRESOURCE(resourceID));
118 GetObjectW(fImageBitmap, sizeof(bitmapInfo), &bitmapInfo);
119 fBitmapSize = bitmapInfo.bmWidth;
120 fMaxFrameCount = bitmapInfo.bmHeight / fBitmapSize;
121 }
122
123 HRESULT STDMETHODCALLTYPE CBrandBand::GetBandInfo(DWORD dwBandID, DWORD dwViewMode, DESKBANDINFO* pdbi)
124 {
125 if (pdbi->dwMask & DBIM_MINSIZE)
126 {
127 pdbi->ptMinSize.x = 38;
128 pdbi->ptMinSize.y = 22;
129 }
130 if (pdbi->dwMask & DBIM_MAXSIZE)
131 {
132 pdbi->ptMaxSize.x = 38;
133 pdbi->ptMaxSize.y = 38;
134 }
135 if (pdbi->dwMask & DBIM_INTEGRAL)
136 {
137 pdbi->ptIntegral.x = 38;
138 pdbi->ptIntegral.y = 38;
139 }
140 if (pdbi->dwMask & DBIM_ACTUAL)
141 {
142 pdbi->ptActual.x = 38;
143 pdbi->ptActual.y = 38;
144 }
145 if (pdbi->dwMask & DBIM_TITLE)
146 wcscpy(pdbi->wszTitle, L"");
147 if (pdbi->dwMask & DBIM_MODEFLAGS)
148 pdbi->dwModeFlags = DBIMF_UNDELETEABLE;
149 if (pdbi->dwMask & DBIM_BKCOLOR)
150 pdbi->crBkgnd = 0;
151 return S_OK;
152 }
153
154 HRESULT STDMETHODCALLTYPE CBrandBand::SetSite(IUnknown* pUnkSite)
155 {
156 CComPtr<IBrowserService> browserService;
157 CComPtr<IOleWindow> oleWindow;
158 CComPtr<IServiceProvider> serviceProvider;
159 CComPtr<IProfferService> profferService;
160 HWND parentWindow;
161 HWND hwnd;
162 HRESULT hResult;
163
164 fSite.Release();
165 if (pUnkSite == NULL)
166 {
167 hResult = AtlUnadvise(fSite, DIID_DWebBrowserEvents, fAdviseCookie);
168 // TODO: revoke brand band service
169 return S_OK;
170 }
171
172 // get window handle of parent
173 hResult = pUnkSite->QueryInterface(IID_IDockingWindowSite, reinterpret_cast<void **>(&fSite));
174 if (FAILED(hResult))
175 return hResult;
176 parentWindow = NULL;
177 hResult = pUnkSite->QueryInterface(IID_IOleWindow, reinterpret_cast<void **>(&oleWindow));
178 if (SUCCEEDED(hResult))
179 hResult = oleWindow->GetWindow(&parentWindow);
180 if (!::IsWindow(parentWindow))
181 return E_FAIL;
182
183 // create worker window in parent window
184 hwnd = SHCreateWorkerWindowW(0, parentWindow, 0,
185 WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, NULL, 0);
186 if (hwnd == NULL)
187 return E_FAIL;
188 SubclassWindow(hwnd);
189
190 // take advice to watch events
191 hResult = pUnkSite->QueryInterface(IID_IServiceProvider, reinterpret_cast<void **>(&serviceProvider));
192 if (SUCCEEDED(hResult))
193 {
194 hResult = serviceProvider->QueryService(
195 SID_SBrandBand, IID_IProfferService, reinterpret_cast<void **>(&profferService));
196 if (SUCCEEDED(hResult))
197 hResult = profferService->ProfferService(SID_SBrandBand,
198 static_cast<IServiceProvider *>(this), &fProfferCookie);
199 hResult = serviceProvider->QueryService(SID_SShellBrowser,
200 IID_IBrowserService, reinterpret_cast<void **>(&browserService));
201 if (SUCCEEDED(hResult))
202 hResult = AtlAdvise(browserService, static_cast<IDispatch *>(this), DIID_DWebBrowserEvents, &fAdviseCookie);
203 }
204
205 // ignore any hResult errors up to here - they are nonfatal
206 hResult = S_OK;
207 SelectImage();
208 return hResult;
209 }
210
211 HRESULT STDMETHODCALLTYPE CBrandBand::GetSite(REFIID riid, void **ppvSite)
212 {
213 if (ppvSite == NULL)
214 return E_POINTER;
215 if (fSite.p == NULL)
216 {
217 *ppvSite = NULL;
218 return E_FAIL;
219 }
220 return fSite.p->QueryInterface(riid, ppvSite);
221 }
222
223 HRESULT STDMETHODCALLTYPE CBrandBand::GetWindow(HWND *lphwnd)
224 {
225 if (lphwnd == NULL)
226 return E_POINTER;
227 *lphwnd = m_hWnd;
228 return S_OK;
229 }
230
231 HRESULT STDMETHODCALLTYPE CBrandBand::ContextSensitiveHelp(BOOL fEnterMode)
232 {
233 return E_NOTIMPL;
234 }
235
236 HRESULT STDMETHODCALLTYPE CBrandBand::CloseDW(DWORD dwReserved)
237 {
238 ShowDW(FALSE);
239
240 if (IsWindow())
241 DestroyWindow();
242
243 m_hWnd = NULL;
244
245 return S_OK;
246 }
247
248 HRESULT STDMETHODCALLTYPE CBrandBand::ResizeBorderDW(
249 const RECT* prcBorder, IUnknown* punkToolbarSite, BOOL fReserved)
250 {
251 return E_NOTIMPL;
252 }
253
254 HRESULT STDMETHODCALLTYPE CBrandBand::ShowDW(BOOL fShow)
255 {
256 if (m_hWnd)
257 {
258 if (fShow)
259 ShowWindow(SW_SHOW);
260 else
261 ShowWindow(SW_HIDE);
262 }
263 return S_OK;
264 }
265
266 HRESULT STDMETHODCALLTYPE CBrandBand::HasFocusIO()
267 {
268 if (GetFocus() == m_hWnd)
269 return S_OK;
270 return S_FALSE;
271 }
272
273 HRESULT STDMETHODCALLTYPE CBrandBand::TranslateAcceleratorIO(LPMSG lpMsg)
274 {
275 return E_NOTIMPL;
276 }
277
278 HRESULT STDMETHODCALLTYPE CBrandBand::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
279 {
280 return E_NOTIMPL;
281 }
282
283 HRESULT STDMETHODCALLTYPE CBrandBand::GetClassID(CLSID *pClassID)
284 {
285 if (pClassID == NULL)
286 return E_POINTER;
287 *pClassID = CLSID_BrandBand;
288 return S_OK;
289 }
290
291 HRESULT STDMETHODCALLTYPE CBrandBand::IsDirty()
292 {
293 return S_FALSE;
294 }
295
296 HRESULT STDMETHODCALLTYPE CBrandBand::Load(IStream *pStm)
297 {
298 return E_NOTIMPL;
299 }
300
301 HRESULT STDMETHODCALLTYPE CBrandBand::Save(IStream *pStm, BOOL fClearDirty)
302 {
303 return E_NOTIMPL;
304 }
305
306 HRESULT STDMETHODCALLTYPE CBrandBand::GetSizeMax(ULARGE_INTEGER *pcbSize)
307 {
308 return E_NOTIMPL;
309 }
310
311 HRESULT STDMETHODCALLTYPE CBrandBand::OnWinEvent(
312 HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
313 {
314 return E_NOTIMPL;
315 }
316
317 HRESULT STDMETHODCALLTYPE CBrandBand::IsWindowOwner(HWND hWnd)
318 {
319 if (hWnd == m_hWnd)
320 return S_OK;
321 return S_FALSE;
322 }
323
324 HRESULT STDMETHODCALLTYPE CBrandBand::QueryStatus(
325 const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[ ], OLECMDTEXT *pCmdText)
326 {
327 return E_NOTIMPL;
328 }
329
330 HRESULT STDMETHODCALLTYPE CBrandBand::Exec(const GUID *pguidCmdGroup,
331 DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
332 {
333 if (IsEqualIID(*pguidCmdGroup, CGID_PrivCITCommands))
334 {
335 }
336 else if (IsEqualIID(*pguidCmdGroup, CGID_BrandCmdGroup))
337 {
338 switch (nCmdID)
339 {
340 case BBID_STARTANIMATION:
341 StartAnimation();
342 return S_OK;
343 case BBID_STOPANIMATION:
344 StopAnimation();
345 return S_OK;
346 }
347 }
348 return E_FAIL;
349 }
350
351 HRESULT STDMETHODCALLTYPE CBrandBand::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
352 {
353 CComPtr<IServiceProvider> serviceProvider;
354 HRESULT hResult;
355
356 if (IsEqualIID(guidService, SID_SBrandBand))
357 return this->QueryInterface(riid, ppvObject);
358 hResult = fSite->QueryInterface(IID_IServiceProvider, reinterpret_cast<void **>(&serviceProvider));
359 if (FAILED(hResult))
360 return hResult;
361 return serviceProvider->QueryService(guidService, riid, ppvObject);
362 }
363
364 HRESULT STDMETHODCALLTYPE CBrandBand::GetTypeInfoCount(UINT *pctinfo)
365 {
366 return E_NOTIMPL;
367 }
368
369 HRESULT STDMETHODCALLTYPE CBrandBand::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
370 {
371 return E_NOTIMPL;
372 }
373
374 HRESULT STDMETHODCALLTYPE CBrandBand::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames,
375 LCID lcid, DISPID *rgDispId)
376 {
377 return E_NOTIMPL;
378 }
379
380 HRESULT STDMETHODCALLTYPE CBrandBand::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
381 DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
382 {
383 if (pDispParams == NULL)
384 return E_INVALIDARG;
385 switch (dispIdMember)
386 {
387 case DISPID_DOWNLOADCOMPLETE:
388 StopAnimation();
389 break;
390 case DISPID_DOWNLOADBEGIN:
391 StartAnimation();
392 break;
393 }
394 return E_INVALIDARG;
395 }
396
397 LRESULT CBrandBand::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
398 {
399 Invalidate(FALSE);
400 return 0;
401 }
402
403 LRESULT CBrandBand::OnEraseBkgnd (UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
404 {
405 return 1;
406 }
407
408 LRESULT CBrandBand::OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
409 {
410 PAINTSTRUCT paintInfo;
411 HDC dc;
412 POINT destinationPoint;
413 HDC sourceDC;
414 HBITMAP oldBitmap;
415 RECT clientRect;
416 RECT tempRect;
417
418 dc = BeginPaint(&paintInfo);
419 GetClientRect(&clientRect);
420
421 destinationPoint.x = (clientRect.right - clientRect.left - fBitmapSize) / 2;
422 destinationPoint.y = (clientRect.bottom - clientRect.top - fBitmapSize) / 2;
423
424 ::SetBkColor(dc, RGB(255, 255, 255));
425
426 tempRect.left = 0;
427 tempRect.top = 0;
428 tempRect.right = clientRect.right;
429 tempRect.bottom = destinationPoint.y;
430 FillSolidRect(dc, &tempRect, RGB(255, 255, 255));
431
432 tempRect.left = 0;
433 tempRect.top = destinationPoint.y + fBitmapSize;
434 tempRect.right = clientRect.right;
435 tempRect.bottom = clientRect.bottom;
436 FillSolidRect(dc, &paintInfo.rcPaint, RGB(255, 255, 255));
437
438 tempRect.left = 0;
439 tempRect.top = destinationPoint.y;
440 tempRect.right = destinationPoint.x;
441 tempRect.bottom = destinationPoint.y + fBitmapSize;
442 FillSolidRect(dc, &paintInfo.rcPaint, RGB(255, 255, 255));
443
444 tempRect.left = destinationPoint.x + fBitmapSize;
445 tempRect.top = destinationPoint.y;
446 tempRect.right = clientRect.right;
447 tempRect.bottom = destinationPoint.y + fBitmapSize;
448 FillSolidRect(dc, &paintInfo.rcPaint, RGB(255, 255, 255));
449
450 sourceDC = CreateCompatibleDC(dc);
451 oldBitmap = reinterpret_cast<HBITMAP>(SelectObject(sourceDC, fImageBitmap));
452
453 BitBlt(dc, destinationPoint.x, destinationPoint.y, fBitmapSize, fBitmapSize, sourceDC, 0, fCurrentFrame * fBitmapSize, SRCCOPY);
454
455 SelectObject(sourceDC, oldBitmap);
456 DeleteDC(sourceDC);
457
458 EndPaint(&paintInfo);
459 return 0;
460 }
461
462 LRESULT CBrandBand::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
463 {
464 fCurrentFrame++;
465 if (fCurrentFrame >= fMaxFrameCount)
466 fCurrentFrame = 0;
467 Invalidate(FALSE);
468 return 0;
469 }
470
471 HRESULT CreateBrandBand(REFIID riid, void **ppv)
472 {
473 CComObject<CBrandBand> *theMenuBar;
474 HRESULT hResult;
475
476 if (ppv == NULL)
477 return E_POINTER;
478 *ppv = NULL;
479 ATLTRY (theMenuBar = new CComObject<CBrandBand>);
480 if (theMenuBar == NULL)
481 return E_OUTOFMEMORY;
482 hResult = theMenuBar->QueryInterface(riid, reinterpret_cast<void **>(ppv));
483 if (FAILED(hResult))
484 {
485 delete theMenuBar;
486 return hResult;
487 }
488 return S_OK;
489 }