xref: /reactos/dll/win32/uxtheme/nonclient.c (revision 7353af1e)
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     HMENU SysMenu;
281     UINT MenuState;
282     PWND_DATA pwndData = ThemeGetWndData(pcontext->hWnd);
283     if (!pwndData)
284         return;
285 
286     switch(buttonId)
287     {
288     case CLOSEBUTTON:
289         SysMenu = GetSystemMenu(pcontext->hWnd, FALSE);
290         MenuState = GetMenuState(SysMenu, SC_CLOSE, MF_BYCOMMAND);
291         if (!(pcontext->wi.dwStyle & WS_SYSMENU) || (MenuState & (MF_GRAYED | MF_DISABLED)) || pcontext->wi.dwStyle & CS_NOCLOSE)
292         {
293             iStateId = (pcontext->Active ? BUTTON_DISABLED : BUTTON_INACTIVE_DISABLED);
294         }
295 
296         iPartId = pcontext->wi.dwExStyle & WS_EX_TOOLWINDOW ? WP_SMALLCLOSEBUTTON : WP_CLOSEBUTTON;
297         break;
298 
299     case MAXBUTTON:
300         if (!(pcontext->wi.dwStyle & WS_MAXIMIZEBOX))
301         {
302             if (!(pcontext->wi.dwStyle & WS_MINIMIZEBOX))
303                 return;
304             else
305                 iStateId = (pcontext->Active ? BUTTON_DISABLED : BUTTON_INACTIVE_DISABLED);
306         }
307 
308         iPartId = pcontext->wi.dwStyle & WS_MAXIMIZE ? WP_RESTOREBUTTON : WP_MAXBUTTON;
309         break;
310 
311     case MINBUTTON:
312         if (!(pcontext->wi.dwStyle & WS_MINIMIZEBOX))
313         {
314             if (!(pcontext->wi.dwStyle & WS_MAXIMIZEBOX))
315                 return;
316             else
317                 iStateId = (pcontext->Active ? BUTTON_DISABLED : BUTTON_INACTIVE_DISABLED);
318         }
319 
320         iPartId = pcontext->wi.dwStyle & WS_MINIMIZE ? WP_RESTOREBUTTON : WP_MINBUTTON;
321         break;
322 
323     default:
324         //FIXME: Implement Help Button
325         return;
326     }
327 
328     if (prcCurrent)
329         prcCurrent->right = pwndData->rcCaptionButtons[buttonId].left;
330 
331     DrawThemeBackground(pcontext->theme, pcontext->hDC, iPartId, iStateId, &pwndData->rcCaptionButtons[buttonId], NULL);
332 }
333 
334 static DWORD
335 ThemeGetButtonState(DWORD htCurrect, DWORD htHot, DWORD htDown, BOOL Active)
336 {
337     if (htHot == htCurrect)
338         return (Active ? BUTTON_HOT : BUTTON_INACTIVE_HOT);
339     if (htDown == htCurrect)
340         return (Active ? BUTTON_PRESSED : BUTTON_INACTIVE_PRESSED);
341 
342     return (Active ? BUTTON_NORMAL : BUTTON_INACTIVE);
343 }
344 
345 /* Used only from mouse event handlers */
346 static void
347 ThemeDrawCaptionButtons(PDRAW_CONTEXT pcontext, DWORD htHot, DWORD htDown)
348 {
349     /* Draw the buttons */
350     ThemeDrawCaptionButton(pcontext, NULL, CLOSEBUTTON,
351                            ThemeGetButtonState(HTCLOSE, htHot, htDown, pcontext->Active));
352     ThemeDrawCaptionButton(pcontext, NULL, MAXBUTTON,
353                            ThemeGetButtonState(HTMAXBUTTON, htHot, htDown, pcontext->Active));
354     ThemeDrawCaptionButton(pcontext, NULL, MINBUTTON,
355                            ThemeGetButtonState(HTMINBUTTON, htHot, htDown, pcontext->Active));
356     ThemeDrawCaptionButton(pcontext, NULL, HELPBUTTON,
357                            ThemeGetButtonState(HTHELP, htHot, htDown, pcontext->Active));
358 }
359 
360 /* Used from WM_NCPAINT and WM_NCACTIVATE handlers */
361 static void
362 ThemeDrawCaption(PDRAW_CONTEXT pcontext, RECT* prcCurrent)
363 {
364     RECT rcPart;
365     int iPart, iState;
366     HICON hIcon;
367 
368     // See also win32ss/user/ntuser/nonclient.c!UserDrawCaptionBar
369     // and win32ss/user/ntuser/nonclient.c!UserDrawCaption
370     if ((pcontext->wi.dwStyle & WS_SYSMENU) && !(pcontext->wi.dwExStyle & WS_EX_TOOLWINDOW))
371         hIcon = UserGetWindowIcon(pcontext);
372     else
373         hIcon = NULL;
374 
375     /* Get the caption part and state id */
376     if (pcontext->wi.dwStyle & WS_MINIMIZE)
377         iPart = WP_MINCAPTION;
378     else if (pcontext->wi.dwExStyle & WS_EX_TOOLWINDOW)
379         iPart = WP_SMALLCAPTION;
380     else if (pcontext->wi.dwStyle & WS_MAXIMIZE)
381         iPart = WP_MAXCAPTION;
382     else
383         iPart = WP_CAPTION;
384 
385     iState = pcontext->Active ? FS_ACTIVE : FS_INACTIVE;
386 
387     /* Draw the caption background */
388     rcPart = *prcCurrent;
389     rcPart.bottom = rcPart.top + pcontext->CaptionHeight;
390     prcCurrent->top = rcPart.bottom;
391     DrawThemeBackground(pcontext->theme, pcontext->hDC,iPart,iState,&rcPart,NULL);
392 
393     /* Add a padding around the objects of the caption */
394     InflateRect(&rcPart, -(int)pcontext->wi.cyWindowBorders-BUTTON_GAP_SIZE,
395                          -(int)pcontext->wi.cyWindowBorders-BUTTON_GAP_SIZE);
396 
397     /* Draw the caption buttons */
398     if (pcontext->wi.dwStyle & WS_SYSMENU)
399     {
400         iState = pcontext->Active ? BUTTON_NORMAL : BUTTON_INACTIVE;
401 
402         ThemeDrawCaptionButton(pcontext, &rcPart, CLOSEBUTTON, iState);
403         ThemeDrawCaptionButton(pcontext, &rcPart, MAXBUTTON, iState);
404         ThemeDrawCaptionButton(pcontext, &rcPart, MINBUTTON, iState);
405         ThemeDrawCaptionButton(pcontext, &rcPart, HELPBUTTON, iState);
406     }
407 
408     rcPart.top += 3 ;
409 
410     /* Draw the icon */
411     if (hIcon)
412     {
413         int IconHeight = GetSystemMetrics(SM_CYSMICON);
414         int IconWidth = GetSystemMetrics(SM_CXSMICON);
415         DrawIconEx(pcontext->hDC, rcPart.left, rcPart.top , hIcon, IconWidth, IconHeight, 0, NULL, DI_NORMAL);
416         rcPart.left += IconWidth + 4;
417     }
418 
419     rcPart.right -= 4;
420 
421     /* Draw the caption */
422     ThemeDrawCaptionText(pcontext, &rcPart, iPart, iState);
423 }
424 
425 static void
426 ThemeDrawBorders(PDRAW_CONTEXT pcontext, RECT* prcCurrent)
427 {
428     RECT rcPart;
429     int iState = pcontext->Active ? FS_ACTIVE : FS_INACTIVE;
430 
431     /* Draw the bottom border */
432     rcPart = *prcCurrent;
433     rcPart.top = rcPart.bottom - pcontext->wi.cyWindowBorders;
434     prcCurrent->bottom = rcPart.top;
435     DrawThemeBackground(pcontext->theme, pcontext->hDC, WP_FRAMEBOTTOM, iState, &rcPart, NULL);
436 
437     /* Draw the left border */
438     rcPart = *prcCurrent;
439     rcPart.right = rcPart.left + pcontext->wi.cxWindowBorders ;
440     prcCurrent->left = rcPart.right;
441     DrawThemeBackground(pcontext->theme, pcontext->hDC,WP_FRAMELEFT, iState, &rcPart, NULL);
442 
443     /* Draw the right border */
444     rcPart = *prcCurrent;
445     rcPart.left = rcPart.right - pcontext->wi.cxWindowBorders;
446     prcCurrent->right = rcPart.left;
447     DrawThemeBackground(pcontext->theme, pcontext->hDC,WP_FRAMERIGHT, iState, &rcPart, NULL);
448 }
449 
450 static void
451 DrawClassicFrame(PDRAW_CONTEXT context, RECT* prcCurrent)
452 {
453     /* Draw outer edge */
454     if (UserHasWindowEdge(context->wi.dwStyle, context->wi.dwExStyle))
455     {
456         DrawEdge(context->hDC, prcCurrent, EDGE_RAISED, BF_RECT | BF_ADJUST);
457     }
458     else if (context->wi.dwExStyle & WS_EX_STATICEDGE)
459     {
460         DrawEdge(context->hDC, prcCurrent, BDR_SUNKENINNER, BF_RECT | BF_ADJUST | BF_FLAT);
461     }
462 
463     /* Firstly the "thick" frame */
464     if ((context->wi.dwStyle & WS_THICKFRAME) && !(context->wi.dwStyle & WS_MINIMIZE))
465     {
466         INT Width =
467             (GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME)) *
468             GetSystemMetrics(SM_CXBORDER);
469         INT Height =
470             (GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME)) *
471             GetSystemMetrics(SM_CYBORDER);
472 
473         SelectObject(context->hDC, GetSysColorBrush(
474                      context->Active ? COLOR_ACTIVEBORDER : COLOR_INACTIVEBORDER));
475 
476         /* Draw frame */
477         PatBlt(context->hDC, prcCurrent->left, prcCurrent->top,
478                prcCurrent->right - prcCurrent->left, Height, PATCOPY);
479         PatBlt(context->hDC, prcCurrent->left, prcCurrent->top,
480                Width, prcCurrent->bottom - prcCurrent->top, PATCOPY);
481         PatBlt(context->hDC, prcCurrent->left, prcCurrent->bottom - 1,
482                prcCurrent->right - prcCurrent->left, -Height, PATCOPY);
483         PatBlt(context->hDC, prcCurrent->right - 1, prcCurrent->top,
484                -Width, prcCurrent->bottom - prcCurrent->top, PATCOPY);
485 
486         InflateRect(prcCurrent, -Width, -Height);
487     }
488 
489     /* Now the other bit of the frame */
490     if (context->wi.dwStyle & (WS_DLGFRAME | WS_BORDER) || (context->wi.dwExStyle & WS_EX_DLGMODALFRAME))
491     {
492         INT Width = GetSystemMetrics(SM_CXBORDER);
493         INT Height = GetSystemMetrics(SM_CYBORDER);
494 
495         SelectObject(context->hDC, GetSysColorBrush(
496             (context->wi.dwExStyle & (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE)) ? COLOR_3DFACE :
497             (context->wi.dwExStyle & WS_EX_STATICEDGE) ? COLOR_WINDOWFRAME :
498             (context->wi.dwStyle & (WS_DLGFRAME | WS_THICKFRAME)) ? COLOR_3DFACE :
499             COLOR_WINDOWFRAME));
500 
501         /* Draw frame */
502         PatBlt(context->hDC, prcCurrent->left, prcCurrent->top,
503                prcCurrent->right - prcCurrent->left, Height, PATCOPY);
504         PatBlt(context->hDC, prcCurrent->left, prcCurrent->top,
505                Width, prcCurrent->bottom - prcCurrent->top, PATCOPY);
506         PatBlt(context->hDC, prcCurrent->left, prcCurrent->bottom - 1,
507                prcCurrent->right - prcCurrent->left, -Height, PATCOPY);
508         PatBlt(context->hDC, prcCurrent->right - 1, prcCurrent->top,
509               -Width, prcCurrent->bottom - prcCurrent->top, PATCOPY);
510 
511         InflateRect(prcCurrent, -Width, -Height);
512     }
513 }
514 
515 static void ThemeDrawMenuBar(PDRAW_CONTEXT pcontext, RECT* prcCurrent)
516 {
517     /* Let the window manager paint the menu */
518     prcCurrent->top += PaintMenuBar(pcontext->hWnd,
519                                     pcontext->hDC,
520                                     pcontext->wi.cxWindowBorders,
521                                     pcontext->wi.cxWindowBorders,
522                                     prcCurrent->top,
523                                     pcontext->Active);
524 }
525 
526 static void ThemeDrawScrollBarsGrip(PDRAW_CONTEXT pcontext, RECT* prcCurrent)
527 {
528     RECT rcPart;
529     HWND hwndParent;
530     RECT ParentClientRect;
531     DWORD ParentStyle;
532 
533     rcPart = *prcCurrent;
534 
535     if (pcontext->wi.dwExStyle & WS_EX_LEFTSCROLLBAR)
536        rcPart.right = rcPart.left + GetSystemMetrics(SM_CXVSCROLL);
537     else
538        rcPart.left = rcPart.right - GetSystemMetrics(SM_CXVSCROLL);
539 
540     rcPart.top = rcPart.bottom - GetSystemMetrics(SM_CYHSCROLL);
541 
542     FillRect(pcontext->hDC, &rcPart, GetSysColorBrush(COLOR_BTNFACE));
543 
544     hwndParent = GetParent(pcontext->hWnd);
545     GetClientRect(hwndParent, &ParentClientRect);
546     ParentStyle = GetWindowLongW(hwndParent, GWL_STYLE);
547 
548     if (HASSIZEGRIP(pcontext->wi.dwStyle, pcontext->wi.dwExStyle, ParentStyle, pcontext->wi.rcWindow, ParentClientRect))
549     {
550         int iState;
551         if (pcontext->wi.dwExStyle & WS_EX_LEFTSCROLLBAR)
552             iState = pcontext->wi.dwExStyle & WS_EX_LEFTSCROLLBAR;
553         else
554             iState = SZB_RIGHTALIGN;
555         DrawThemeBackground(pcontext->scrolltheme, pcontext->hDC, SBP_SIZEBOX, iState, &rcPart, NULL);
556     }
557 }
558 
559 static void
560 ThemePaintWindow(PDRAW_CONTEXT pcontext, RECT* prcCurrent, BOOL bDoDoubleBuffering)
561 {
562     if(!(pcontext->wi.dwStyle & WS_VISIBLE))
563         return;
564 
565     if((pcontext->wi.dwStyle & WS_CAPTION)==WS_CAPTION)
566     {
567         if (bDoDoubleBuffering)
568             ThemeStartBufferedPaint(pcontext, prcCurrent->right, pcontext->CaptionHeight);
569         ThemeDrawCaption(pcontext, prcCurrent);
570         if (bDoDoubleBuffering)
571             ThemeEndBufferedPaint(pcontext, 0, 0, prcCurrent->right, pcontext->CaptionHeight);
572         ThemeDrawBorders(pcontext, prcCurrent);
573     }
574     else
575     {
576         DrawClassicFrame(pcontext, prcCurrent);
577     }
578 
579     if(pcontext->wi.dwStyle & WS_MINIMIZE)
580         return;
581 
582     if(HAS_MENU(pcontext->hWnd, pcontext->wi.dwStyle))
583         ThemeDrawMenuBar(pcontext, prcCurrent);
584 
585     if (pcontext->wi.dwExStyle & WS_EX_CLIENTEDGE)
586         DrawEdge(pcontext->hDC, prcCurrent, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
587 
588     if((pcontext->wi.dwStyle & WS_HSCROLL) && IsScrollBarVisible(pcontext->hWnd, OBJID_HSCROLL))
589         ThemeDrawScrollBar(pcontext, SB_HORZ , NULL);
590 
591     if((pcontext->wi.dwStyle & WS_VSCROLL) && IsScrollBarVisible(pcontext->hWnd, OBJID_VSCROLL))
592         ThemeDrawScrollBar(pcontext, SB_VERT, NULL);
593 
594     if((pcontext->wi.dwStyle & (WS_HSCROLL|WS_VSCROLL)) == (WS_HSCROLL|WS_VSCROLL) &&
595        IsScrollBarVisible(pcontext->hWnd, OBJID_HSCROLL) &&
596        IsScrollBarVisible(pcontext->hWnd, OBJID_VSCROLL))
597     {
598         ThemeDrawScrollBarsGrip(pcontext, prcCurrent);
599     }
600 }
601 
602 /*
603  * Message handlers
604  */
605 
606 static LRESULT
607 ThemeHandleNCPaint(HWND hWnd, HRGN hRgn)
608 {
609     DRAW_CONTEXT context;
610     RECT rcCurrent;
611 
612     ThemeInitDrawContext(&context, hWnd, hRgn);
613 
614     rcCurrent = context.wi.rcWindow;
615     OffsetRect( &rcCurrent, -context.wi.rcWindow.left, -context.wi.rcWindow.top);
616 
617     ThemePaintWindow(&context, &rcCurrent, TRUE);
618     ThemeCleanupDrawContext(&context);
619 
620     return 0;
621 }
622 
623 static LRESULT
624 ThemeHandleNcMouseMove(HWND hWnd, DWORD ht, POINT* pt)
625 {
626     DRAW_CONTEXT context;
627     TRACKMOUSEEVENT tme;
628     DWORD style;
629     PWND_DATA pwndData;
630 
631     /* First of all check if we have something to do here */
632     style = GetWindowLongW(hWnd, GWL_STYLE);
633     if((style & (WS_CAPTION|WS_HSCROLL|WS_VSCROLL))==0)
634         return 0;
635 
636     /* Get theme data for this window */
637     pwndData = ThemeGetWndData(hWnd);
638     if (pwndData == NULL)
639         return 0;
640 
641     /* Begin tracking in the non client area if we are not tracking yet */
642     tme.cbSize = sizeof(TRACKMOUSEEVENT);
643     tme.dwFlags = TME_QUERY;
644     tme.hwndTrack  = hWnd;
645     TrackMouseEvent(&tme);
646     if (tme.dwFlags != (TME_LEAVE | TME_NONCLIENT))
647     {
648         tme.hwndTrack  = hWnd;
649         tme.dwFlags = TME_LEAVE | TME_NONCLIENT;
650         TrackMouseEvent(&tme);
651     }
652 
653     ThemeInitDrawContext(&context, hWnd, 0);
654     if (context.wi.dwStyle & WS_SYSMENU)
655     {
656         if (HT_ISBUTTON(ht) || HT_ISBUTTON(pwndData->lastHitTest))
657             ThemeDrawCaptionButtons(&context, ht, 0);
658     }
659 
660    if (context.wi.dwStyle & WS_HSCROLL)
661    {
662        if (ht == HTHSCROLL || pwndData->lastHitTest == HTHSCROLL)
663            ThemeDrawScrollBar(&context, SB_HORZ , ht == HTHSCROLL ? pt : NULL);
664    }
665 
666     if (context.wi.dwStyle & WS_VSCROLL)
667     {
668         if (ht == HTVSCROLL || pwndData->lastHitTest == HTVSCROLL)
669             ThemeDrawScrollBar(&context, SB_VERT, ht == HTVSCROLL ? pt : NULL);
670     }
671     ThemeCleanupDrawContext(&context);
672 
673     pwndData->lastHitTest = ht;
674 
675     return 0;
676 }
677 
678 static LRESULT
679 ThemeHandleNcMouseLeave(HWND hWnd)
680 {
681     DRAW_CONTEXT context;
682     DWORD style;
683     PWND_DATA pwndData;
684 
685     /* First of all check if we have something to do here */
686     style = GetWindowLongW(hWnd, GWL_STYLE);
687     if((style & (WS_CAPTION|WS_HSCROLL|WS_VSCROLL))==0)
688         return 0;
689 
690     /* Get theme data for this window */
691     pwndData = ThemeGetWndData(hWnd);
692     if (pwndData == NULL)
693         return 0;
694 
695     ThemeInitDrawContext(&context, hWnd, 0);
696     if (context.wi.dwStyle & WS_SYSMENU && HT_ISBUTTON(pwndData->lastHitTest))
697         ThemeDrawCaptionButtons(&context, 0, 0);
698 
699    if (context.wi.dwStyle & WS_HSCROLL && pwndData->lastHitTest == HTHSCROLL)
700         ThemeDrawScrollBar(&context, SB_HORZ,  NULL);
701 
702     if (context.wi.dwStyle & WS_VSCROLL && pwndData->lastHitTest == HTVSCROLL)
703         ThemeDrawScrollBar(&context, SB_VERT, NULL);
704 
705     ThemeCleanupDrawContext(&context);
706 
707     pwndData->lastHitTest = HTNOWHERE;
708 
709     return 0;
710 }
711 
712 static VOID
713 ThemeHandleButton(HWND hWnd, WPARAM wParam)
714 {
715     MSG Msg;
716     BOOL Pressed = TRUE;
717     WPARAM SCMsg, ht;
718     ULONG Style;
719     DRAW_CONTEXT context;
720     PWND_DATA pwndData;
721 
722     Style = GetWindowLongW(hWnd, GWL_STYLE);
723     if (!((Style & WS_CAPTION) && (Style & WS_SYSMENU)))
724         return ;
725 
726     switch (wParam)
727     {
728         case HTCLOSE:
729             SCMsg = SC_CLOSE;
730             break;
731         case HTMINBUTTON:
732             if (!(Style & WS_MINIMIZEBOX))
733                 return;
734             SCMsg = ((Style & WS_MINIMIZE) ? SC_RESTORE : SC_MINIMIZE);
735             break;
736         case HTMAXBUTTON:
737             if (!(Style & WS_MAXIMIZEBOX))
738                 return;
739             SCMsg = ((Style & WS_MAXIMIZE) ? SC_RESTORE : SC_MAXIMIZE);
740             break;
741         default :
742             return;
743     }
744 
745     /* Get theme data for this window */
746     pwndData = ThemeGetWndData(hWnd);
747     if (pwndData == NULL)
748         return;
749 
750     ThemeInitDrawContext(&context, hWnd, 0);
751     ThemeDrawCaptionButtons(&context, 0,  wParam);
752     pwndData->lastHitTest = wParam;
753 
754     SetCapture(hWnd);
755 
756     ht = wParam;
757 
758     for (;;)
759     {
760         if (GetMessageW(&Msg, 0, WM_MOUSEFIRST, WM_MOUSELAST) <= 0)
761             break;
762 
763         if (Msg.message == WM_LBUTTONUP)
764             break;
765 
766         if (Msg.message != WM_MOUSEMOVE)
767             continue;
768 
769         ht = SendMessage(hWnd, WM_NCHITTEST, 0, MAKELPARAM(Msg.pt.x, Msg.pt.y));
770         Pressed = (ht == wParam);
771 
772         /* Only draw the buttons if the hit test changed */
773         if (ht != pwndData->lastHitTest &&
774             (HT_ISBUTTON(ht) || HT_ISBUTTON(pwndData->lastHitTest)))
775         {
776             ThemeDrawCaptionButtons(&context, 0, Pressed ? wParam: 0);
777             pwndData->lastHitTest = ht;
778         }
779     }
780 
781     ThemeDrawCaptionButtons(&context, ht, 0);
782     ThemeCleanupDrawContext(&context);
783 
784     ReleaseCapture();
785 
786     if (Pressed)
787         SendMessageW(hWnd, WM_SYSCOMMAND, SCMsg, 0);
788 }
789 
790 
791 static LRESULT
792 DefWndNCHitTest(HWND hWnd, POINT Point)
793 {
794     RECT WindowRect;
795     POINT ClientPoint;
796     WINDOWINFO wi;
797 
798     wi.cbSize = sizeof(wi);
799     GetWindowInfo(hWnd, &wi);
800 
801     if (!PtInRect(&wi.rcWindow, Point))
802     {
803         return HTNOWHERE;
804     }
805     WindowRect = wi.rcWindow;
806 
807     if (UserHasWindowEdge(wi.dwStyle, wi.dwExStyle))
808     {
809         LONG XSize, YSize;
810 
811         InflateRect(&WindowRect, -(int)wi.cxWindowBorders, -(int)wi.cyWindowBorders);
812         XSize = GetSystemMetrics(SM_CXSIZE) * GetSystemMetrics(SM_CXBORDER);
813         YSize = GetSystemMetrics(SM_CYSIZE) * GetSystemMetrics(SM_CYBORDER);
814         if (!PtInRect(&WindowRect, Point))
815         {
816             BOOL ThickFrame;
817 
818             ThickFrame = (wi.dwStyle & WS_THICKFRAME);
819             if (Point.y < WindowRect.top)
820             {
821                 if(wi.dwStyle & WS_MINIMIZE)
822                     return HTCAPTION;
823                 if(!ThickFrame)
824                     return HTBORDER;
825                 if (Point.x < (WindowRect.left + XSize))
826                     return HTTOPLEFT;
827                 if (Point.x >= (WindowRect.right - XSize))
828                     return HTTOPRIGHT;
829                 return HTTOP;
830             }
831             if (Point.y >= WindowRect.bottom)
832             {
833                 if(wi.dwStyle & WS_MINIMIZE)
834                     return HTCAPTION;
835                 if(!ThickFrame)
836                     return HTBORDER;
837                 if (Point.x < (WindowRect.left + XSize))
838                     return HTBOTTOMLEFT;
839                 if (Point.x >= (WindowRect.right - XSize))
840                     return HTBOTTOMRIGHT;
841                 return HTBOTTOM;
842             }
843             if (Point.x < WindowRect.left)
844             {
845                 if(wi.dwStyle & WS_MINIMIZE)
846                     return HTCAPTION;
847                 if(!ThickFrame)
848                     return HTBORDER;
849                 if (Point.y < (WindowRect.top + YSize))
850                     return HTTOPLEFT;
851                 if (Point.y >= (WindowRect.bottom - YSize))
852                     return HTBOTTOMLEFT;
853                 return HTLEFT;
854             }
855             if (Point.x >= WindowRect.right)
856             {
857                 if(wi.dwStyle & WS_MINIMIZE)
858                     return HTCAPTION;
859                 if(!ThickFrame)
860                     return HTBORDER;
861                 if (Point.y < (WindowRect.top + YSize))
862                     return HTTOPRIGHT;
863                 if (Point.y >= (WindowRect.bottom - YSize))
864                     return HTBOTTOMRIGHT;
865                 return HTRIGHT;
866             }
867         }
868     }
869     else
870     {
871         if (wi.dwExStyle & WS_EX_STATICEDGE)
872             InflateRect(&WindowRect, -GetSystemMetrics(SM_CXBORDER),
873                                      -GetSystemMetrics(SM_CYBORDER));
874         if (!PtInRect(&WindowRect, Point))
875             return HTBORDER;
876     }
877 
878     if ((wi.dwStyle & WS_CAPTION) == WS_CAPTION)
879     {
880         if (wi.dwExStyle & WS_EX_TOOLWINDOW)
881             WindowRect.top += GetSystemMetrics(SM_CYSMCAPTION);
882         else
883             WindowRect.top += GetSystemMetrics(SM_CYCAPTION);
884 
885         if (!PtInRect(&WindowRect, Point))
886         {
887             if (wi.dwStyle & WS_SYSMENU)
888             {
889                 PWND_DATA pwndData = ThemeGetWndData(hWnd);
890 
891                 if (!(wi.dwExStyle & WS_EX_TOOLWINDOW))
892                 {
893                     // if(!(wi.dwExStyle & WS_EX_DLGMODALFRAME))
894                     // FIXME: The real test should check whether there is
895                     // an icon for the system window, and if so, do the
896                     // rect.left increase.
897                     // See win32ss/user/user32/windows/nonclient.c!DefWndNCHitTest
898                     // and win32ss/user/ntuser/nonclient.c!GetNCHitEx which does
899                     // the test better.
900                         WindowRect.left += GetSystemMetrics(SM_CXSMICON);
901                 }
902 
903                 if (pwndData)
904                 {
905                     POINT pt = {Point.x - wi.rcWindow.left, Point.y - wi.rcWindow.top};
906                     if (PtInRect(&pwndData->rcCaptionButtons[CLOSEBUTTON], pt))
907                         return HTCLOSE;
908                     if (PtInRect(&pwndData->rcCaptionButtons[MAXBUTTON], pt))
909                         return HTMAXBUTTON;
910                     if (PtInRect(&pwndData->rcCaptionButtons[MINBUTTON], pt))
911                         return HTMINBUTTON;
912                 }
913             }
914             if (Point.x < WindowRect.left)
915                 return HTSYSMENU;
916             return HTCAPTION;
917         }
918     }
919 
920     if(!(wi.dwStyle & WS_MINIMIZE))
921     {
922         HMENU menu;
923 
924         ClientPoint = Point;
925         ScreenToClient(hWnd, &ClientPoint);
926         GetClientRect(hWnd, &wi.rcClient);
927 
928         if (PtInRect(&wi.rcClient, ClientPoint))
929         {
930             return HTCLIENT;
931         }
932 
933         if ((menu = GetMenu(hWnd)) && !(wi.dwStyle & WS_CHILD))
934         {
935             if (Point.x > 0 && Point.x < WindowRect.right && ClientPoint.y < 0)
936                 return HTMENU;
937         }
938 
939         if (wi.dwExStyle & WS_EX_CLIENTEDGE)
940         {
941             InflateRect(&WindowRect, -2 * GetSystemMetrics(SM_CXBORDER),
942                         -2 * GetSystemMetrics(SM_CYBORDER));
943         }
944 
945         if ((wi.dwStyle & WS_VSCROLL) && (wi.dwStyle & WS_HSCROLL) &&
946             (WindowRect.bottom - WindowRect.top) > GetSystemMetrics(SM_CYHSCROLL))
947         {
948             RECT ParentRect, TempRect = WindowRect, TempRect2 = WindowRect;
949             HWND Parent = GetParent(hWnd);
950 
951             TempRect.bottom -= GetSystemMetrics(SM_CYHSCROLL);
952             if ((wi.dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
953                 TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL);
954             else
955                 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL);
956             if (PtInRect(&TempRect, Point))
957                 return HTVSCROLL;
958 
959             TempRect2.top = TempRect2.bottom - GetSystemMetrics(SM_CYHSCROLL);
960             if ((wi.dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
961                 TempRect2.left += GetSystemMetrics(SM_CXVSCROLL);
962             else
963                 TempRect2.right -= GetSystemMetrics(SM_CXVSCROLL);
964             if (PtInRect(&TempRect2, Point))
965                 return HTHSCROLL;
966 
967             TempRect.top = TempRect2.top;
968             TempRect.bottom = TempRect2.bottom;
969             if(Parent)
970                 GetClientRect(Parent, &ParentRect);
971             if (PtInRect(&TempRect, Point) && HASSIZEGRIP(wi.dwStyle, wi.dwExStyle,
972                       GetWindowLongW(Parent, GWL_STYLE), wi.rcWindow, ParentRect))
973             {
974                 if ((wi.dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
975                     return HTBOTTOMLEFT;
976                 else
977                     return HTBOTTOMRIGHT;
978             }
979         }
980         else
981         {
982             if (wi.dwStyle & WS_VSCROLL)
983             {
984                 RECT TempRect = WindowRect;
985 
986                 if ((wi.dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
987                     TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL);
988                 else
989                     TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL);
990                 if (PtInRect(&TempRect, Point))
991                     return HTVSCROLL;
992             }
993             else if (wi.dwStyle & WS_HSCROLL)
994             {
995                 RECT TempRect = WindowRect;
996                 TempRect.top = TempRect.bottom - GetSystemMetrics(SM_CYHSCROLL);
997                 if (PtInRect(&TempRect, Point))
998                     return HTHSCROLL;
999             }
1000         }
1001     }
1002 
1003     return HTNOWHERE;
1004 }
1005 
1006 LRESULT CALLBACK
1007 ThemeWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, WNDPROC DefWndProc)
1008 {
1009     switch(Msg)
1010     {
1011     case WM_NCPAINT:
1012         return ThemeHandleNCPaint(hWnd, (HRGN)wParam);
1013     //
1014     // WM_NCUAHDRAWCAPTION : wParam are DC_* flags.
1015     //
1016     case WM_NCUAHDRAWCAPTION:
1017     //
1018     // WM_NCUAHDRAWFRAME : wParam is HDC, lParam are DC_ACTIVE and or DC_REDRAWHUNGWND.
1019     //
1020     case WM_NCUAHDRAWFRAME:
1021     case WM_NCACTIVATE:
1022 
1023         if ((GetWindowLongW(hWnd, GWL_STYLE) & WS_CAPTION) != WS_CAPTION)
1024             return TRUE;
1025 
1026         ThemeHandleNCPaint(hWnd, (HRGN)1);
1027         return TRUE;
1028     case WM_NCMOUSEMOVE:
1029     {
1030         POINT Point;
1031         Point.x = GET_X_LPARAM(lParam);
1032         Point.y = GET_Y_LPARAM(lParam);
1033         return ThemeHandleNcMouseMove(hWnd, wParam, &Point);
1034     }
1035     case WM_NCMOUSELEAVE:
1036         return ThemeHandleNcMouseLeave(hWnd);
1037     case WM_NCLBUTTONDOWN:
1038         switch (wParam)
1039         {
1040             case HTMINBUTTON:
1041             case HTMAXBUTTON:
1042             case HTCLOSE:
1043             {
1044                 ThemeHandleButton(hWnd, wParam);
1045                 return 0;
1046             }
1047             default:
1048                 return DefWndProc(hWnd, Msg, wParam, lParam);
1049         }
1050     case WM_NCHITTEST:
1051     {
1052         POINT Point;
1053         Point.x = GET_X_LPARAM(lParam);
1054         Point.y = GET_Y_LPARAM(lParam);
1055         return DefWndNCHitTest(hWnd, Point);
1056     }
1057     case WM_SYSCOMMAND:
1058     {
1059         if((wParam & 0xfff0) == SC_VSCROLL ||
1060            (wParam & 0xfff0) == SC_HSCROLL)
1061         {
1062             POINT Pt;
1063             Pt.x = (short)LOWORD(lParam);
1064             Pt.y = (short)HIWORD(lParam);
1065             NC_TrackScrollBar(hWnd, wParam, Pt);
1066             return 0;
1067         }
1068         else
1069         {
1070             return DefWndProc(hWnd, Msg, wParam, lParam);
1071         }
1072     }
1073     default:
1074         return DefWndProc(hWnd, Msg, wParam, lParam);
1075     }
1076 }
1077 
1078 HRESULT WINAPI DrawNCPreview(HDC hDC,
1079                              DWORD DNCP_Flag,
1080                              LPRECT prcPreview,
1081                              LPCWSTR pszThemeFileName,
1082                              LPCWSTR pszColorName,
1083                              LPCWSTR pszSizeName,
1084                              PNONCLIENTMETRICSW pncMetrics,
1085                              COLORREF* lpaRgbValues)
1086 {
1087     WNDCLASSEXW DummyPreviewWindowClass;
1088     HWND hwndDummy;
1089     HRESULT hres;
1090     HTHEMEFILE hThemeFile;
1091     DRAW_CONTEXT context;
1092     RECT rcCurrent;
1093 
1094     /* FIXME: We also need to implement drawing the rest of the preview windows
1095      *        and make use of the ncmetrics and colors passed as parameters */
1096 
1097     /* Create a dummy window that will be used to trick the paint funtions */
1098     memset(&DummyPreviewWindowClass, 0, sizeof(DummyPreviewWindowClass));
1099     DummyPreviewWindowClass.cbSize = sizeof(DummyPreviewWindowClass);
1100     DummyPreviewWindowClass.lpszClassName = L"DummyPreviewWindowClass";
1101     DummyPreviewWindowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
1102     DummyPreviewWindowClass.hInstance = hDllInst;
1103     DummyPreviewWindowClass.lpfnWndProc = DefWindowProcW;
1104     if (!RegisterClassExW(&DummyPreviewWindowClass))
1105         return E_FAIL;
1106 
1107     hwndDummy = CreateWindowExW(0, L"DummyPreviewWindowClass", L"Active window", WS_OVERLAPPEDWINDOW,30,30,300,150,0,0,hDllInst,NULL);
1108     if (!hwndDummy)
1109         return E_FAIL;
1110 
1111     hres = OpenThemeFile(pszThemeFileName, pszColorName, pszSizeName, &hThemeFile,0);
1112     if (FAILED(hres))
1113         return hres;
1114 
1115     /* Initialize the special draw context for the preview */
1116     context.hDC = hDC;
1117     context.hWnd = hwndDummy;
1118     context.theme = OpenThemeDataFromFile(hThemeFile, hwndDummy, L"WINDOW", 0);
1119     if (!context.theme)
1120         return E_FAIL;
1121     context.scrolltheme = OpenThemeDataFromFile(hThemeFile, hwndDummy, L"SCROLLBAR", 0);
1122     if (!context.scrolltheme)
1123         return E_FAIL;
1124     context.Active = TRUE;
1125     context.wi.cbSize = sizeof(context.wi);
1126     if (!GetWindowInfo(hwndDummy, &context.wi))
1127         return E_FAIL;
1128     context.wi.dwStyle |= WS_VISIBLE;
1129     context.CaptionHeight = context.wi.cyWindowBorders;
1130     context.CaptionHeight += GetSystemMetrics(context.wi.dwExStyle & WS_EX_TOOLWINDOW ? SM_CYSMCAPTION : SM_CYCAPTION );
1131     context.hRgn = CreateRectRgnIndirect(&context.wi.rcWindow);
1132 
1133     /* Paint the window on the preview hDC */
1134     rcCurrent = context.wi.rcWindow;
1135     OffsetRect( &rcCurrent, -context.wi.rcWindow.left, -context.wi.rcWindow.top);
1136     SetViewportOrgEx(hDC, context.wi.rcWindow.left, context.wi.rcWindow.top, NULL);
1137     ThemeCalculateCaptionButtonsPos(hwndDummy, context.theme);
1138     ThemePaintWindow(&context, &rcCurrent, FALSE);
1139     SetViewportOrgEx(hDC, 0, 0, NULL);
1140 
1141     context.hDC = NULL;
1142     CloseThemeData (context.theme);
1143     CloseThemeData (context.scrolltheme);
1144     ThemeCleanupDrawContext(&context);
1145 
1146     /* Cleanup */
1147     DestroyWindow(hwndDummy);
1148     UnregisterClassW(L"DummyPreviewWindowClass", hDllInst);
1149 
1150     return S_OK;
1151 }
1152