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