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