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
11 HFONT hMenuFont
= NULL
;
12 HFONT hMenuFontBold
= NULL
;
14 void InitMenuFont(VOID
)
18 ncm
.cbSize
= sizeof(NONCLIENTMETRICS
);
20 if (!SystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
25 hMenuFont
= CreateFontIndirect(&ncm
.lfMenuFont
);
27 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
28 hMenuFontBold
= CreateFontIndirect(&ncm
.lfMenuFont
);
32 IsWindowActive(HWND hWnd
, DWORD ExStyle
)
36 if (ExStyle
& WS_EX_MDICHILD
)
38 ret
= IsChild(GetForegroundWindow(), hWnd
);
40 ret
= (hWnd
== (HWND
)SendMessageW(GetParent(hWnd
), WM_MDIGETACTIVE
, 0, 0));
44 ret
= (GetForegroundWindow() == hWnd
);
51 UserHasWindowEdge(DWORD Style
, DWORD ExStyle
)
53 if (Style
& WS_MINIMIZE
)
55 if (ExStyle
& WS_EX_DLGMODALFRAME
)
57 if (ExStyle
& WS_EX_STATICEDGE
)
59 if (Style
& WS_THICKFRAME
)
62 if (Style
== WS_DLGFRAME
|| Style
== WS_CAPTION
)
68 UserGetWindowIcon(PDRAW_CONTEXT pcontext
)
72 SendMessageTimeout(pcontext
->hWnd
, WM_GETICON
, ICON_SMALL2
, 0, SMTO_ABORTIFHUNG
, 1000, (PDWORD_PTR
)&hIcon
);
75 SendMessageTimeout(pcontext
->hWnd
, WM_GETICON
, ICON_SMALL
, 0, SMTO_ABORTIFHUNG
, 1000, (PDWORD_PTR
)&hIcon
);
78 SendMessageTimeout(pcontext
->hWnd
, WM_GETICON
, ICON_BIG
, 0, SMTO_ABORTIFHUNG
, 1000, (PDWORD_PTR
)&hIcon
);
81 hIcon
= (HICON
)GetClassLong(pcontext
->hWnd
, GCL_HICONSM
);
84 hIcon
= (HICON
)GetClassLong(pcontext
->hWnd
, GCL_HICON
);
86 // See also win32ss/user/ntuser/nonclient.c!NC_IconForWindow
87 if (!hIcon
&& !(pcontext
->wi
.dwExStyle
& WS_EX_DLGMODALFRAME
))
88 hIcon
= LoadIconW(NULL
, (LPCWSTR
)IDI_WINLOGO
);
93 WCHAR
*UserGetWindowCaption(HWND hwnd
)
97 text
= (WCHAR
*)HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
98 if (text
) InternalGetWindowText(hwnd
, text
, len
);
103 ThemeDrawTitle(PDRAW_CONTEXT context
, RECT
* prcCurrent
)
108 HRESULT WINAPI
ThemeDrawCaptionText(HTHEME hTheme
, HDC hdc
, int iPartId
, int iStateId
,
109 LPCWSTR pszText
, int iCharCount
, DWORD dwTextFlags
,
110 DWORD dwTextFlags2
, const RECT
*pRect
, BOOL Active
)
114 HGDIOBJ oldFont
= NULL
;
117 COLORREF oldTextColor
;
121 hr
= GetThemeSysFont(0,TMT_CAPTIONFONT
,&logfont
);
124 hFont
= CreateFontIndirectW(&logfont
);
126 CopyRect(&rt
, pRect
);
128 oldFont
= SelectObject(hdc
, hFont
);
130 if(dwTextFlags2
& DTT_GRAYED
)
131 textColor
= GetSysColor(COLOR_GRAYTEXT
);
133 textColor
= GetSysColor(COLOR_INACTIVECAPTIONTEXT
);
135 textColor
= GetSysColor(COLOR_CAPTIONTEXT
);
137 oldTextColor
= SetTextColor(hdc
, textColor
);
138 oldBkMode
= SetBkMode(hdc
, TRANSPARENT
);
139 DrawThemeText(hTheme
, hdc
, iPartId
, iStateId
, pszText
, iCharCount
, dwTextFlags
, dwTextFlags
, pRect
);
140 SetBkMode(hdc
, oldBkMode
);
141 SetTextColor(hdc
, oldTextColor
);
144 SelectObject(hdc
, oldFont
);
151 ThemeInitDrawContext(PDRAW_CONTEXT pcontext
,
155 pcontext
->wi
.cbSize
= sizeof(pcontext
->wi
);
156 GetWindowInfo(hWnd
, &pcontext
->wi
);
157 pcontext
->hWnd
= hWnd
;
158 pcontext
->Active
= IsWindowActive(hWnd
, pcontext
->wi
.dwExStyle
);
159 pcontext
->theme
= MSSTYLES_OpenThemeClass(ActiveThemeFile
, NULL
, L
"WINDOW");
160 pcontext
->scrolltheme
= MSSTYLES_OpenThemeClass(ActiveThemeFile
, NULL
, L
"SCROLLBAR");
162 pcontext
->CaptionHeight
= pcontext
->wi
.cyWindowBorders
;
163 pcontext
->CaptionHeight
+= GetSystemMetrics(pcontext
->wi
.dwExStyle
& WS_EX_TOOLWINDOW
? SM_CYSMCAPTION
: SM_CYCAPTION
);
167 hRgn
= CreateRectRgnIndirect(&pcontext
->wi
.rcWindow
);
169 pcontext
->hRgn
= hRgn
;
171 pcontext
->hDC
= GetDCEx(hWnd
, hRgn
, DCX_WINDOW
| DCX_INTERSECTRGN
| DCX_USESTYLE
| DCX_KEEPCLIPRGN
);
175 ThemeCleanupDrawContext(PDRAW_CONTEXT pcontext
)
177 ReleaseDC(pcontext
->hWnd
,pcontext
->hDC
);
179 CloseThemeData (pcontext
->theme
);
180 CloseThemeData (pcontext
->scrolltheme
);
182 if(pcontext
->hRgn
!= NULL
)
184 DeleteObject(pcontext
->hRgn
);
189 ThemeStartBufferedPaint(PDRAW_CONTEXT pcontext
, int cx
, int cy
)
193 pcontext
->hDCScreen
= pcontext
->hDC
;
194 pcontext
->hDC
= CreateCompatibleDC(pcontext
->hDCScreen
);
195 hbmp
= CreateCompatibleBitmap(pcontext
->hDCScreen
, cx
, cy
);
196 pcontext
->hbmpOld
= (HBITMAP
)SelectObject(pcontext
->hDC
, hbmp
);
200 ThemeEndBufferedPaint(PDRAW_CONTEXT pcontext
, int x
, int y
, int cx
, int cy
)
203 BitBlt(pcontext
->hDCScreen
, 0, 0, cx
, cy
, pcontext
->hDC
, x
, y
, SRCCOPY
);
204 hbmp
= (HBITMAP
) SelectObject(pcontext
->hDC
, pcontext
->hbmpOld
);
205 DeleteObject(pcontext
->hDC
);
208 pcontext
->hDC
= pcontext
->hDCScreen
;
212 ThemeDrawCaptionButton(PDRAW_CONTEXT pcontext
,
214 CAPTIONBUTTON buttonId
,
218 INT ButtonWidth
, ButtonHeight
, iPartId
;
224 iPartId
= pcontext
->wi
.dwExStyle
& WS_EX_TOOLWINDOW
? WP_SMALLCLOSEBUTTON
: WP_CLOSEBUTTON
;
228 if (!(pcontext
->wi
.dwStyle
& WS_MAXIMIZEBOX
))
230 if (!(pcontext
->wi
.dwStyle
& WS_MINIMIZEBOX
))
233 iStateId
= BUTTON_DISABLED
;
236 iPartId
= pcontext
->wi
.dwStyle
& WS_MAXIMIZE
? WP_RESTOREBUTTON
: WP_MAXBUTTON
;
240 if (!(pcontext
->wi
.dwStyle
& WS_MINIMIZEBOX
))
242 if (!(pcontext
->wi
.dwStyle
& WS_MAXIMIZEBOX
))
245 iStateId
= BUTTON_DISABLED
;
248 iPartId
= WP_MINBUTTON
;
252 //FIXME: Implement Help Button
256 GetThemePartSize(pcontext
->theme
, pcontext
->hDC
, iPartId
, 0, NULL
, TS_MIN
, &ButtonSize
);
258 ButtonHeight
= GetSystemMetrics( pcontext
->wi
.dwExStyle
& WS_EX_TOOLWINDOW
? SM_CYSMSIZE
: SM_CYSIZE
);
259 ButtonWidth
= MulDiv(ButtonSize
.cx
, ButtonHeight
, ButtonSize
.cy
);
264 /* Calculate the position */
265 rcPart
.top
= prcCurrent
->top
;
266 rcPart
.right
= prcCurrent
->right
;
267 rcPart
.bottom
= rcPart
.top
+ ButtonHeight
;
268 rcPart
.left
= rcPart
.right
- ButtonWidth
;
269 prcCurrent
->right
-= ButtonWidth
+ BUTTON_GAP_SIZE
;
271 DrawThemeBackground(pcontext
->theme
, pcontext
->hDC
, iPartId
, iStateId
, &rcPart
, NULL
);
275 ThemeGetButtonState(DWORD htCurrect
, DWORD htHot
, DWORD htDown
, BOOL Active
)
277 if (htHot
== htCurrect
)
280 return BUTTON_INACTIVE
;
281 if (htDown
== htCurrect
)
282 return BUTTON_PRESSED
;
284 return BUTTON_NORMAL
;
287 /* Used only from mouse event handlers */
289 ThemeDrawCaptionButtons(PDRAW_CONTEXT pcontext
, DWORD htHot
, DWORD htDown
)
293 /* Calculate the area of the caption */
294 rcCurrent
.top
= rcCurrent
.left
= 0;
295 rcCurrent
.right
= pcontext
->wi
.rcWindow
.right
- pcontext
->wi
.rcWindow
.left
;
296 rcCurrent
.bottom
= pcontext
->CaptionHeight
;
298 /* Add a padding around the objects of the caption */
299 InflateRect(&rcCurrent
, -(int)pcontext
->wi
.cyWindowBorders
-BUTTON_GAP_SIZE
,
300 -(int)pcontext
->wi
.cyWindowBorders
-BUTTON_GAP_SIZE
);
302 /* Draw the buttons */
303 ThemeDrawCaptionButton(pcontext
, &rcCurrent
, CLOSEBUTTON
,
304 ThemeGetButtonState(HTCLOSE
, htHot
, htDown
, pcontext
->Active
));
305 ThemeDrawCaptionButton(pcontext
, &rcCurrent
, MAXBUTTON
,
306 ThemeGetButtonState(HTMAXBUTTON
, htHot
, htDown
, pcontext
->Active
));
307 ThemeDrawCaptionButton(pcontext
, &rcCurrent
, MINBUTTON
,
308 ThemeGetButtonState(HTMINBUTTON
, htHot
, htDown
, pcontext
->Active
));
309 ThemeDrawCaptionButton(pcontext
, &rcCurrent
, HELPBUTTON
,
310 ThemeGetButtonState(HTHELP
, htHot
, htDown
, pcontext
->Active
));
313 /* Used from WM_NCPAINT and WM_NCACTIVATE handlers */
315 ThemeDrawCaption(PDRAW_CONTEXT pcontext
, RECT
* prcCurrent
)
322 // See also win32ss/user/ntuser/nonclient.c!UserDrawCaptionBar
323 // and win32ss/user/ntuser/nonclient.c!UserDrawCaption
324 if ((pcontext
->wi
.dwStyle
& WS_SYSMENU
) && !(pcontext
->wi
.dwExStyle
& WS_EX_TOOLWINDOW
))
325 hIcon
= UserGetWindowIcon(pcontext
);
329 CaptionText
= UserGetWindowCaption(pcontext
->hWnd
);
331 /* Get the caption part and state id */
332 if (pcontext
->wi
.dwExStyle
& WS_EX_TOOLWINDOW
)
333 iPart
= WP_SMALLCAPTION
;
334 else if (pcontext
->wi
.dwStyle
& WS_MAXIMIZE
)
335 iPart
= WP_MAXCAPTION
;
339 iState
= pcontext
->Active
? FS_ACTIVE
: FS_INACTIVE
;
341 /* Draw the caption background */
342 rcPart
= *prcCurrent
;
343 rcPart
.bottom
= rcPart
.top
+ pcontext
->CaptionHeight
;
344 prcCurrent
->top
= rcPart
.bottom
;
345 DrawThemeBackground(pcontext
->theme
, pcontext
->hDC
,iPart
,iState
,&rcPart
,NULL
);
347 /* Add a padding around the objects of the caption */
348 InflateRect(&rcPart
, -(int)pcontext
->wi
.cyWindowBorders
-BUTTON_GAP_SIZE
,
349 -(int)pcontext
->wi
.cyWindowBorders
-BUTTON_GAP_SIZE
);
351 /* Draw the caption buttons */
352 if (pcontext
->wi
.dwStyle
& WS_SYSMENU
)
354 iState
= pcontext
->Active
? BUTTON_NORMAL
: BUTTON_INACTIVE
;
356 ThemeDrawCaptionButton(pcontext
, &rcPart
, CLOSEBUTTON
, iState
);
357 ThemeDrawCaptionButton(pcontext
, &rcPart
, MAXBUTTON
, iState
);
358 ThemeDrawCaptionButton(pcontext
, &rcPart
, MINBUTTON
, iState
);
359 ThemeDrawCaptionButton(pcontext
, &rcPart
, HELPBUTTON
, iState
);
367 int IconHeight
= GetSystemMetrics(SM_CYSMICON
);
368 int IconWidth
= GetSystemMetrics(SM_CXSMICON
);
369 DrawIconEx(pcontext
->hDC
, rcPart
.left
, rcPart
.top
, hIcon
, IconWidth
, IconHeight
, 0, NULL
, DI_NORMAL
);
370 rcPart
.left
+= IconWidth
+ 4;
375 /* Draw the caption */
378 /* FIXME: Use DrawThemeTextEx */
379 ThemeDrawCaptionText(pcontext
->theme
,
384 lstrlenW(CaptionText
),
385 DT_VCENTER
| DT_SINGLELINE
| DT_END_ELLIPSIS
,
389 HeapFree(GetProcessHeap(), 0, CaptionText
);
394 ThemeDrawBorders(PDRAW_CONTEXT pcontext
, RECT
* prcCurrent
)
397 int iState
= pcontext
->Active
? FS_ACTIVE
: FS_INACTIVE
;
399 /* Draw the bottom border */
400 rcPart
= *prcCurrent
;
401 rcPart
.top
= rcPart
.bottom
- pcontext
->wi
.cyWindowBorders
;
402 prcCurrent
->bottom
= rcPart
.top
;
403 DrawThemeBackground(pcontext
->theme
, pcontext
->hDC
, WP_FRAMEBOTTOM
, iState
, &rcPart
, NULL
);
405 /* Draw the left border */
406 rcPart
= *prcCurrent
;
407 rcPart
.right
= rcPart
.left
+ pcontext
->wi
.cxWindowBorders
;
408 prcCurrent
->left
= rcPart
.right
;
409 DrawThemeBackground(pcontext
->theme
, pcontext
->hDC
,WP_FRAMELEFT
, iState
, &rcPart
, NULL
);
411 /* Draw the right border */
412 rcPart
= *prcCurrent
;
413 rcPart
.left
= rcPart
.right
- pcontext
->wi
.cxWindowBorders
;
414 prcCurrent
->right
= rcPart
.left
;
415 DrawThemeBackground(pcontext
->theme
, pcontext
->hDC
,WP_FRAMERIGHT
, iState
, &rcPart
, NULL
);
419 DrawClassicFrame(PDRAW_CONTEXT context
, RECT
* prcCurrent
)
421 /* Draw outer edge */
422 if (UserHasWindowEdge(context
->wi
.dwStyle
, context
->wi
.dwExStyle
))
424 DrawEdge(context
->hDC
, prcCurrent
, EDGE_RAISED
, BF_RECT
| BF_ADJUST
);
426 else if (context
->wi
.dwExStyle
& WS_EX_STATICEDGE
)
428 DrawEdge(context
->hDC
, prcCurrent
, BDR_SUNKENINNER
, BF_RECT
| BF_ADJUST
| BF_FLAT
);
431 /* Firstly the "thick" frame */
432 if ((context
->wi
.dwStyle
& WS_THICKFRAME
) && !(context
->wi
.dwStyle
& WS_MINIMIZE
))
435 (GetSystemMetrics(SM_CXFRAME
) - GetSystemMetrics(SM_CXDLGFRAME
)) *
436 GetSystemMetrics(SM_CXBORDER
);
438 (GetSystemMetrics(SM_CYFRAME
) - GetSystemMetrics(SM_CYDLGFRAME
)) *
439 GetSystemMetrics(SM_CYBORDER
);
441 SelectObject(context
->hDC
, GetSysColorBrush(
442 context
->Active
? COLOR_ACTIVEBORDER
: COLOR_INACTIVEBORDER
));
445 PatBlt(context
->hDC
, prcCurrent
->left
, prcCurrent
->top
,
446 prcCurrent
->right
- prcCurrent
->left
, Height
, PATCOPY
);
447 PatBlt(context
->hDC
, prcCurrent
->left
, prcCurrent
->top
,
448 Width
, prcCurrent
->bottom
- prcCurrent
->top
, PATCOPY
);
449 PatBlt(context
->hDC
, prcCurrent
->left
, prcCurrent
->bottom
- 1,
450 prcCurrent
->right
- prcCurrent
->left
, -Height
, PATCOPY
);
451 PatBlt(context
->hDC
, prcCurrent
->right
- 1, prcCurrent
->top
,
452 -Width
, prcCurrent
->bottom
- prcCurrent
->top
, PATCOPY
);
454 InflateRect(prcCurrent
, -Width
, -Height
);
457 /* Now the other bit of the frame */
458 if (context
->wi
.dwStyle
& (WS_DLGFRAME
| WS_BORDER
) || (context
->wi
.dwExStyle
& WS_EX_DLGMODALFRAME
))
460 INT Width
= GetSystemMetrics(SM_CXBORDER
);
461 INT Height
= GetSystemMetrics(SM_CYBORDER
);
463 SelectObject(context
->hDC
, GetSysColorBrush(
464 (context
->wi
.dwExStyle
& (WS_EX_DLGMODALFRAME
| WS_EX_CLIENTEDGE
)) ? COLOR_3DFACE
:
465 (context
->wi
.dwExStyle
& WS_EX_STATICEDGE
) ? COLOR_WINDOWFRAME
:
466 (context
->wi
.dwStyle
& (WS_DLGFRAME
| WS_THICKFRAME
)) ? COLOR_3DFACE
:
470 PatBlt(context
->hDC
, prcCurrent
->left
, prcCurrent
->top
,
471 prcCurrent
->right
- prcCurrent
->left
, Height
, PATCOPY
);
472 PatBlt(context
->hDC
, prcCurrent
->left
, prcCurrent
->top
,
473 Width
, prcCurrent
->bottom
- prcCurrent
->top
, PATCOPY
);
474 PatBlt(context
->hDC
, prcCurrent
->left
, prcCurrent
->bottom
- 1,
475 prcCurrent
->right
- prcCurrent
->left
, -Height
, PATCOPY
);
476 PatBlt(context
->hDC
, prcCurrent
->right
- 1, prcCurrent
->top
,
477 -Width
, prcCurrent
->bottom
- prcCurrent
->top
, PATCOPY
);
479 InflateRect(prcCurrent
, -Width
, -Height
);
482 if (context
->wi
.dwExStyle
& WS_EX_CLIENTEDGE
)
484 DrawEdge(context
->hDC
, prcCurrent
, EDGE_SUNKEN
, BF_RECT
| BF_ADJUST
);
489 ThemeDrawMenuItem(PDRAW_CONTEXT pcontext
, HMENU Menu
, int imenu
)
492 BOOL flat_menu
= FALSE
;
495 WCHAR wstrItemText
[20];
497 HFONT FontOld
= NULL
;
498 UINT uFormat
= DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
;
500 Item
.cbSize
= sizeof(MENUITEMINFOW
);
501 Item
.fMask
= MIIM_FTYPE
| MIIM_STATE
| MIIM_STRING
;
502 Item
.dwTypeData
= wstrItemText
;
504 if (!GetMenuItemInfoW(Menu
, imenu
, TRUE
, &Item
))
507 if(Item
.fType
& MF_SEPARATOR
)
513 Item
.dwTypeData
= (LPWSTR
)HeapAlloc(GetProcessHeap(), 0, Item
.cch
* sizeof(WCHAR
));
514 Item
.fMask
= MIIM_FTYPE
| MIIM_STATE
| MIIM_STRING
;
515 GetMenuItemInfoW(Menu
, imenu
, TRUE
, &Item
);
521 flat_menu
= GetThemeSysBool(pcontext
->theme
, TMT_FLATMENUS
);
523 GetMenuItemRect(pcontext
->hWnd
, Menu
, imenu
, &Rect
);
525 OffsetRect(&Rect
, -pcontext
->wi
.rcWindow
.left
, -pcontext
->wi
.rcWindow
.top
);
527 SetBkColor(pcontext
->hDC
, GetSysColor(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
528 SetTextColor(pcontext
->hDC
, GetSysColor(Item
.fState
& MF_GRAYED
? COLOR_GRAYTEXT
: COLOR_MENUTEXT
));
530 if (0 != (Item
.fState
& MFS_DEFAULT
))
532 FontOld
= (HFONT
)SelectObject(pcontext
->hDC
, hMenuFontBold
);
535 Rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
536 Rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
538 Text
= (PWCHAR
) Item
.dwTypeData
;
541 for (i
= 0; L
'\0' != Text
[i
]; i
++)
543 if (L
'\t' == Text
[i
] || L
'\b' == Text
[i
])
550 SetBkMode(pcontext
->hDC
, OPAQUE
);
552 if (0 != (Item
.fState
& MF_GRAYED
))
554 if (0 == (Item
.fState
& MF_HILITE
))
556 ++Rect
.left
; ++Rect
.top
; ++Rect
.right
; ++Rect
.bottom
;
557 SetTextColor(pcontext
->hDC
, RGB(0xff, 0xff, 0xff));
558 DrawTextW(pcontext
->hDC
, Text
, i
, &Rect
, uFormat
);
559 --Rect
.left
; --Rect
.top
; --Rect
.right
; --Rect
.bottom
;
561 SetTextColor(pcontext
->hDC
, RGB(0x80, 0x80, 0x80));
562 SetBkMode(pcontext
->hDC
, TRANSPARENT
);
565 DrawTextW(pcontext
->hDC
, Text
, i
, &Rect
, uFormat
);
567 /* Exclude from the clip region the area drawn by DrawText */
568 SetRect(&rcCalc
, 0,0,0,0);
569 DrawTextW(pcontext
->hDC
, Text
, i
, &rcCalc
, uFormat
| DT_CALCRECT
);
570 InflateRect( &Rect
, 0, -(rcCalc
.bottom
+1)/2);
571 ExcludeClipRect(pcontext
->hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
575 SelectObject(pcontext
->hDC
, FontOld
);
580 ThemeDrawMenuBar(PDRAW_CONTEXT pcontext
, PRECT prcCurrent
)
583 MENUBARINFO MenuBarInfo
;
585 HFONT FontOld
= NULL
;
593 flat_menu
= GetThemeSysBool(pcontext
->theme
, TMT_FLATMENUS
);
595 MenuBarInfo
.cbSize
= sizeof(MENUBARINFO
);
596 if (! GetMenuBarInfo(pcontext
->hWnd
, OBJID_MENU
, 0, &MenuBarInfo
))
599 Menu
= GetMenu(pcontext
->hWnd
);
600 if (GetMenuItemCount(Menu
) == 0)
603 Rect
= MenuBarInfo
.rcBar
;
604 OffsetRect(&Rect
, -pcontext
->wi
.rcWindow
.left
, -pcontext
->wi
.rcWindow
.top
);
606 /* Draw a line under the menu */
607 oldPen
= (HPEN
)SelectObject(pcontext
->hDC
, GetStockObject(DC_PEN
));
608 SetDCPenColor(pcontext
->hDC
, GetSysColor(COLOR_3DFACE
));
609 MoveToEx(pcontext
->hDC
, Rect
.left
, Rect
.bottom
, NULL
);
610 LineTo(pcontext
->hDC
, Rect
.right
, Rect
.bottom
);
611 SelectObject(pcontext
->hDC
, oldPen
);
613 /* Draw menu items */
614 FontOld
= (HFONT
)SelectObject(pcontext
->hDC
, hMenuFont
);
616 for (i
= 0; i
< GetMenuItemCount(Menu
); i
++)
618 ThemeDrawMenuItem(pcontext
, Menu
, i
);
621 SelectObject(pcontext
->hDC
, FontOld
);
623 /* Fill the menu background area that isn't painted yet */
624 FillRect(pcontext
->hDC
, &Rect
, GetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
628 ThemePaintWindow(PDRAW_CONTEXT pcontext
, RECT
* prcCurrent
, BOOL bDoDoubleBuffering
)
630 if(!(pcontext
->wi
.dwStyle
& WS_VISIBLE
))
633 if(pcontext
->wi
.dwStyle
& WS_MINIMIZE
)
635 ThemeDrawTitle(pcontext
, prcCurrent
);
639 if((pcontext
->wi
.dwStyle
& WS_CAPTION
)==WS_CAPTION
)
641 if (bDoDoubleBuffering
)
642 ThemeStartBufferedPaint(pcontext
, prcCurrent
->right
, pcontext
->CaptionHeight
);
643 ThemeDrawCaption(pcontext
, prcCurrent
);
644 if (bDoDoubleBuffering
)
645 ThemeEndBufferedPaint(pcontext
, 0, 0, prcCurrent
->right
, pcontext
->CaptionHeight
);
646 ThemeDrawBorders(pcontext
, prcCurrent
);
650 DrawClassicFrame(pcontext
, prcCurrent
);
653 if(HAS_MENU(pcontext
->hWnd
, pcontext
->wi
.dwStyle
))
654 ThemeDrawMenuBar(pcontext
, prcCurrent
);
656 if(pcontext
->wi
.dwStyle
& WS_HSCROLL
)
657 ThemeDrawScrollBar(pcontext
, SB_HORZ
, NULL
);
659 if(pcontext
->wi
.dwStyle
& WS_VSCROLL
)
660 ThemeDrawScrollBar(pcontext
, SB_VERT
, NULL
);
668 ThemeHandleNCPaint(HWND hWnd
, HRGN hRgn
)
670 DRAW_CONTEXT context
;
673 ThemeInitDrawContext(&context
, hWnd
, hRgn
);
675 rcCurrent
= context
.wi
.rcWindow
;
676 OffsetRect( &rcCurrent
, -context
.wi
.rcWindow
.left
, -context
.wi
.rcWindow
.top
);
678 ThemePaintWindow(&context
, &rcCurrent
, TRUE
);
679 ThemeCleanupDrawContext(&context
);
685 ThemeHandleNcMouseMove(HWND hWnd
, DWORD ht
, POINT
* pt
)
687 DRAW_CONTEXT context
;
690 PWND_CONTEXT pcontext
;
692 /* First of all check if we have something to do here */
693 style
= GetWindowLongW(hWnd
, GWL_STYLE
);
694 if((style
& (WS_CAPTION
|WS_HSCROLL
|WS_VSCROLL
))==0)
697 /* Get theme data for this window */
698 pcontext
= ThemeGetWndContext(hWnd
);
699 if (pcontext
== NULL
)
702 /* Begin tracking in the non client area if we are not tracking yet */
703 tme
.cbSize
= sizeof(TRACKMOUSEEVENT
);
704 tme
.dwFlags
= TME_QUERY
;
705 tme
.hwndTrack
= hWnd
;
706 TrackMouseEvent(&tme
);
707 if (tme
.dwFlags
!= (TME_LEAVE
| TME_NONCLIENT
))
709 tme
.hwndTrack
= hWnd
;
710 tme
.dwFlags
= TME_LEAVE
| TME_NONCLIENT
;
711 TrackMouseEvent(&tme
);
714 ThemeInitDrawContext(&context
, hWnd
, 0);
715 if (context
.wi
.dwStyle
& WS_SYSMENU
)
717 if (HT_ISBUTTON(ht
) || HT_ISBUTTON(pcontext
->lastHitTest
))
718 ThemeDrawCaptionButtons(&context
, ht
, 0);
721 if (context
.wi
.dwStyle
& WS_HSCROLL
)
723 if (ht
== HTHSCROLL
|| pcontext
->lastHitTest
== HTHSCROLL
)
724 ThemeDrawScrollBar(&context
, SB_HORZ
, ht
== HTHSCROLL
? pt
: NULL
);
727 if (context
.wi
.dwStyle
& WS_VSCROLL
)
729 if (ht
== HTVSCROLL
|| pcontext
->lastHitTest
== HTVSCROLL
)
730 ThemeDrawScrollBar(&context
, SB_VERT
, ht
== HTVSCROLL
? pt
: NULL
);
732 ThemeCleanupDrawContext(&context
);
734 pcontext
->lastHitTest
= ht
;
740 ThemeHandleNcMouseLeave(HWND hWnd
)
742 DRAW_CONTEXT context
;
744 PWND_CONTEXT pWndContext
;
746 /* First of all check if we have something to do here */
747 style
= GetWindowLongW(hWnd
, GWL_STYLE
);
748 if((style
& (WS_CAPTION
|WS_HSCROLL
|WS_VSCROLL
))==0)
751 /* Get theme data for this window */
752 pWndContext
= ThemeGetWndContext(hWnd
);
753 if (pWndContext
== NULL
)
756 ThemeInitDrawContext(&context
, hWnd
, 0);
757 if (context
.wi
.dwStyle
& WS_SYSMENU
&& HT_ISBUTTON(pWndContext
->lastHitTest
))
758 ThemeDrawCaptionButtons(&context
, 0, 0);
760 if (context
.wi
.dwStyle
& WS_HSCROLL
&& pWndContext
->lastHitTest
== HTHSCROLL
)
761 ThemeDrawScrollBar(&context
, SB_HORZ
, NULL
);
763 if (context
.wi
.dwStyle
& WS_VSCROLL
&& pWndContext
->lastHitTest
== HTVSCROLL
)
764 ThemeDrawScrollBar(&context
, SB_VERT
, NULL
);
766 ThemeCleanupDrawContext(&context
);
768 pWndContext
->lastHitTest
= HTNOWHERE
;
774 ThemeHandleButton(HWND hWnd
, WPARAM wParam
)
780 DRAW_CONTEXT context
;
781 PWND_CONTEXT pWndContext
;
783 Style
= GetWindowLongW(hWnd
, GWL_STYLE
);
784 if (!((Style
& WS_CAPTION
) && (Style
& WS_SYSMENU
)))
793 if (!(Style
& WS_MINIMIZEBOX
))
795 SCMsg
= ((Style
& WS_MINIMIZE
) ? SC_RESTORE
: SC_MINIMIZE
);
798 if (!(Style
& WS_MAXIMIZEBOX
))
800 SCMsg
= ((Style
& WS_MAXIMIZE
) ? SC_RESTORE
: SC_MAXIMIZE
);
806 /* Get theme data for this window */
807 pWndContext
= ThemeGetWndContext(hWnd
);
808 if (pWndContext
== NULL
)
811 ThemeInitDrawContext(&context
, hWnd
, 0);
812 ThemeDrawCaptionButtons(&context
, 0, wParam
);
813 pWndContext
->lastHitTest
= wParam
;
821 if (GetMessageW(&Msg
, 0, WM_MOUSEFIRST
, WM_MOUSELAST
) <= 0)
824 if (Msg
.message
== WM_LBUTTONUP
)
827 if (Msg
.message
!= WM_MOUSEMOVE
)
830 ht
= SendMessage(hWnd
, WM_NCHITTEST
, 0, MAKELPARAM(Msg
.pt
.x
, Msg
.pt
.y
));
831 Pressed
= (ht
== wParam
);
833 /* Only draw the buttons if the hit test changed */
834 if (ht
!= pWndContext
->lastHitTest
&&
835 (HT_ISBUTTON(ht
) || HT_ISBUTTON(pWndContext
->lastHitTest
)))
837 ThemeDrawCaptionButtons(&context
, 0, Pressed
? wParam
: 0);
838 pWndContext
->lastHitTest
= ht
;
842 ThemeDrawCaptionButtons(&context
, ht
, 0);
843 ThemeCleanupDrawContext(&context
);
848 SendMessageW(hWnd
, WM_SYSCOMMAND
, SCMsg
, 0);
853 DefWndNCHitTest(HWND hWnd
, POINT Point
)
859 wi
.cbSize
= sizeof(wi
);
860 GetWindowInfo(hWnd
, &wi
);
862 if (!PtInRect(&wi
.rcWindow
, Point
))
866 WindowRect
= wi
.rcWindow
;
868 if (UserHasWindowEdge(wi
.dwStyle
, wi
.dwExStyle
))
872 InflateRect(&WindowRect
, -(int)wi
.cxWindowBorders
, -(int)wi
.cyWindowBorders
);
873 XSize
= GetSystemMetrics(SM_CXSIZE
) * GetSystemMetrics(SM_CXBORDER
);
874 YSize
= GetSystemMetrics(SM_CYSIZE
) * GetSystemMetrics(SM_CYBORDER
);
875 if (!PtInRect(&WindowRect
, Point
))
879 ThickFrame
= (wi
.dwStyle
& WS_THICKFRAME
);
880 if (Point
.y
< WindowRect
.top
)
882 if(wi
.dwStyle
& WS_MINIMIZE
)
886 if (Point
.x
< (WindowRect
.left
+ XSize
))
888 if (Point
.x
>= (WindowRect
.right
- XSize
))
892 if (Point
.y
>= WindowRect
.bottom
)
894 if(wi
.dwStyle
& WS_MINIMIZE
)
898 if (Point
.x
< (WindowRect
.left
+ XSize
))
900 if (Point
.x
>= (WindowRect
.right
- XSize
))
901 return HTBOTTOMRIGHT
;
904 if (Point
.x
< WindowRect
.left
)
906 if(wi
.dwStyle
& WS_MINIMIZE
)
910 if (Point
.y
< (WindowRect
.top
+ YSize
))
912 if (Point
.y
>= (WindowRect
.bottom
- YSize
))
916 if (Point
.x
>= WindowRect
.right
)
918 if(wi
.dwStyle
& WS_MINIMIZE
)
922 if (Point
.y
< (WindowRect
.top
+ YSize
))
924 if (Point
.y
>= (WindowRect
.bottom
- YSize
))
925 return HTBOTTOMRIGHT
;
932 if (wi
.dwExStyle
& WS_EX_STATICEDGE
)
933 InflateRect(&WindowRect
, -GetSystemMetrics(SM_CXBORDER
),
934 -GetSystemMetrics(SM_CYBORDER
));
935 if (!PtInRect(&WindowRect
, Point
))
939 if ((wi
.dwStyle
& WS_CAPTION
) == WS_CAPTION
)
941 if (wi
.dwExStyle
& WS_EX_TOOLWINDOW
)
942 WindowRect
.top
+= GetSystemMetrics(SM_CYSMCAPTION
);
944 WindowRect
.top
+= GetSystemMetrics(SM_CYCAPTION
);
946 if (!PtInRect(&WindowRect
, Point
))
950 if (wi
.dwExStyle
& WS_EX_TOOLWINDOW
)
951 ButtonWidth
= GetSystemMetrics(SM_CXSMSIZE
);
953 ButtonWidth
= GetSystemMetrics(SM_CXSIZE
);
956 ButtonWidth
+= BUTTON_GAP_SIZE
;
958 if (wi
.dwStyle
& WS_SYSMENU
)
960 if (wi
.dwExStyle
& WS_EX_TOOLWINDOW
)
962 WindowRect
.right
-= ButtonWidth
;
966 // if(!(wi.dwExStyle & WS_EX_DLGMODALFRAME))
967 // FIXME: The real test should check whether there is
968 // an icon for the system window, and if so, do the
969 // rect.left increase.
970 // See win32ss/user/user32/windows/nonclient.c!DefWndNCHitTest
971 // and win32ss/user/ntuser/nonclient.c!GetNCHitEx which does
973 WindowRect
.left
+= ButtonWidth
;
974 WindowRect
.right
-= ButtonWidth
;
977 if (Point
.x
< WindowRect
.left
)
979 if (WindowRect
.right
<= Point
.x
)
981 if (wi
.dwStyle
& WS_MAXIMIZEBOX
|| wi
.dwStyle
& WS_MINIMIZEBOX
)
982 WindowRect
.right
-= ButtonWidth
;
983 if (Point
.x
>= WindowRect
.right
)
985 if (wi
.dwStyle
& WS_MINIMIZEBOX
)
986 WindowRect
.right
-= ButtonWidth
;
987 if (Point
.x
>= WindowRect
.right
)
993 if(!(wi
.dwStyle
& WS_MINIMIZE
))
998 ScreenToClient(hWnd
, &ClientPoint
);
999 GetClientRect(hWnd
, &wi
.rcClient
);
1001 if (PtInRect(&wi
.rcClient
, ClientPoint
))
1006 if ((menu
= GetMenu(hWnd
)) && !(wi
.dwStyle
& WS_CHILD
))
1008 if (Point
.x
> 0 && Point
.x
< WindowRect
.right
&& ClientPoint
.y
< 0)
1012 if (wi
.dwExStyle
& WS_EX_CLIENTEDGE
)
1014 InflateRect(&WindowRect
, -2 * GetSystemMetrics(SM_CXBORDER
),
1015 -2 * GetSystemMetrics(SM_CYBORDER
));
1018 if ((wi
.dwStyle
& WS_VSCROLL
) && (wi
.dwStyle
& WS_HSCROLL
) &&
1019 (WindowRect
.bottom
- WindowRect
.top
) > GetSystemMetrics(SM_CYHSCROLL
))
1021 RECT ParentRect
, TempRect
= WindowRect
, TempRect2
= WindowRect
;
1022 HWND Parent
= GetParent(hWnd
);
1024 TempRect
.bottom
-= GetSystemMetrics(SM_CYHSCROLL
);
1025 if ((wi
.dwExStyle
& WS_EX_LEFTSCROLLBAR
) != 0)
1026 TempRect
.right
= TempRect
.left
+ GetSystemMetrics(SM_CXVSCROLL
);
1028 TempRect
.left
= TempRect
.right
- GetSystemMetrics(SM_CXVSCROLL
);
1029 if (PtInRect(&TempRect
, Point
))
1032 TempRect2
.top
= TempRect2
.bottom
- GetSystemMetrics(SM_CYHSCROLL
);
1033 if ((wi
.dwExStyle
& WS_EX_LEFTSCROLLBAR
) != 0)
1034 TempRect2
.left
+= GetSystemMetrics(SM_CXVSCROLL
);
1036 TempRect2
.right
-= GetSystemMetrics(SM_CXVSCROLL
);
1037 if (PtInRect(&TempRect2
, Point
))
1040 TempRect
.top
= TempRect2
.top
;
1041 TempRect
.bottom
= TempRect2
.bottom
;
1043 GetClientRect(Parent
, &ParentRect
);
1044 if (PtInRect(&TempRect
, Point
) && HASSIZEGRIP(wi
.dwStyle
, wi
.dwExStyle
,
1045 GetWindowLongW(Parent
, GWL_STYLE
), wi
.rcWindow
, ParentRect
))
1047 if ((wi
.dwExStyle
& WS_EX_LEFTSCROLLBAR
) != 0)
1048 return HTBOTTOMLEFT
;
1050 return HTBOTTOMRIGHT
;
1055 if (wi
.dwStyle
& WS_VSCROLL
)
1057 RECT TempRect
= WindowRect
;
1059 if ((wi
.dwExStyle
& WS_EX_LEFTSCROLLBAR
) != 0)
1060 TempRect
.right
= TempRect
.left
+ GetSystemMetrics(SM_CXVSCROLL
);
1062 TempRect
.left
= TempRect
.right
- GetSystemMetrics(SM_CXVSCROLL
);
1063 if (PtInRect(&TempRect
, Point
))
1066 else if (wi
.dwStyle
& WS_HSCROLL
)
1068 RECT TempRect
= WindowRect
;
1069 TempRect
.top
= TempRect
.bottom
- GetSystemMetrics(SM_CYHSCROLL
);
1070 if (PtInRect(&TempRect
, Point
))
1080 ThemeWndProc(HWND hWnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
, WNDPROC DefWndProc
)
1085 return ThemeHandleNCPaint(hWnd
, (HRGN
)wParam
);
1087 // WM_NCUAHDRAWCAPTION : wParam are DC_* flags.
1089 case WM_NCUAHDRAWCAPTION
:
1091 // WM_NCUAHDRAWFRAME : wParam is HDC, lParam are DC_ACTIVE and or DC_REDRAWHUNGWND.
1093 case WM_NCUAHDRAWFRAME
:
1096 if ((GetWindowLongW(hWnd
, GWL_STYLE
) & WS_CAPTION
) != WS_CAPTION
)
1099 ThemeHandleNCPaint(hWnd
, (HRGN
)1);
1101 case WM_NCMOUSEMOVE
:
1104 Point
.x
= GET_X_LPARAM(lParam
);
1105 Point
.y
= GET_Y_LPARAM(lParam
);
1106 return ThemeHandleNcMouseMove(hWnd
, wParam
, &Point
);
1108 case WM_NCMOUSELEAVE
:
1109 return ThemeHandleNcMouseLeave(hWnd
);
1110 case WM_NCLBUTTONDOWN
:
1117 ThemeHandleButton(hWnd
, wParam
);
1121 return DefWndProc(hWnd
, Msg
, wParam
, lParam
);
1126 Point
.x
= GET_X_LPARAM(lParam
);
1127 Point
.y
= GET_Y_LPARAM(lParam
);
1128 return DefWndNCHitTest(hWnd
, Point
);
1132 if((wParam
& 0xfff0) == SC_VSCROLL
||
1133 (wParam
& 0xfff0) == SC_HSCROLL
)
1136 Pt
.x
= (short)LOWORD(lParam
);
1137 Pt
.y
= (short)HIWORD(lParam
);
1138 NC_TrackScrollBar(hWnd
, wParam
, Pt
);
1143 return DefWndProc(hWnd
, Msg
, wParam
, lParam
);
1147 return DefWndProc(hWnd
, Msg
, wParam
, lParam
);
1151 HRESULT WINAPI
DrawNCPreview(HDC hDC
,
1154 LPCWSTR pszThemeFileName
,
1155 LPCWSTR pszColorName
,
1156 LPCWSTR pszSizeName
,
1157 PNONCLIENTMETRICSW pncMetrics
,
1158 COLORREF
* lpaRgbValues
)
1160 WNDCLASSEXW DummyPreviewWindowClass
;
1163 HTHEMEFILE hThemeFile
;
1164 DRAW_CONTEXT context
;
1167 /* FIXME: We also need to implement drawing the rest of the preview windows
1168 * and make use of the ncmetrics and colors passed as parameters */
1170 /* Create a dummy window that will be used to trick the paint funtions */
1171 memset(&DummyPreviewWindowClass
, 0, sizeof(DummyPreviewWindowClass
));
1172 DummyPreviewWindowClass
.cbSize
= sizeof(DummyPreviewWindowClass
);
1173 DummyPreviewWindowClass
.lpszClassName
= L
"DummyPreviewWindowClass";
1174 DummyPreviewWindowClass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+1);
1175 DummyPreviewWindowClass
.hInstance
= hDllInst
;
1176 DummyPreviewWindowClass
.lpfnWndProc
= DefWindowProcW
;
1177 if (!RegisterClassExW(&DummyPreviewWindowClass
))
1180 hwndDummy
= CreateWindowExW(0, L
"DummyPreviewWindowClass", L
"Active window", WS_OVERLAPPEDWINDOW
,30,30,300,150,0,0,hDllInst
,NULL
);
1184 hres
= OpenThemeFile(pszThemeFileName
, pszColorName
, pszSizeName
, &hThemeFile
,0);
1188 /* Initialize the special draw context for the preview */
1190 context
.hWnd
= hwndDummy
;
1191 context
.theme
= OpenThemeDataFromFile(hThemeFile
, hwndDummy
, L
"WINDOW", 0);
1194 context
.scrolltheme
= OpenThemeDataFromFile(hThemeFile
, hwndDummy
, L
"SCROLLBAR", 0);
1197 context
.Active
= TRUE
;
1198 context
.wi
.cbSize
= sizeof(context
.wi
);
1199 if (!GetWindowInfo(hwndDummy
, &context
.wi
))
1201 context
.wi
.dwStyle
|= WS_VISIBLE
;
1202 context
.CaptionHeight
= context
.wi
.cyWindowBorders
;
1203 context
.CaptionHeight
+= GetSystemMetrics(context
.wi
.dwExStyle
& WS_EX_TOOLWINDOW
? SM_CYSMCAPTION
: SM_CYCAPTION
);
1204 context
.hRgn
= CreateRectRgnIndirect(&context
.wi
.rcWindow
);
1206 /* Paint the window on the preview hDC */
1207 rcCurrent
= context
.wi
.rcWindow
;
1208 ThemePaintWindow(&context
, &rcCurrent
, FALSE
);
1210 ThemeCleanupDrawContext(&context
);
1213 DestroyWindow(hwndDummy
);
1214 UnregisterClassW(L
"DummyPreviewWindowClass", hDllInst
);