* Sync to recent trunk (r52563).
[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 <windows.h>
26 #include <shlobj.h>
27 #include <shlobj_undoc.h>
28 #include <shlguid.h>
29 #include <shlguid_undoc.h>
30 #include <tchar.h>
31 #include <exdisp.h>
32 #include <exdispid.h>
33 #include <atlbase.h>
34 #include <atlcom.h>
35 #include <atlwin.h>
36 #include "resource.h"
37 #include "brandband.h"
38
39 /*
40 TODO:
41 Add Exec command handlers
42 Properly implement GetBandInfo
43 Fix SetSite to revoke brand band service when site is cleared
44 */
45
46 inline void FillSolidRect(HDC dc, const RECT *bounds)
47 {
48 ::ExtTextOut(dc, 0, 0, ETO_OPAQUE, bounds, NULL, 0, NULL);
49 }
50
51 inline void FillSolidRect(HDC dc, const RECT *bounds, COLORREF clr)
52 {
53 ::SetBkColor(dc, clr);
54 ::ExtTextOut(dc, 0, 0, ETO_OPAQUE, bounds, NULL, 0, NULL);
55 }
56
57 long GetScreenDepth()
58 {
59 HDC tempDC;
60 long depth;
61
62 tempDC = GetDC(NULL);
63 depth = GetDeviceCaps(tempDC, BITSPIXEL) * GetDeviceCaps(tempDC, PLANES);
64 ReleaseDC(NULL, tempDC);
65 return depth;
66 }
67
68 static const int gSmallImageSize = 22;
69 static const int gMediumImageSize = 26;
70 static const int gLargeImageSize = 38;
71
72 static const int gTrueColorResourceBase = 240;
73 static const int g256ColorResourceBase = 245;
74
75 CBrandBand::CBrandBand()
76 {
77 fProfferCookie = 0;
78 fCurrentFrame = 0;
79 fMaxFrameCount = 0;
80 fImageBitmap = NULL;
81 fAdviseCookie = 0;
82 }
83
84 CBrandBand::~CBrandBand()
85 {
86 DeleteObject(fImageBitmap);
87 }
88
89 void CBrandBand::StartAnimation()
90 {
91 fCurrentFrame = 0;
92 SetTimer(5678, 30, NULL);
93 }
94
95 void CBrandBand::StopAnimation()
96 {
97 KillTimer(5678);
98 fCurrentFrame = 0;
99 Invalidate(FALSE);
100 }
101
102 void CBrandBand::SelectImage()
103 {
104 int screenDepth;
105 RECT clientRect;
106 int clientWidth;
107 int clientHeight;
108 int clientSize;
109 HINSTANCE shell32Instance;
110 BITMAP bitmapInfo;
111 int resourceID;
112
113 screenDepth = GetScreenDepth();
114 GetClientRect(&clientRect);
115 clientWidth = clientRect.right - clientRect.left;
116 clientHeight = clientRect.bottom - clientRect.top;
117 clientSize = min(clientWidth, clientHeight);
118 if (screenDepth > 8)
119 resourceID = gTrueColorResourceBase;
120 else
121 resourceID = g256ColorResourceBase;
122 if (clientSize >= gLargeImageSize)
123 resourceID += 2;
124 else if (clientSize >= gMediumImageSize)
125 resourceID += 1;
126 shell32Instance = GetModuleHandle(L"shell32.dll");
127 fImageBitmap = LoadBitmap(shell32Instance, MAKEINTRESOURCE(resourceID));
128 GetObjectW(fImageBitmap, sizeof(bitmapInfo), &bitmapInfo);
129 fBitmapSize = bitmapInfo.bmWidth;
130 fMaxFrameCount = bitmapInfo.bmHeight / fBitmapSize;
131 }
132
133 HRESULT STDMETHODCALLTYPE CBrandBand::GetBandInfo(DWORD dwBandID, DWORD dwViewMode, DESKBANDINFO* pdbi)
134 {
135 if (pdbi->dwMask & DBIM_MINSIZE)
136 {
137 pdbi->ptMinSize.x = 38;
138 pdbi->ptMinSize.y = 22;
139 }
140 if (pdbi->dwMask & DBIM_MAXSIZE)
141 {
142 pdbi->ptMaxSize.x = 38;
143 pdbi->ptMaxSize.y = 38;
144 }
145 if (pdbi->dwMask & DBIM_INTEGRAL)
146 {
147 pdbi->ptIntegral.x = 38;
148 pdbi->ptIntegral.y = 38;
149 }
150 if (pdbi->dwMask & DBIM_ACTUAL)
151 {
152 pdbi->ptActual.x = 38;
153 pdbi->ptActual.y = 38;
154 }
155 if (pdbi->dwMask & DBIM_TITLE)
156 wcscpy(pdbi->wszTitle, L"");
157 if (pdbi->dwMask & DBIM_MODEFLAGS)
158 pdbi->dwModeFlags = DBIMF_UNDELETEABLE;
159 if (pdbi->dwMask & DBIM_BKCOLOR)
160 pdbi->crBkgnd = 0;
161 return S_OK;
162 }
163
164 HRESULT STDMETHODCALLTYPE CBrandBand::SetSite(IUnknown* pUnkSite)
165 {
166 CComPtr<IBrowserService> browserService;
167 CComPtr<IOleWindow> oleWindow;
168 CComPtr<IServiceProvider> serviceProvider;
169 CComPtr<IProfferService> profferService;
170 HWND parentWindow;
171 HWND hwnd;
172 HRESULT hResult;
173
174 fSite.Release();
175 if (pUnkSite == NULL)
176 {
177 hResult = AtlUnadvise(fSite, DIID_DWebBrowserEvents, fAdviseCookie);
178 // TODO: revoke brand band service
179 return S_OK;
180 }
181 hResult = pUnkSite->QueryInterface(IID_IDockingWindowSite, (void **)&fSite);
182 if (FAILED(hResult))
183 return hResult;
184 parentWindow = NULL;
185 hResult = pUnkSite->QueryInterface(IID_IOleWindow, (void **)&oleWindow);
186 if (SUCCEEDED(hResult))
187 hResult = oleWindow->GetWindow(&parentWindow);
188 if (!::IsWindow(parentWindow))
189 return E_FAIL;
190
191 hwnd = SHCreateWorkerWindowW(0, parentWindow, 0, WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, NULL, 0);
192 if (hwnd == NULL)
193 return E_FAIL;
194 SubclassWindow(hwnd);
195 hResult = pUnkSite->QueryInterface(IID_IServiceProvider, (void **)&serviceProvider);
196 if (SUCCEEDED(hResult))
197 {
198 hResult = serviceProvider->QueryService(SID_SBrandBand, IID_IProfferService, (void **)&profferService);
199 if (SUCCEEDED(hResult))
200 hResult = profferService->ProfferService(SID_SBrandBand, (IServiceProvider *)this, &fProfferCookie);
201 hResult = serviceProvider->QueryService(SID_SShellBrowser, IID_IBrowserService, (void **)&browserService);
202 if (SUCCEEDED(hResult))
203 hResult = AtlAdvise(browserService, (IDispatch *)this, DIID_DWebBrowserEvents, &fAdviseCookie);
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(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(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
311 {
312 return E_NOTIMPL;
313 }
314
315 HRESULT STDMETHODCALLTYPE CBrandBand::IsWindowOwner(HWND hWnd)
316 {
317 if (hWnd == m_hWnd)
318 return S_OK;
319 return S_FALSE;
320 }
321
322 HRESULT STDMETHODCALLTYPE CBrandBand::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[ ], OLECMDTEXT *pCmdText)
323 {
324 return E_NOTIMPL;
325 }
326
327 HRESULT STDMETHODCALLTYPE CBrandBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
328 {
329 if (IsEqualIID(*pguidCmdGroup, CGID_PrivCITCommands))
330 {
331 }
332 else if (IsEqualIID(*pguidCmdGroup, CGID_BrandCmdGroup))
333 {
334 switch (nCmdID)
335 {
336 case BBID_STARTANIMATION:
337 StartAnimation();
338 return S_OK;
339 case BBID_STOPANIMATION:
340 StopAnimation();
341 return S_OK;
342 }
343 }
344 return E_FAIL;
345 }
346
347 HRESULT STDMETHODCALLTYPE CBrandBand::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
348 {
349 CComPtr<IServiceProvider> serviceProvider;
350 HRESULT hResult;
351
352 if (IsEqualIID(guidService, SID_SBrandBand))
353 return this->QueryInterface(riid, ppvObject);
354 hResult = fSite->QueryInterface(IID_IServiceProvider, (void **)&serviceProvider);
355 if (FAILED (hResult))
356 return hResult;
357 return serviceProvider->QueryService(guidService, riid, ppvObject);
358 }
359
360 HRESULT STDMETHODCALLTYPE CBrandBand::GetTypeInfoCount(UINT *pctinfo)
361 {
362 return E_NOTIMPL;
363 }
364
365 HRESULT STDMETHODCALLTYPE CBrandBand::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
366 {
367 return E_NOTIMPL;
368 }
369
370 HRESULT STDMETHODCALLTYPE CBrandBand::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
371 {
372 return E_NOTIMPL;
373 }
374
375 HRESULT STDMETHODCALLTYPE CBrandBand::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
376 {
377 if (pDispParams == NULL)
378 return E_INVALIDARG;
379 switch (dispIdMember)
380 {
381 case DISPID_DOWNLOADCOMPLETE:
382 StopAnimation();
383 break;
384 case DISPID_DOWNLOADBEGIN:
385 StartAnimation();
386 break;
387 }
388 return E_INVALIDARG;
389 }
390
391 LRESULT CBrandBand::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
392 {
393 Invalidate(FALSE);
394 return 0;
395 }
396
397 LRESULT CBrandBand::OnEraseBkgnd (UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
398 {
399 return 1;
400 }
401
402 LRESULT CBrandBand::OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
403 {
404 PAINTSTRUCT paintInfo;
405 HDC dc;
406 POINT destinationPoint;
407 HDC sourceDC;
408 HBITMAP oldBitmap;
409 RECT clientRect;
410 RECT tempRect;
411
412 dc = BeginPaint(&paintInfo);
413 GetClientRect(&clientRect);
414
415 destinationPoint.x = (clientRect.right - clientRect.left - fBitmapSize) / 2;
416 destinationPoint.y = (clientRect.bottom - clientRect.top - fBitmapSize) / 2;
417
418 ::SetBkColor(dc, RGB(255, 255, 255));
419
420 tempRect.left = 0;
421 tempRect.top = 0;
422 tempRect.right = clientRect.right;
423 tempRect.bottom = destinationPoint.y;
424 FillSolidRect(dc, &tempRect, RGB(255, 255, 255));
425
426 tempRect.left = 0;
427 tempRect.top = destinationPoint.y + fBitmapSize;
428 tempRect.right = clientRect.right;
429 tempRect.bottom = clientRect.bottom;
430 FillSolidRect(dc, &paintInfo.rcPaint, RGB(255, 255, 255));
431
432 tempRect.left = 0;
433 tempRect.top = destinationPoint.y;
434 tempRect.right = destinationPoint.x;
435 tempRect.bottom = destinationPoint.y + fBitmapSize;
436 FillSolidRect(dc, &paintInfo.rcPaint, RGB(255, 255, 255));
437
438 tempRect.left = destinationPoint.x + fBitmapSize;
439 tempRect.top = destinationPoint.y;
440 tempRect.right = clientRect.right;
441 tempRect.bottom = destinationPoint.y + fBitmapSize;
442 FillSolidRect(dc, &paintInfo.rcPaint, RGB(255, 255, 255));
443
444 sourceDC = CreateCompatibleDC(dc);
445 oldBitmap = (HBITMAP)SelectObject(sourceDC, fImageBitmap);
446
447 BitBlt(dc, destinationPoint.x, destinationPoint.y, fBitmapSize, fBitmapSize, sourceDC, 0, fCurrentFrame * fBitmapSize, SRCCOPY);
448
449 SelectObject(sourceDC, oldBitmap);
450 DeleteDC(sourceDC);
451
452 EndPaint(&paintInfo);
453 return 0;
454 }
455
456 LRESULT CBrandBand::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
457 {
458 fCurrentFrame++;
459 if (fCurrentFrame >= fMaxFrameCount)
460 fCurrentFrame = 0;
461 Invalidate(FALSE);
462 return 0;
463 }
464
465 HRESULT CreateBrandBand(REFIID riid, void **ppv)
466 {
467 CComObject<CBrandBand> *theMenuBar;
468 HRESULT hResult;
469
470 if (ppv == NULL)
471 return E_POINTER;
472 *ppv = NULL;
473 ATLTRY (theMenuBar = new CComObject<CBrandBand>);
474 if (theMenuBar == NULL)
475 return E_OUTOFMEMORY;
476 hResult = theMenuBar->QueryInterface (riid, (void **)ppv);
477 if (FAILED (hResult))
478 {
479 delete theMenuBar;
480 return hResult;
481 }
482 return S_OK;
483 }