f79f86c7a3014f3fbbcec4fc6508a95f86f0c8a3
[reactos.git] / reactos / dll / win32 / uxtheme / nonclient.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS uxtheme.dll
4 * FILE: dll/win32/uxtheme/nonclient.c
5 * PURPOSE: uxtheme non client area management
6 * PROGRAMMER: Giannis Adamopoulos
7 */
8
9 #include "uxthemep.h"
10
11 HFONT hMenuFont = NULL;
12 HFONT hMenuFontBold = NULL;
13
14 void InitMenuFont(VOID)
15 {
16 NONCLIENTMETRICS ncm;
17
18 ncm.cbSize = sizeof(NONCLIENTMETRICS);
19
20 if (!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
21 {
22 return;
23 }
24
25 hMenuFont = CreateFontIndirect(&ncm.lfMenuFont);
26
27 ncm.lfMenuFont.lfWeight = max(ncm.lfMenuFont.lfWeight + 300, 1000);
28 hMenuFontBold = CreateFontIndirect(&ncm.lfMenuFont);
29 }
30
31 static BOOL
32 IsWindowActive(HWND hWnd, DWORD ExStyle)
33 {
34 BOOL ret;
35
36 if (ExStyle & WS_EX_MDICHILD)
37 {
38 ret = IsChild(GetForegroundWindow(), hWnd);
39 if (ret)
40 ret = (hWnd == (HWND)SendMessageW(GetParent(hWnd), WM_MDIGETACTIVE, 0, 0));
41 }
42 else
43 {
44 ret = (GetForegroundWindow() == hWnd);
45 }
46
47 return ret;
48 }
49
50 BOOL
51 IsScrollBarVisible(HWND hWnd, INT hBar)
52 {
53 SCROLLBARINFO sbi = {sizeof(SCROLLBARINFO)};
54 if(!GetScrollBarInfo(hWnd, hBar, &sbi))
55 return FALSE;
56
57 return !(sbi.rgstate[0] & STATE_SYSTEM_OFFSCREEN);
58 }
59
60 static BOOL
61 UserHasWindowEdge(DWORD Style, DWORD ExStyle)
62 {
63 if (Style & WS_MINIMIZE)
64 return TRUE;
65 if (ExStyle & WS_EX_DLGMODALFRAME)
66 return TRUE;
67 if (ExStyle & WS_EX_STATICEDGE)
68 return FALSE;
69 if (Style & WS_THICKFRAME)
70 return TRUE;
71 Style &= WS_CAPTION;
72 if (Style == WS_DLGFRAME || Style == WS_CAPTION)
73 return TRUE;
74 return FALSE;
75 }
76
77 static HICON
78 UserGetWindowIcon(PDRAW_CONTEXT pcontext)
79 {
80 HICON hIcon = NULL;
81
82 SendMessageTimeout(pcontext->hWnd, WM_GETICON, ICON_SMALL2, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon);
83
84 if (!hIcon)
85 SendMessageTimeout(pcontext->hWnd, WM_GETICON, ICON_SMALL, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon);
86
87 if (!hIcon)
88 SendMessageTimeout(pcontext->hWnd, WM_GETICON, ICON_BIG, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon);
89
90 if (!hIcon)
91 hIcon = (HICON)GetClassLong(pcontext->hWnd, GCL_HICONSM);
92
93 if (!hIcon)
94 hIcon = (HICON)GetClassLong(pcontext->hWnd, GCL_HICON);
95
96 // See also win32ss/user/ntuser/nonclient.c!NC_IconForWindow
97 if (!hIcon && !(pcontext->wi.dwExStyle & WS_EX_DLGMODALFRAME))
98 hIcon = LoadIconW(NULL, (LPCWSTR)IDI_WINLOGO);
99
100 return hIcon;
101 }
102
103 HRESULT WINAPI ThemeDrawCaptionText(PDRAW_CONTEXT pcontext, RECT* pRect, int iPartId, int iStateId)
104 {
105 HRESULT hr;
106 HFONT hFont = NULL;
107 HGDIOBJ oldFont = NULL;
108 LOGFONTW logfont;
109 COLORREF textColor;
110 COLORREF oldTextColor;
111
112 WCHAR buffer[50];
113 WCHAR *pszText = buffer;
114 INT len;
115
116 len = InternalGetWindowText(pcontext->hWnd, NULL, 0);
117 if (!len)
118 return S_OK;
119
120 len++; /* From now on this is the size of the buffer so include the null */
121
122 if (len > ARRAYSIZE(buffer))
123 {
124 pszText = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
125 if (!pszText)
126 return E_OUTOFMEMORY;
127 }
128
129 InternalGetWindowText(pcontext->hWnd, pszText, len);
130
131 hr = GetThemeSysFont(0,TMT_CAPTIONFONT,&logfont);
132 if(SUCCEEDED(hr))
133 hFont = CreateFontIndirectW(&logfont);
134
135 if(hFont)
136 oldFont = SelectObject(pcontext->hDC, hFont);
137
138 if (!pcontext->Active)
139 textColor = GetSysColor(COLOR_INACTIVECAPTIONTEXT);
140 else
141 textColor = GetSysColor(COLOR_CAPTIONTEXT);
142
143 oldTextColor = SetTextColor(pcontext->hDC, textColor);
144 DrawThemeText(pcontext->theme,
145 pcontext->hDC,
146 iPartId,
147 iStateId,
148 pszText,
149 len - 1,
150 DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS,
151 0,
152 pRect);
153 SetTextColor(pcontext->hDC, oldTextColor);
154
155 if (hFont)
156 {
157 SelectObject(pcontext->hDC, oldFont);
158 DeleteObject(hFont);
159 }
160 if (pszText != buffer)
161 {
162 HeapFree(GetProcessHeap(), 0, pszText);
163 }
164 return S_OK;
165 }
166
167 void
168 ThemeInitDrawContext(PDRAW_CONTEXT pcontext,
169 HWND hWnd,
170 HRGN hRgn)
171 {
172 pcontext->wi.cbSize = sizeof(pcontext->wi);
173 GetWindowInfo(hWnd, &pcontext->wi);
174 pcontext->hWnd = hWnd;
175 pcontext->Active = IsWindowActive(hWnd, pcontext->wi.dwExStyle);
176 pcontext->theme = GetNCCaptionTheme(hWnd, pcontext->wi.dwStyle);
177 pcontext->scrolltheme = GetNCScrollbarTheme(hWnd, pcontext->wi.dwStyle);
178
179 pcontext->CaptionHeight = pcontext->wi.cyWindowBorders;
180 pcontext->CaptionHeight += GetSystemMetrics(pcontext->wi.dwExStyle & WS_EX_TOOLWINDOW ? SM_CYSMCAPTION : SM_CYCAPTION );
181
182 if(hRgn <= (HRGN)1)
183 {
184 hRgn = CreateRectRgnIndirect(&pcontext->wi.rcWindow);
185 }
186 pcontext->hRgn = hRgn;
187
188 pcontext->hDC = GetDCEx(hWnd, hRgn, DCX_WINDOW | DCX_INTERSECTRGN | DCX_USESTYLE | DCX_KEEPCLIPRGN);
189 }
190
191 void
192 ThemeCleanupDrawContext(PDRAW_CONTEXT pcontext)
193 {
194 ReleaseDC(pcontext->hWnd ,pcontext->hDC);
195
196 if(pcontext->hRgn != NULL)
197 {
198 DeleteObject(pcontext->hRgn);
199 }
200 }
201
202 static void
203 ThemeStartBufferedPaint(PDRAW_CONTEXT pcontext, int cx, int cy)
204 {
205 HBITMAP hbmp;
206
207 pcontext->hDCScreen = pcontext->hDC;
208 pcontext->hDC = CreateCompatibleDC(pcontext->hDCScreen);
209 hbmp = CreateCompatibleBitmap(pcontext->hDCScreen, cx, cy);
210 pcontext->hbmpOld = (HBITMAP)SelectObject(pcontext->hDC, hbmp);
211 }
212
213 static void
214 ThemeEndBufferedPaint(PDRAW_CONTEXT pcontext, int x, int y, int cx, int cy)
215 {
216 HBITMAP hbmp;
217 BitBlt(pcontext->hDCScreen, 0, 0, cx, cy, pcontext->hDC, x, y, SRCCOPY);
218 hbmp = (HBITMAP) SelectObject(pcontext->hDC, pcontext->hbmpOld);
219 DeleteObject(pcontext->hDC);
220 DeleteObject(hbmp);
221
222 pcontext->hDC = pcontext->hDCScreen;
223 }
224
225 void ThemeCalculateCaptionButtonsPos(HWND hWnd, HTHEME htheme)
226 {
227 PWND_DATA pwndData;
228 DWORD style;
229 INT ButtonWidth, ButtonHeight, iPartId, i;
230 WINDOWINFO wi = {sizeof(wi)};
231 RECT rcCurrent;
232
233 /* First of all check if we have something to do here */
234 style = GetWindowLongW(hWnd, GWL_STYLE);
235 if((style & (WS_CAPTION | WS_SYSMENU)) != (WS_CAPTION | WS_SYSMENU))
236 return;
237
238 /* Get theme data for this window */
239 pwndData = ThemeGetWndData(hWnd);
240 if (pwndData == NULL)
241 return;
242
243 if (!htheme)
244 htheme = pwndData->hthemeWindow;
245
246 if(!GetWindowInfo(hWnd, &wi))
247 return;
248
249 /* Calculate the area of the caption */
250 rcCurrent.top = rcCurrent.left = 0;
251 rcCurrent.right = wi.rcWindow.right - wi.rcWindow.left;
252 rcCurrent.bottom = wi.rcWindow.bottom - wi.rcWindow.top;
253
254 /* Add a padding around the objects of the caption */
255 InflateRect(&rcCurrent, -(int)wi.cyWindowBorders-BUTTON_GAP_SIZE,
256 -(int)wi.cyWindowBorders-BUTTON_GAP_SIZE);
257
258 for (i = CLOSEBUTTON; i <= HELPBUTTON; i++)
259 {
260 SIZE ButtonSize;
261
262 switch(i)
263 {
264 case CLOSEBUTTON:
265 iPartId = wi.dwExStyle & WS_EX_TOOLWINDOW ? WP_SMALLCLOSEBUTTON : WP_CLOSEBUTTON;
266 break;
267
268 case MAXBUTTON:
269 iPartId = wi.dwStyle & WS_MAXIMIZE ? WP_RESTOREBUTTON : WP_MAXBUTTON;
270 break;
271
272 case MINBUTTON:
273 iPartId = wi.dwStyle & WS_MINIMIZE ? WP_RESTOREBUTTON : WP_MINBUTTON;
274 break;
275
276 default:
277 iPartId = WP_HELPBUTTON ;
278 }
279
280 GetThemePartSize(htheme, NULL, iPartId, 0, NULL, TS_MIN, &ButtonSize);
281
282 ButtonHeight = GetSystemMetrics( wi.dwExStyle & WS_EX_TOOLWINDOW ? SM_CYSMSIZE : SM_CYSIZE);
283 ButtonWidth = MulDiv(ButtonSize.cx, ButtonHeight, ButtonSize.cy);
284
285 ButtonHeight -= 4;
286 ButtonWidth -= 4;
287
288 SetRect(&pwndData->rcCaptionButtons[i],
289 rcCurrent.right - ButtonWidth,
290 rcCurrent.top,
291 rcCurrent.right,
292 rcCurrent.top + ButtonHeight);
293
294 rcCurrent.right -= ButtonWidth + BUTTON_GAP_SIZE;
295 }
296 }
297
298 static void
299 ThemeDrawCaptionButton(PDRAW_CONTEXT pcontext,
300 CAPTIONBUTTON buttonId,
301 INT iStateId)
302 {
303 INT iPartId;
304 PWND_DATA pwndData = ThemeGetWndData(pcontext->hWnd);
305 if (!pwndData)
306 return;
307
308 switch(buttonId)
309 {
310 case CLOSEBUTTON:
311 iPartId = pcontext->wi.dwExStyle & WS_EX_TOOLWINDOW ? WP_SMALLCLOSEBUTTON : WP_CLOSEBUTTON;
312 break;
313
314 case MAXBUTTON:
315 if (!(pcontext->wi.dwStyle & WS_MAXIMIZEBOX))
316 {
317 if (!(pcontext->wi.dwStyle & WS_MINIMIZEBOX))
318 return;
319 else
320 iStateId = BUTTON_DISABLED;
321 }
322
323 iPartId = pcontext->wi.dwStyle & WS_MAXIMIZE ? WP_RESTOREBUTTON : WP_MAXBUTTON;
324 break;
325
326 case MINBUTTON:
327 if (!(pcontext->wi.dwStyle & WS_MINIMIZEBOX))
328 {
329 if (!(pcontext->wi.dwStyle & WS_MAXIMIZEBOX))
330 return;
331 else
332 iStateId = BUTTON_DISABLED;
333 }
334
335 iPartId = pcontext->wi.dwStyle & WS_MINIMIZE ? WP_RESTOREBUTTON : WP_MINBUTTON;
336 break;
337
338 default:
339 //FIXME: Implement Help Button
340 return;
341 }
342
343 DrawThemeBackground(pcontext->theme, pcontext->hDC, iPartId, iStateId, &pwndData->rcCaptionButtons[buttonId], NULL);
344 }
345
346 static DWORD
347 ThemeGetButtonState(DWORD htCurrect, DWORD htHot, DWORD htDown, BOOL Active)
348 {
349 if (htHot == htCurrect)
350 return BUTTON_HOT;
351 if (!Active)
352 return BUTTON_INACTIVE;
353 if (htDown == htCurrect)
354 return BUTTON_PRESSED;
355
356 return BUTTON_NORMAL;
357 }
358
359 /* Used only from mouse event handlers */
360 static void
361 ThemeDrawCaptionButtons(PDRAW_CONTEXT pcontext, DWORD htHot, DWORD htDown)
362 {
363 /* Draw the buttons */
364 ThemeDrawCaptionButton(pcontext, CLOSEBUTTON,
365 ThemeGetButtonState(HTCLOSE, htHot, htDown, pcontext->Active));
366 ThemeDrawCaptionButton(pcontext, MAXBUTTON,
367 ThemeGetButtonState(HTMAXBUTTON, htHot, htDown, pcontext->Active));
368 ThemeDrawCaptionButton(pcontext, MINBUTTON,
369 ThemeGetButtonState(HTMINBUTTON, htHot, htDown, pcontext->Active));
370 ThemeDrawCaptionButton(pcontext, HELPBUTTON,
371 ThemeGetButtonState(HTHELP, htHot, htDown, pcontext->Active));
372 }
373
374 /* Used from WM_NCPAINT and WM_NCACTIVATE handlers */
375 static void
376 ThemeDrawCaption(PDRAW_CONTEXT pcontext, RECT* prcCurrent)
377 {
378 RECT rcPart;
379 int iPart, iState;
380 HICON hIcon;
381
382 // See also win32ss/user/ntuser/nonclient.c!UserDrawCaptionBar
383 // and win32ss/user/ntuser/nonclient.c!UserDrawCaption
384 if ((pcontext->wi.dwStyle & WS_SYSMENU) && !(pcontext->wi.dwExStyle & WS_EX_TOOLWINDOW))
385 hIcon = UserGetWindowIcon(pcontext);
386 else
387 hIcon = NULL;
388
389 /* Get the caption part and state id */
390 if (pcontext->wi.dwStyle & WS_MINIMIZE)
391 iPart = WP_MINCAPTION;
392 else if (pcontext->wi.dwExStyle & WS_EX_TOOLWINDOW)
393 iPart = WP_SMALLCAPTION;
394 else if (pcontext->wi.dwStyle & WS_MAXIMIZE)
395 iPart = WP_MAXCAPTION;
396 else
397 iPart = WP_CAPTION;
398
399 iState = pcontext->Active ? FS_ACTIVE : FS_INACTIVE;
400
401 /* Draw the caption background */
402 rcPart = *prcCurrent;
403 rcPart.bottom = rcPart.top + pcontext->CaptionHeight;
404 prcCurrent->top = rcPart.bottom;
405 DrawThemeBackground(pcontext->theme, pcontext->hDC,iPart,iState,&rcPart,NULL);
406
407 /* Add a padding around the objects of the caption */
408 InflateRect(&rcPart, -(int)pcontext->wi.cyWindowBorders-BUTTON_GAP_SIZE,
409 -(int)pcontext->wi.cyWindowBorders-BUTTON_GAP_SIZE);
410
411 /* Draw the caption buttons */
412 if (pcontext->wi.dwStyle & WS_SYSMENU)
413 {
414 iState = pcontext->Active ? BUTTON_NORMAL : BUTTON_INACTIVE;
415
416 ThemeDrawCaptionButton(pcontext, CLOSEBUTTON, iState);
417 ThemeDrawCaptionButton(pcontext, MAXBUTTON, iState);
418 ThemeDrawCaptionButton(pcontext, MINBUTTON, iState);
419 ThemeDrawCaptionButton(pcontext, HELPBUTTON, iState);
420 }
421
422 rcPart.top += 3 ;
423
424 /* Draw the icon */
425 if (hIcon)
426 {
427 int IconHeight = GetSystemMetrics(SM_CYSMICON);
428 int IconWidth = GetSystemMetrics(SM_CXSMICON);
429 DrawIconEx(pcontext->hDC, rcPart.left, rcPart.top , hIcon, IconWidth, IconHeight, 0, NULL, DI_NORMAL);
430 rcPart.left += IconWidth + 4;
431 }
432
433 rcPart.right -= 4;
434
435 /* Draw the caption */
436 ThemeDrawCaptionText(pcontext, &rcPart, iPart, iState);
437 }
438
439 static void
440 ThemeDrawBorders(PDRAW_CONTEXT pcontext, RECT* prcCurrent)
441 {
442 RECT rcPart;
443 int iState = pcontext->Active ? FS_ACTIVE : FS_INACTIVE;
444
445 /* Draw the bottom border */
446 rcPart = *prcCurrent;
447 rcPart.top = rcPart.bottom - pcontext->wi.cyWindowBorders;
448 prcCurrent->bottom = rcPart.top;
449 DrawThemeBackground(pcontext->theme, pcontext->hDC, WP_FRAMEBOTTOM, iState, &rcPart, NULL);
450
451 /* Draw the left border */
452 rcPart = *prcCurrent;
453 rcPart.right = rcPart.left + pcontext->wi.cxWindowBorders ;
454 prcCurrent->left = rcPart.right;
455 DrawThemeBackground(pcontext->theme, pcontext->hDC,WP_FRAMELEFT, iState, &rcPart, NULL);
456
457 /* Draw the right border */
458 rcPart = *prcCurrent;
459 rcPart.left = rcPart.right - pcontext->wi.cxWindowBorders;
460 prcCurrent->right = rcPart.left;
461 DrawThemeBackground(pcontext->theme, pcontext->hDC,WP_FRAMERIGHT, iState, &rcPart, NULL);
462 }
463
464 static void
465 DrawClassicFrame(PDRAW_CONTEXT context, RECT* prcCurrent)
466 {
467 /* Draw outer edge */
468 if (UserHasWindowEdge(context->wi.dwStyle, context->wi.dwExStyle))
469 {
470 DrawEdge(context->hDC, prcCurrent, EDGE_RAISED, BF_RECT | BF_ADJUST);
471 }
472 else if (context->wi.dwExStyle & WS_EX_STATICEDGE)
473 {
474 DrawEdge(context->hDC, prcCurrent, BDR_SUNKENINNER, BF_RECT | BF_ADJUST | BF_FLAT);
475 }
476
477 /* Firstly the "thick" frame */
478 if ((context->wi.dwStyle & WS_THICKFRAME) && !(context->wi.dwStyle & WS_MINIMIZE))
479 {
480 INT Width =
481 (GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME)) *
482 GetSystemMetrics(SM_CXBORDER);
483 INT Height =
484 (GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME)) *
485 GetSystemMetrics(SM_CYBORDER);
486
487 SelectObject(context->hDC, GetSysColorBrush(
488 context->Active ? COLOR_ACTIVEBORDER : COLOR_INACTIVEBORDER));
489
490 /* Draw frame */
491 PatBlt(context->hDC, prcCurrent->left, prcCurrent->top,
492 prcCurrent->right - prcCurrent->left, Height, PATCOPY);
493 PatBlt(context->hDC, prcCurrent->left, prcCurrent->top,
494 Width, prcCurrent->bottom - prcCurrent->top, PATCOPY);
495 PatBlt(context->hDC, prcCurrent->left, prcCurrent->bottom - 1,
496 prcCurrent->right - prcCurrent->left, -Height, PATCOPY);
497 PatBlt(context->hDC, prcCurrent->right - 1, prcCurrent->top,
498 -Width, prcCurrent->bottom - prcCurrent->top, PATCOPY);
499
500 InflateRect(prcCurrent, -Width, -Height);
501 }
502
503 /* Now the other bit of the frame */
504 if (context->wi.dwStyle & (WS_DLGFRAME | WS_BORDER) || (context->wi.dwExStyle & WS_EX_DLGMODALFRAME))
505 {
506 INT Width = GetSystemMetrics(SM_CXBORDER);
507 INT Height = GetSystemMetrics(SM_CYBORDER);
508
509 SelectObject(context->hDC, GetSysColorBrush(
510 (context->wi.dwExStyle & (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE)) ? COLOR_3DFACE :
511 (context->wi.dwExStyle & WS_EX_STATICEDGE) ? COLOR_WINDOWFRAME :
512 (context->wi.dwStyle & (WS_DLGFRAME | WS_THICKFRAME)) ? COLOR_3DFACE :
513 COLOR_WINDOWFRAME));
514
515 /* Draw frame */
516 PatBlt(context->hDC, prcCurrent->left, prcCurrent->top,
517 prcCurrent->right - prcCurrent->left, Height, PATCOPY);
518 PatBlt(context->hDC, prcCurrent->left, prcCurrent->top,
519 Width, prcCurrent->bottom - prcCurrent->top, PATCOPY);
520 PatBlt(context->hDC, prcCurrent->left, prcCurrent->bottom - 1,
521 prcCurrent->right - prcCurrent->left, -Height, PATCOPY);
522 PatBlt(context->hDC, prcCurrent->right - 1, prcCurrent->top,
523 -Width, prcCurrent->bottom - prcCurrent->top, PATCOPY);
524
525 InflateRect(prcCurrent, -Width, -Height);
526 }
527 }
528
529 static void ThemeDrawMenuBar(PDRAW_CONTEXT pcontext, RECT* prcCurrent)
530 {
531 /* Let the window manager paint the menu */
532 prcCurrent->top += PaintMenuBar(pcontext->hWnd,
533 pcontext->hDC,
534 pcontext->wi.cxWindowBorders,
535 pcontext->wi.cxWindowBorders,
536 prcCurrent->top,
537 pcontext->Active);
538 }
539
540 static void ThemeDrawScrollBarsGrip(PDRAW_CONTEXT pcontext, RECT* prcCurrent)
541 {
542 RECT rcPart;
543 HWND hwndParent;
544 RECT ParentClientRect;
545 DWORD ParentStyle;
546
547 rcPart = *prcCurrent;
548
549 if (pcontext->wi.dwExStyle & WS_EX_LEFTSCROLLBAR)
550 rcPart.right = rcPart.left + GetSystemMetrics(SM_CXVSCROLL);
551 else
552 rcPart.left = rcPart.right - GetSystemMetrics(SM_CXVSCROLL);
553
554 rcPart.top = rcPart.bottom - GetSystemMetrics(SM_CYHSCROLL);
555
556 FillRect(pcontext->hDC, &rcPart, GetSysColorBrush(COLOR_BTNFACE));
557
558 hwndParent = GetParent(pcontext->hWnd);
559 GetClientRect(hwndParent, &ParentClientRect);
560 ParentStyle = GetWindowLongW(hwndParent, GWL_STYLE);
561
562 if (HASSIZEGRIP(pcontext->wi.dwStyle, pcontext->wi.dwExStyle, ParentStyle, pcontext->wi.rcWindow, ParentClientRect))
563 {
564 int iState;
565 if (pcontext->wi.dwExStyle & WS_EX_LEFTSCROLLBAR)
566 iState = pcontext->wi.dwExStyle & WS_EX_LEFTSCROLLBAR;
567 else
568 iState = SZB_RIGHTALIGN;
569 DrawThemeBackground(pcontext->scrolltheme, pcontext->hDC, SBP_SIZEBOX, iState, &rcPart, NULL);
570 }
571 }
572
573 static void
574 ThemePaintWindow(PDRAW_CONTEXT pcontext, RECT* prcCurrent, BOOL bDoDoubleBuffering)
575 {
576 if(!(pcontext->wi.dwStyle & WS_VISIBLE))
577 return;
578
579 if((pcontext->wi.dwStyle & WS_CAPTION)==WS_CAPTION)
580 {
581 if (bDoDoubleBuffering)
582 ThemeStartBufferedPaint(pcontext, prcCurrent->right, pcontext->CaptionHeight);
583 ThemeDrawCaption(pcontext, prcCurrent);
584 if (bDoDoubleBuffering)
585 ThemeEndBufferedPaint(pcontext, 0, 0, prcCurrent->right, pcontext->CaptionHeight);
586 ThemeDrawBorders(pcontext, prcCurrent);
587 }
588 else
589 {
590 DrawClassicFrame(pcontext, prcCurrent);
591 }
592
593 if(pcontext->wi.dwStyle & WS_MINIMIZE)
594 return;
595
596 if(HAS_MENU(pcontext->hWnd, pcontext->wi.dwStyle))
597 ThemeDrawMenuBar(pcontext, prcCurrent);
598
599 if (pcontext->wi.dwExStyle & WS_EX_CLIENTEDGE)
600 DrawEdge(pcontext->hDC, prcCurrent, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
601
602 if((pcontext->wi.dwStyle & WS_HSCROLL) && IsScrollBarVisible(pcontext->hWnd, OBJID_HSCROLL))
603 ThemeDrawScrollBar(pcontext, SB_HORZ , NULL);
604
605 if((pcontext->wi.dwStyle & WS_VSCROLL) && IsScrollBarVisible(pcontext->hWnd, OBJID_VSCROLL))
606 ThemeDrawScrollBar(pcontext, SB_VERT, NULL);
607
608 if((pcontext->wi.dwStyle & (WS_HSCROLL|WS_VSCROLL)) == (WS_HSCROLL|WS_VSCROLL) &&
609 IsScrollBarVisible(pcontext->hWnd, OBJID_HSCROLL) &&
610 IsScrollBarVisible(pcontext->hWnd, OBJID_VSCROLL))
611 {
612 ThemeDrawScrollBarsGrip(pcontext, prcCurrent);
613 }
614 }
615
616 /*
617 * Message handlers
618 */
619
620 static LRESULT
621 ThemeHandleNCPaint(HWND hWnd, HRGN hRgn)
622 {
623 DRAW_CONTEXT context;
624 RECT rcCurrent;
625
626 ThemeInitDrawContext(&context, hWnd, hRgn);
627
628 rcCurrent = context.wi.rcWindow;
629 OffsetRect( &rcCurrent, -context.wi.rcWindow.left, -context.wi.rcWindow.top);
630
631 ThemePaintWindow(&context, &rcCurrent, TRUE);
632 ThemeCleanupDrawContext(&context);
633
634 return 0;
635 }
636
637 static LRESULT
638 ThemeHandleNcMouseMove(HWND hWnd, DWORD ht, POINT* pt)
639 {
640 DRAW_CONTEXT context;
641 TRACKMOUSEEVENT tme;
642 DWORD style;
643 PWND_DATA pwndData;
644
645 /* First of all check if we have something to do here */
646 style = GetWindowLongW(hWnd, GWL_STYLE);
647 if((style & (WS_CAPTION|WS_HSCROLL|WS_VSCROLL))==0)
648 return 0;
649
650 /* Get theme data for this window */
651 pwndData = ThemeGetWndData(hWnd);
652 if (pwndData == NULL)
653 return 0;
654
655 /* Begin tracking in the non client area if we are not tracking yet */
656 tme.cbSize = sizeof(TRACKMOUSEEVENT);
657 tme.dwFlags = TME_QUERY;
658 tme.hwndTrack = hWnd;
659 TrackMouseEvent(&tme);
660 if (tme.dwFlags != (TME_LEAVE | TME_NONCLIENT))
661 {
662 tme.hwndTrack = hWnd;
663 tme.dwFlags = TME_LEAVE | TME_NONCLIENT;
664 TrackMouseEvent(&tme);
665 }
666
667 ThemeInitDrawContext(&context, hWnd, 0);
668 if (context.wi.dwStyle & WS_SYSMENU)
669 {
670 if (HT_ISBUTTON(ht) || HT_ISBUTTON(pwndData->lastHitTest))
671 ThemeDrawCaptionButtons(&context, ht, 0);
672 }
673
674 if (context.wi.dwStyle & WS_HSCROLL)
675 {
676 if (ht == HTHSCROLL || pwndData->lastHitTest == HTHSCROLL)
677 ThemeDrawScrollBar(&context, SB_HORZ , ht == HTHSCROLL ? pt : NULL);
678 }
679
680 if (context.wi.dwStyle & WS_VSCROLL)
681 {
682 if (ht == HTVSCROLL || pwndData->lastHitTest == HTVSCROLL)
683 ThemeDrawScrollBar(&context, SB_VERT, ht == HTVSCROLL ? pt : NULL);
684 }
685 ThemeCleanupDrawContext(&context);
686
687 pwndData->lastHitTest = ht;
688
689 return 0;
690 }
691
692 static LRESULT
693 ThemeHandleNcMouseLeave(HWND hWnd)
694 {
695 DRAW_CONTEXT context;
696 DWORD style;
697 PWND_DATA pwndData;
698
699 /* First of all check if we have something to do here */
700 style = GetWindowLongW(hWnd, GWL_STYLE);
701 if((style & (WS_CAPTION|WS_HSCROLL|WS_VSCROLL))==0)
702 return 0;
703
704 /* Get theme data for this window */
705 pwndData = ThemeGetWndData(hWnd);
706 if (pwndData == NULL)
707 return 0;
708
709 ThemeInitDrawContext(&context, hWnd, 0);
710 if (context.wi.dwStyle & WS_SYSMENU && HT_ISBUTTON(pwndData->lastHitTest))
711 ThemeDrawCaptionButtons(&context, 0, 0);
712
713 if (context.wi.dwStyle & WS_HSCROLL && pwndData->lastHitTest == HTHSCROLL)
714 ThemeDrawScrollBar(&context, SB_HORZ, NULL);
715
716 if (context.wi.dwStyle & WS_VSCROLL && pwndData->lastHitTest == HTVSCROLL)
717 ThemeDrawScrollBar(&context, SB_VERT, NULL);
718
719 ThemeCleanupDrawContext(&context);
720
721 pwndData->lastHitTest = HTNOWHERE;
722
723 return 0;
724 }
725
726 static VOID
727 ThemeHandleButton(HWND hWnd, WPARAM wParam)
728 {
729 MSG Msg;
730 BOOL Pressed = TRUE;
731 WPARAM SCMsg, ht;
732 ULONG Style;
733 DRAW_CONTEXT context;
734 PWND_DATA pwndData;
735
736 Style = GetWindowLongW(hWnd, GWL_STYLE);
737 if (!((Style & WS_CAPTION) && (Style & WS_SYSMENU)))
738 return ;
739
740 switch (wParam)
741 {
742 case HTCLOSE:
743 SCMsg = SC_CLOSE;
744 break;
745 case HTMINBUTTON:
746 if (!(Style & WS_MINIMIZEBOX))
747 return;
748 SCMsg = ((Style & WS_MINIMIZE) ? SC_RESTORE : SC_MINIMIZE);
749 break;
750 case HTMAXBUTTON:
751 if (!(Style & WS_MAXIMIZEBOX))
752 return;
753 SCMsg = ((Style & WS_MAXIMIZE) ? SC_RESTORE : SC_MAXIMIZE);
754 break;
755 default :
756 return;
757 }
758
759 /* Get theme data for this window */
760 pwndData = ThemeGetWndData(hWnd);
761 if (pwndData == NULL)
762 return;
763
764 ThemeInitDrawContext(&context, hWnd, 0);
765 ThemeDrawCaptionButtons(&context, 0, wParam);
766 pwndData->lastHitTest = wParam;
767
768 SetCapture(hWnd);
769
770 ht = wParam;
771
772 for (;;)
773 {
774 if (GetMessageW(&Msg, 0, WM_MOUSEFIRST, WM_MOUSELAST) <= 0)
775 break;
776
777 if (Msg.message == WM_LBUTTONUP)
778 break;
779
780 if (Msg.message != WM_MOUSEMOVE)
781 continue;
782
783 ht = SendMessage(hWnd, WM_NCHITTEST, 0, MAKELPARAM(Msg.pt.x, Msg.pt.y));
784 Pressed = (ht == wParam);
785
786 /* Only draw the buttons if the hit test changed */
787 if (ht != pwndData->lastHitTest &&
788 (HT_ISBUTTON(ht) || HT_ISBUTTON(pwndData->lastHitTest)))
789 {
790 ThemeDrawCaptionButtons(&context, 0, Pressed ? wParam: 0);
791 pwndData->lastHitTest = ht;
792 }
793 }
794
795 ThemeDrawCaptionButtons(&context, ht, 0);
796 ThemeCleanupDrawContext(&context);
797
798 ReleaseCapture();
799
800 if (Pressed)
801 SendMessageW(hWnd, WM_SYSCOMMAND, SCMsg, 0);
802 }
803
804
805 static LRESULT
806 DefWndNCHitTest(HWND hWnd, POINT Point)
807 {
808 RECT WindowRect;
809 POINT ClientPoint;
810 WINDOWINFO wi;
811
812 wi.cbSize = sizeof(wi);
813 GetWindowInfo(hWnd, &wi);
814
815 if (!PtInRect(&wi.rcWindow, Point))
816 {
817 return HTNOWHERE;
818 }
819 WindowRect = wi.rcWindow;
820
821 if (UserHasWindowEdge(wi.dwStyle, wi.dwExStyle))
822 {
823 LONG XSize, YSize;
824
825 InflateRect(&WindowRect, -(int)wi.cxWindowBorders, -(int)wi.cyWindowBorders);
826 XSize = GetSystemMetrics(SM_CXSIZE) * GetSystemMetrics(SM_CXBORDER);
827 YSize = GetSystemMetrics(SM_CYSIZE) * GetSystemMetrics(SM_CYBORDER);
828 if (!PtInRect(&WindowRect, Point))
829 {
830 BOOL ThickFrame;
831
832 ThickFrame = (wi.dwStyle & WS_THICKFRAME);
833 if (Point.y < WindowRect.top)
834 {
835 if(wi.dwStyle & WS_MINIMIZE)
836 return HTCAPTION;
837 if(!ThickFrame)
838 return HTBORDER;
839 if (Point.x < (WindowRect.left + XSize))
840 return HTTOPLEFT;
841 if (Point.x >= (WindowRect.right - XSize))
842 return HTTOPRIGHT;
843 return HTTOP;
844 }
845 if (Point.y >= WindowRect.bottom)
846 {
847 if(wi.dwStyle & WS_MINIMIZE)
848 return HTCAPTION;
849 if(!ThickFrame)
850 return HTBORDER;
851 if (Point.x < (WindowRect.left + XSize))
852 return HTBOTTOMLEFT;
853 if (Point.x >= (WindowRect.right - XSize))
854 return HTBOTTOMRIGHT;
855 return HTBOTTOM;
856 }
857 if (Point.x < WindowRect.left)
858 {
859 if(wi.dwStyle & WS_MINIMIZE)
860 return HTCAPTION;
861 if(!ThickFrame)
862 return HTBORDER;
863 if (Point.y < (WindowRect.top + YSize))
864 return HTTOPLEFT;
865 if (Point.y >= (WindowRect.bottom - YSize))
866 return HTBOTTOMLEFT;
867 return HTLEFT;
868 }
869 if (Point.x >= WindowRect.right)
870 {
871 if(wi.dwStyle & WS_MINIMIZE)
872 return HTCAPTION;
873 if(!ThickFrame)
874 return HTBORDER;
875 if (Point.y < (WindowRect.top + YSize))
876 return HTTOPRIGHT;
877 if (Point.y >= (WindowRect.bottom - YSize))
878 return HTBOTTOMRIGHT;
879 return HTRIGHT;
880 }
881 }
882 }
883 else
884 {
885 if (wi.dwExStyle & WS_EX_STATICEDGE)
886 InflateRect(&WindowRect, -GetSystemMetrics(SM_CXBORDER),
887 -GetSystemMetrics(SM_CYBORDER));
888 if (!PtInRect(&WindowRect, Point))
889 return HTBORDER;
890 }
891
892 if ((wi.dwStyle & WS_CAPTION) == WS_CAPTION)
893 {
894 if (wi.dwExStyle & WS_EX_TOOLWINDOW)
895 WindowRect.top += GetSystemMetrics(SM_CYSMCAPTION);
896 else
897 WindowRect.top += GetSystemMetrics(SM_CYCAPTION);
898
899 if (!PtInRect(&WindowRect, Point))
900 {
901 if (wi.dwStyle & WS_SYSMENU)
902 {
903 PWND_DATA pwndData = ThemeGetWndData(hWnd);
904
905 if (!(wi.dwExStyle & WS_EX_TOOLWINDOW))
906 {
907 // if(!(wi.dwExStyle & WS_EX_DLGMODALFRAME))
908 // FIXME: The real test should check whether there is
909 // an icon for the system window, and if so, do the
910 // rect.left increase.
911 // See win32ss/user/user32/windows/nonclient.c!DefWndNCHitTest
912 // and win32ss/user/ntuser/nonclient.c!GetNCHitEx which does
913 // the test better.
914 WindowRect.left += GetSystemMetrics(SM_CXSMICON);
915 }
916
917 if (pwndData)
918 {
919 POINT pt = {Point.x - wi.rcWindow.left, Point.y - wi.rcWindow.top};
920 if (PtInRect(&pwndData->rcCaptionButtons[CLOSEBUTTON], pt))
921 return HTCLOSE;
922 if (PtInRect(&pwndData->rcCaptionButtons[MAXBUTTON], pt))
923 return HTMAXBUTTON;
924 if (PtInRect(&pwndData->rcCaptionButtons[MINBUTTON], pt))
925 return HTMINBUTTON;
926 }
927 }
928 if (Point.x < WindowRect.left)
929 return HTSYSMENU;
930 return HTCAPTION;
931 }
932 }
933
934 if(!(wi.dwStyle & WS_MINIMIZE))
935 {
936 HMENU menu;
937
938 ClientPoint = Point;
939 ScreenToClient(hWnd, &ClientPoint);
940 GetClientRect(hWnd, &wi.rcClient);
941
942 if (PtInRect(&wi.rcClient, ClientPoint))
943 {
944 return HTCLIENT;
945 }
946
947 if ((menu = GetMenu(hWnd)) && !(wi.dwStyle & WS_CHILD))
948 {
949 if (Point.x > 0 && Point.x < WindowRect.right && ClientPoint.y < 0)
950 return HTMENU;
951 }
952
953 if (wi.dwExStyle & WS_EX_CLIENTEDGE)
954 {
955 InflateRect(&WindowRect, -2 * GetSystemMetrics(SM_CXBORDER),
956 -2 * GetSystemMetrics(SM_CYBORDER));
957 }
958
959 if ((wi.dwStyle & WS_VSCROLL) && (wi.dwStyle & WS_HSCROLL) &&
960 (WindowRect.bottom - WindowRect.top) > GetSystemMetrics(SM_CYHSCROLL))
961 {
962 RECT ParentRect, TempRect = WindowRect, TempRect2 = WindowRect;
963 HWND Parent = GetParent(hWnd);
964
965 TempRect.bottom -= GetSystemMetrics(SM_CYHSCROLL);
966 if ((wi.dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
967 TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL);
968 else
969 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL);
970 if (PtInRect(&TempRect, Point))
971 return HTVSCROLL;
972
973 TempRect2.top = TempRect2.bottom - GetSystemMetrics(SM_CYHSCROLL);
974 if ((wi.dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
975 TempRect2.left += GetSystemMetrics(SM_CXVSCROLL);
976 else
977 TempRect2.right -= GetSystemMetrics(SM_CXVSCROLL);
978 if (PtInRect(&TempRect2, Point))
979 return HTHSCROLL;
980
981 TempRect.top = TempRect2.top;
982 TempRect.bottom = TempRect2.bottom;
983 if(Parent)
984 GetClientRect(Parent, &ParentRect);
985 if (PtInRect(&TempRect, Point) && HASSIZEGRIP(wi.dwStyle, wi.dwExStyle,
986 GetWindowLongW(Parent, GWL_STYLE), wi.rcWindow, ParentRect))
987 {
988 if ((wi.dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
989 return HTBOTTOMLEFT;
990 else
991 return HTBOTTOMRIGHT;
992 }
993 }
994 else
995 {
996 if (wi.dwStyle & WS_VSCROLL)
997 {
998 RECT TempRect = WindowRect;
999
1000 if ((wi.dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1001 TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL);
1002 else
1003 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL);
1004 if (PtInRect(&TempRect, Point))
1005 return HTVSCROLL;
1006 }
1007 else if (wi.dwStyle & WS_HSCROLL)
1008 {
1009 RECT TempRect = WindowRect;
1010 TempRect.top = TempRect.bottom - GetSystemMetrics(SM_CYHSCROLL);
1011 if (PtInRect(&TempRect, Point))
1012 return HTHSCROLL;
1013 }
1014 }
1015 }
1016
1017 return HTNOWHERE;
1018 }
1019
1020 LRESULT CALLBACK
1021 ThemeWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, WNDPROC DefWndProc)
1022 {
1023 switch(Msg)
1024 {
1025 case WM_NCPAINT:
1026 return ThemeHandleNCPaint(hWnd, (HRGN)wParam);
1027 //
1028 // WM_NCUAHDRAWCAPTION : wParam are DC_* flags.
1029 //
1030 case WM_NCUAHDRAWCAPTION:
1031 //
1032 // WM_NCUAHDRAWFRAME : wParam is HDC, lParam are DC_ACTIVE and or DC_REDRAWHUNGWND.
1033 //
1034 case WM_NCUAHDRAWFRAME:
1035 case WM_NCACTIVATE:
1036
1037 if ((GetWindowLongW(hWnd, GWL_STYLE) & WS_CAPTION) != WS_CAPTION)
1038 return TRUE;
1039
1040 ThemeHandleNCPaint(hWnd, (HRGN)1);
1041 return TRUE;
1042 case WM_NCMOUSEMOVE:
1043 {
1044 POINT Point;
1045 Point.x = GET_X_LPARAM(lParam);
1046 Point.y = GET_Y_LPARAM(lParam);
1047 return ThemeHandleNcMouseMove(hWnd, wParam, &Point);
1048 }
1049 case WM_NCMOUSELEAVE:
1050 return ThemeHandleNcMouseLeave(hWnd);
1051 case WM_NCLBUTTONDOWN:
1052 switch (wParam)
1053 {
1054 case HTMINBUTTON:
1055 case HTMAXBUTTON:
1056 case HTCLOSE:
1057 {
1058 ThemeHandleButton(hWnd, wParam);
1059 return 0;
1060 }
1061 default:
1062 return DefWndProc(hWnd, Msg, wParam, lParam);
1063 }
1064 case WM_NCHITTEST:
1065 {
1066 POINT Point;
1067 Point.x = GET_X_LPARAM(lParam);
1068 Point.y = GET_Y_LPARAM(lParam);
1069 return DefWndNCHitTest(hWnd, Point);
1070 }
1071 case WM_SYSCOMMAND:
1072 {
1073 if((wParam & 0xfff0) == SC_VSCROLL ||
1074 (wParam & 0xfff0) == SC_HSCROLL)
1075 {
1076 POINT Pt;
1077 Pt.x = (short)LOWORD(lParam);
1078 Pt.y = (short)HIWORD(lParam);
1079 NC_TrackScrollBar(hWnd, wParam, Pt);
1080 return 0;
1081 }
1082 else
1083 {
1084 return DefWndProc(hWnd, Msg, wParam, lParam);
1085 }
1086 }
1087 default:
1088 return DefWndProc(hWnd, Msg, wParam, lParam);
1089 }
1090 }
1091
1092 HRESULT WINAPI DrawNCPreview(HDC hDC,
1093 DWORD DNCP_Flag,
1094 LPRECT prcPreview,
1095 LPCWSTR pszThemeFileName,
1096 LPCWSTR pszColorName,
1097 LPCWSTR pszSizeName,
1098 PNONCLIENTMETRICSW pncMetrics,
1099 COLORREF* lpaRgbValues)
1100 {
1101 WNDCLASSEXW DummyPreviewWindowClass;
1102 HWND hwndDummy;
1103 HRESULT hres;
1104 HTHEMEFILE hThemeFile;
1105 DRAW_CONTEXT context;
1106 RECT rcCurrent;
1107
1108 /* FIXME: We also need to implement drawing the rest of the preview windows
1109 * and make use of the ncmetrics and colors passed as parameters */
1110
1111 /* Create a dummy window that will be used to trick the paint funtions */
1112 memset(&DummyPreviewWindowClass, 0, sizeof(DummyPreviewWindowClass));
1113 DummyPreviewWindowClass.cbSize = sizeof(DummyPreviewWindowClass);
1114 DummyPreviewWindowClass.lpszClassName = L"DummyPreviewWindowClass";
1115 DummyPreviewWindowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
1116 DummyPreviewWindowClass.hInstance = hDllInst;
1117 DummyPreviewWindowClass.lpfnWndProc = DefWindowProcW;
1118 if (!RegisterClassExW(&DummyPreviewWindowClass))
1119 return E_FAIL;
1120
1121 hwndDummy = CreateWindowExW(0, L"DummyPreviewWindowClass", L"Active window", WS_OVERLAPPEDWINDOW,30,30,300,150,0,0,hDllInst,NULL);
1122 if (!hwndDummy)
1123 return E_FAIL;
1124
1125 hres = OpenThemeFile(pszThemeFileName, pszColorName, pszSizeName, &hThemeFile,0);
1126 if (FAILED(hres))
1127 return hres;
1128
1129 /* Initialize the special draw context for the preview */
1130 context.hDC = hDC;
1131 context.hWnd = hwndDummy;
1132 context.theme = OpenThemeDataFromFile(hThemeFile, hwndDummy, L"WINDOW", 0);
1133 if (!context.theme)
1134 return E_FAIL;
1135 context.scrolltheme = OpenThemeDataFromFile(hThemeFile, hwndDummy, L"SCROLLBAR", 0);
1136 if (!context.scrolltheme)
1137 return E_FAIL;
1138 context.Active = TRUE;
1139 context.wi.cbSize = sizeof(context.wi);
1140 if (!GetWindowInfo(hwndDummy, &context.wi))
1141 return E_FAIL;
1142 context.wi.dwStyle |= WS_VISIBLE;
1143 context.CaptionHeight = context.wi.cyWindowBorders;
1144 context.CaptionHeight += GetSystemMetrics(context.wi.dwExStyle & WS_EX_TOOLWINDOW ? SM_CYSMCAPTION : SM_CYCAPTION );
1145 context.hRgn = CreateRectRgnIndirect(&context.wi.rcWindow);
1146
1147 /* Paint the window on the preview hDC */
1148 rcCurrent = context.wi.rcWindow;
1149 OffsetRect( &rcCurrent, -context.wi.rcWindow.left, -context.wi.rcWindow.top);
1150 SetViewportOrgEx(hDC, context.wi.rcWindow.left, context.wi.rcWindow.top, NULL);
1151 ThemeCalculateCaptionButtonsPos(hwndDummy, context.theme);
1152 ThemePaintWindow(&context, &rcCurrent, FALSE);
1153 SetViewportOrgEx(hDC, 0, 0, NULL);
1154
1155 context.hDC = NULL;
1156 CloseThemeData (context.theme);
1157 CloseThemeData (context.scrolltheme);
1158 ThemeCleanupDrawContext(&context);
1159
1160 /* Cleanup */
1161 DestroyWindow(hwndDummy);
1162 UnregisterClassW(L"DummyPreviewWindowClass", hDllInst);
1163
1164 return S_OK;
1165 }