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