1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Win32k subsystem 4 * PURPOSE: Window painting function 5 * FILE: win32ss/user/ntuser/painting.c 6 * PROGRAMER: Filip Navara (xnavara@volny.cz) 7 */ 8 9 #include <win32k.h> 10 DBG_DEFAULT_CHANNEL(UserPainting); 11 12 BOOL UserExtTextOutW(HDC hdc, INT x, INT y, UINT flags, PRECTL lprc, 13 LPCWSTR lpString, UINT count); 14 15 /* PRIVATE FUNCTIONS **********************************************************/ 16 17 /** 18 * @name IntIntersectWithParents 19 * 20 * Intersect window rectangle with all parent client rectangles. 21 * 22 * @param Child 23 * Pointer to child window to start intersecting from. 24 * @param WindowRect 25 * Pointer to rectangle that we want to intersect in screen 26 * coordinates on input and intersected rectangle on output (if TRUE 27 * is returned). 28 * 29 * @return 30 * If any parent is minimized or invisible or the resulting rectangle 31 * is empty then FALSE is returned. Otherwise TRUE is returned. 32 */ 33 34 BOOL FASTCALL 35 IntIntersectWithParents(PWND Child, RECTL *WindowRect) 36 { 37 PWND ParentWnd; 38 39 if (Child->ExStyle & WS_EX_REDIRECTED) 40 return TRUE; 41 42 ParentWnd = Child->spwndParent; 43 while (ParentWnd != NULL) 44 { 45 if (!(ParentWnd->style & WS_VISIBLE) || 46 (ParentWnd->style & WS_MINIMIZE) || 47 !RECTL_bIntersectRect(WindowRect, WindowRect, &ParentWnd->rcClient) ) 48 { 49 return FALSE; 50 } 51 52 if (ParentWnd->ExStyle & WS_EX_REDIRECTED) 53 return TRUE; 54 55 ParentWnd = ParentWnd->spwndParent; 56 } 57 58 return TRUE; 59 } 60 61 BOOL FASTCALL 62 IntValidateParents(PWND Child, BOOL Recurse) 63 { 64 RECTL ParentRect, Rect; 65 BOOL Start, Ret = TRUE; 66 PWND ParentWnd = Child; 67 PREGION Rgn = NULL; 68 69 if (ParentWnd->style & WS_CHILD) 70 { 71 do 72 ParentWnd = ParentWnd->spwndParent; 73 while (ParentWnd->style & WS_CHILD); 74 } 75 76 // No pending nonclient paints. 77 if (!(ParentWnd->state & WNDS_SYNCPAINTPENDING)) Recurse = FALSE; 78 79 Start = TRUE; 80 ParentWnd = Child->spwndParent; 81 while (ParentWnd) 82 { 83 if (ParentWnd->style & WS_CLIPCHILDREN) 84 break; 85 86 if (ParentWnd->hrgnUpdate != 0) 87 { 88 if (Recurse) 89 { 90 Ret = FALSE; 91 break; 92 } 93 // Start with child clipping. 94 if (Start) 95 { 96 Start = FALSE; 97 98 Rect = Child->rcWindow; 99 100 if (!IntIntersectWithParents(Child, &Rect)) break; 101 102 Rgn = IntSysCreateRectpRgnIndirect(&Rect); 103 104 if (Child->hrgnClip) 105 { 106 PREGION RgnClip = REGION_LockRgn(Child->hrgnClip); 107 IntGdiCombineRgn(Rgn, Rgn, RgnClip, RGN_AND); 108 REGION_UnlockRgn(RgnClip); 109 } 110 } 111 112 ParentRect = ParentWnd->rcWindow; 113 114 if (!IntIntersectWithParents(ParentWnd, &ParentRect)) break; 115 116 IntInvalidateWindows( ParentWnd, 117 Rgn, 118 RDW_VALIDATE | RDW_NOCHILDREN | RDW_NOUPDATEDIRTY); 119 } 120 ParentWnd = ParentWnd->spwndParent; 121 } 122 123 if (Rgn) REGION_Delete(Rgn); 124 125 return Ret; 126 } 127 128 /* 129 Synchronize painting to the top-level windows of other threads. 130 */ 131 VOID FASTCALL 132 IntSendSyncPaint(PWND Wnd, ULONG Flags) 133 { 134 PTHREADINFO ptiCur, ptiWnd; 135 PUSER_SENT_MESSAGE Message; 136 PLIST_ENTRY Entry; 137 BOOL bSend = TRUE; 138 139 ptiWnd = Wnd->head.pti; 140 ptiCur = PsGetCurrentThreadWin32Thread(); 141 /* 142 Not the current thread, Wnd is in send Nonclient paint also in send erase background and it is visiable. 143 */ 144 if ( Wnd->head.pti != ptiCur && 145 Wnd->state & WNDS_SENDNCPAINT && 146 Wnd->state & WNDS_SENDERASEBACKGROUND && 147 Wnd->style & WS_VISIBLE) 148 { 149 // For testing, if you see this, break out the Champagne and have a party! 150 TRACE("SendSyncPaint Wnd in State!\n"); 151 if (!IsListEmpty(&ptiWnd->SentMessagesListHead)) 152 { 153 // Scan sent queue messages to see if we received sync paint messages. 154 Entry = ptiWnd->SentMessagesListHead.Flink; 155 Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry); 156 do 157 { 158 ERR("LOOP it\n"); 159 if (Message->Msg.message == WM_SYNCPAINT && 160 Message->Msg.hwnd == UserHMGetHandle(Wnd)) 161 { // Already received so exit out. 162 ERR("SendSyncPaint Found one in the Sent Msg Queue!\n"); 163 bSend = FALSE; 164 break; 165 } 166 Entry = Message->ListEntry.Flink; 167 Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry); 168 } 169 while (Entry != &ptiWnd->SentMessagesListHead); 170 } 171 if (bSend) 172 { 173 TRACE("Sending WM_SYNCPAINT\n"); 174 // This message has no parameters. But it does! Pass Flags along. 175 co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_SYNCPAINT, Flags, 0); 176 Wnd->state |= WNDS_SYNCPAINTPENDING; 177 } 178 } 179 180 // Send to all the children if this is the desktop window. 181 if (UserIsDesktopWindow(Wnd)) 182 { 183 if ( Flags & RDW_ALLCHILDREN || 184 ( !(Flags & RDW_NOCHILDREN) && Wnd->style & WS_CLIPCHILDREN)) 185 { 186 PWND spwndChild = Wnd->spwndChild; 187 while(spwndChild) 188 { 189 if ( spwndChild->style & WS_CHILD && 190 spwndChild->head.pti != ptiCur) 191 { 192 spwndChild = spwndChild->spwndNext; 193 continue; 194 } 195 IntSendSyncPaint( spwndChild, Flags ); 196 spwndChild = spwndChild->spwndNext; 197 } 198 } 199 } 200 } 201 202 /* 203 * @name IntCalcWindowRgn 204 * 205 * Get a window or client region. 206 */ 207 208 HRGN FASTCALL 209 IntCalcWindowRgn(PWND Wnd, BOOL Client) 210 { 211 HRGN hRgnWindow; 212 213 if (Client) 214 { 215 hRgnWindow = NtGdiCreateRectRgn( 216 Wnd->rcClient.left, 217 Wnd->rcClient.top, 218 Wnd->rcClient.right, 219 Wnd->rcClient.bottom); 220 } 221 else 222 { 223 hRgnWindow = NtGdiCreateRectRgn( 224 Wnd->rcWindow.left, 225 Wnd->rcWindow.top, 226 Wnd->rcWindow.right, 227 Wnd->rcWindow.bottom); 228 } 229 230 if (Wnd->hrgnClip != NULL && !(Wnd->style & WS_MINIMIZE)) 231 { 232 NtGdiOffsetRgn(hRgnWindow, 233 -Wnd->rcWindow.left, 234 -Wnd->rcWindow.top); 235 NtGdiCombineRgn(hRgnWindow, hRgnWindow, Wnd->hrgnClip, RGN_AND); 236 NtGdiOffsetRgn(hRgnWindow, 237 Wnd->rcWindow.left, 238 Wnd->rcWindow.top); 239 } 240 241 return hRgnWindow; 242 } 243 244 /* 245 * @name IntGetNCUpdateRgn 246 * 247 * Get non-client update region of a window and optionally validate it. 248 * 249 * @param Window 250 * Pointer to window to get the NC update region from. 251 * @param Validate 252 * Set to TRUE to force validating the NC update region. 253 * 254 * @return 255 * Handle to NC update region. The caller is responsible for deleting 256 * it. 257 */ 258 259 HRGN FASTCALL 260 IntGetNCUpdateRgn(PWND Window, BOOL Validate) 261 { 262 HRGN hRgnNonClient; 263 HRGN hRgnWindow; 264 UINT RgnType, NcType; 265 RECT update; 266 267 if (Window->hrgnUpdate != NULL && 268 Window->hrgnUpdate != HRGN_WINDOW) 269 { 270 hRgnNonClient = IntCalcWindowRgn(Window, FALSE); 271 272 /* 273 * If region creation fails it's safe to fallback to whole 274 * window region. 275 */ 276 if (hRgnNonClient == NULL) 277 { 278 return HRGN_WINDOW; 279 } 280 281 hRgnWindow = IntCalcWindowRgn(Window, TRUE); 282 if (hRgnWindow == NULL) 283 { 284 GreDeleteObject(hRgnNonClient); 285 return HRGN_WINDOW; 286 } 287 288 NcType = IntGdiGetRgnBox(hRgnNonClient, &update); 289 290 RgnType = NtGdiCombineRgn(hRgnNonClient, hRgnNonClient, hRgnWindow, RGN_DIFF); 291 292 if (RgnType == ERROR) 293 { 294 GreDeleteObject(hRgnWindow); 295 GreDeleteObject(hRgnNonClient); 296 return HRGN_WINDOW; 297 } 298 else if (RgnType == NULLREGION) 299 { 300 GreDeleteObject(hRgnWindow); 301 GreDeleteObject(hRgnNonClient); 302 Window->state &= ~WNDS_UPDATEDIRTY; 303 return NULL; 304 } 305 306 /* 307 * Remove the nonclient region from the standard update region if 308 * we were asked for it. 309 */ 310 311 if (Validate) 312 { 313 if (NtGdiCombineRgn(Window->hrgnUpdate, Window->hrgnUpdate, hRgnWindow, RGN_AND) == NULLREGION) 314 { 315 IntGdiSetRegionOwner(Window->hrgnUpdate, GDI_OBJ_HMGR_POWNED); 316 GreDeleteObject(Window->hrgnUpdate); 317 Window->state &= ~WNDS_UPDATEDIRTY; 318 Window->hrgnUpdate = NULL; 319 if (!(Window->state & WNDS_INTERNALPAINT)) 320 MsqDecPaintCountQueue(Window->head.pti); 321 } 322 } 323 324 /* check if update rgn contains complete nonclient area */ 325 if (NcType == SIMPLEREGION) 326 { 327 RECT window; 328 IntGetWindowRect( Window, &window ); 329 330 if (IntEqualRect( &window, &update )) 331 { 332 GreDeleteObject(hRgnNonClient); 333 hRgnNonClient = HRGN_WINDOW; 334 } 335 } 336 337 GreDeleteObject(hRgnWindow); 338 339 return hRgnNonClient; 340 } 341 else 342 { 343 return Window->hrgnUpdate; 344 } 345 } 346 347 VOID FASTCALL 348 IntSendNCPaint(PWND pWnd, HRGN hRgn) 349 { 350 pWnd->state &= ~WNDS_SENDNCPAINT; 351 352 if ( pWnd == GetW32ThreadInfo()->MessageQueue->spwndActive && 353 !(pWnd->state & WNDS_ACTIVEFRAME)) 354 { 355 pWnd->state |= WNDS_ACTIVEFRAME; 356 pWnd->state &= ~WNDS_NONCPAINT; 357 hRgn = HRGN_WINDOW; 358 } 359 360 if (pWnd->state2 & WNDS2_FORCEFULLNCPAINTCLIPRGN) 361 { 362 pWnd->state2 &= ~WNDS2_FORCEFULLNCPAINTCLIPRGN; 363 hRgn = HRGN_WINDOW; 364 } 365 366 if (hRgn) co_IntSendMessage(UserHMGetHandle(pWnd), WM_NCPAINT, (WPARAM)hRgn, 0); 367 } 368 369 VOID FASTCALL 370 IntSendChildNCPaint(PWND pWnd) 371 { 372 pWnd = pWnd->spwndChild; 373 while (pWnd) 374 { 375 if ((pWnd->hrgnUpdate == NULL) && (pWnd->state & WNDS_SENDNCPAINT)) 376 { 377 PWND Next; 378 USER_REFERENCE_ENTRY Ref; 379 380 /* Reference, IntSendNCPaint leaves win32k */ 381 UserRefObjectCo(pWnd, &Ref); 382 IntSendNCPaint(pWnd, HRGN_WINDOW); 383 384 /* Make sure to grab next one before dereferencing/freeing */ 385 Next = pWnd->spwndNext; 386 UserDerefObjectCo(pWnd); 387 pWnd = Next; 388 } 389 else 390 { 391 pWnd = pWnd->spwndNext; 392 } 393 } 394 } 395 396 /* 397 * IntPaintWindows 398 * 399 * Internal function used by IntRedrawWindow. 400 */ 401 402 VOID FASTCALL 403 co_IntPaintWindows(PWND Wnd, ULONG Flags, BOOL Recurse) 404 { 405 HDC hDC; 406 HWND hWnd = Wnd->head.h; 407 HRGN TempRegion = NULL; 408 409 Wnd->state &= ~WNDS_PAINTNOTPROCESSED; 410 411 if (Wnd->state & WNDS_SENDNCPAINT || 412 Wnd->state & WNDS_SENDERASEBACKGROUND) 413 { 414 if (!(Wnd->style & WS_VISIBLE)) 415 { 416 Wnd->state &= ~(WNDS_SENDNCPAINT|WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND); 417 return; 418 } 419 else 420 { 421 if (Wnd->hrgnUpdate == NULL) 422 { 423 Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND); 424 } 425 426 if (Wnd->head.pti == PsGetCurrentThreadWin32Thread()) 427 { 428 if (Wnd->state & WNDS_SENDNCPAINT) 429 { 430 TempRegion = IntGetNCUpdateRgn(Wnd, TRUE); 431 432 IntSendNCPaint(Wnd, TempRegion); 433 434 if (TempRegion > HRGN_WINDOW && GreIsHandleValid(TempRegion)) 435 { 436 /* NOTE: The region can already be deleted! */ 437 GreDeleteObject(TempRegion); 438 } 439 } 440 441 if (Wnd->state & WNDS_SENDERASEBACKGROUND) 442 { 443 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 444 if (Wnd->hrgnUpdate) 445 { 446 hDC = UserGetDCEx( Wnd, 447 Wnd->hrgnUpdate, 448 DCX_CACHE|DCX_USESTYLE|DCX_INTERSECTRGN|DCX_KEEPCLIPRGN); 449 450 if (Wnd->head.pti->ppi != pti->ppi) 451 { 452 ERR("Sending DC to another Process!!!\n"); 453 } 454 455 Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND); 456 // Kill the loop, so Clear before we send. 457 if (!co_IntSendMessage(hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0)) 458 { 459 Wnd->state |= (WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND); 460 } 461 UserReleaseDC(Wnd, hDC, FALSE); 462 } 463 } 464 } 465 466 } 467 } 468 469 /* 470 * Check that the window is still valid at this point 471 */ 472 if (!IntIsWindow(hWnd)) 473 { 474 return; 475 } 476 477 /* 478 * Paint child windows. 479 */ 480 481 if (!(Flags & RDW_NOCHILDREN) && 482 !(Wnd->style & WS_MINIMIZE) && 483 ( Flags & RDW_ALLCHILDREN || 484 (Flags & RDW_CLIPCHILDREN && Wnd->style & WS_CLIPCHILDREN) ) ) 485 { 486 HWND *List, *phWnd; 487 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 488 489 if ((List = IntWinListChildren(Wnd))) 490 { 491 for (phWnd = List; *phWnd; ++phWnd) 492 { 493 if ((Wnd = UserGetWindowObject(*phWnd)) == NULL) 494 continue; 495 496 if (Wnd->head.pti != pti && Wnd->style & WS_CHILD) 497 continue; 498 499 if (Wnd->style & WS_VISIBLE) 500 { 501 USER_REFERENCE_ENTRY Ref; 502 UserRefObjectCo(Wnd, &Ref); 503 co_IntPaintWindows(Wnd, Flags, TRUE); 504 UserDerefObjectCo(Wnd); 505 } 506 } 507 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 508 } 509 } 510 } 511 512 /* 513 * IntUpdateWindows 514 * 515 * Internal function used by IntRedrawWindow, simplecall. 516 */ 517 518 VOID FASTCALL 519 co_IntUpdateWindows(PWND Wnd, ULONG Flags, BOOL Recurse) 520 { 521 HWND hWnd = Wnd->head.h; 522 523 if ( Wnd->hrgnUpdate != NULL || Wnd->state & WNDS_INTERNALPAINT ) 524 { 525 if (Wnd->hrgnUpdate) 526 { 527 if (!IntValidateParents(Wnd, Recurse)) 528 { 529 return; 530 } 531 } 532 533 if (Wnd->state & WNDS_INTERNALPAINT) 534 { 535 Wnd->state &= ~WNDS_INTERNALPAINT; 536 537 if (Wnd->hrgnUpdate == NULL) 538 MsqDecPaintCountQueue(Wnd->head.pti); 539 } 540 541 Wnd->state |= WNDS_PAINTNOTPROCESSED; 542 Wnd->state &= ~WNDS_UPDATEDIRTY; 543 544 Wnd->state2 |= WNDS2_WMPAINTSENT; 545 co_IntSendMessage(hWnd, WM_PAINT, 0, 0); 546 547 if (Wnd->state & WNDS_PAINTNOTPROCESSED) 548 { 549 USER_REFERENCE_ENTRY Ref; 550 UserRefObjectCo(Wnd, &Ref); 551 co_IntPaintWindows(Wnd, RDW_NOCHILDREN, FALSE); 552 UserDerefObjectCo(Wnd); 553 } 554 } 555 556 // Force flags as a toggle. Fixes msg:test_paint_messages:WmChildPaintNc. 557 Flags = (Flags & RDW_NOCHILDREN) ? RDW_NOCHILDREN : RDW_ALLCHILDREN; // All children is the default. 558 559 /* 560 * Update child windows. 561 */ 562 563 if (!(Flags & RDW_NOCHILDREN) && 564 (Flags & RDW_ALLCHILDREN) && 565 !UserIsDesktopWindow(Wnd)) 566 { 567 PWND Child; 568 569 for (Child = Wnd->spwndChild; Child; Child = Child->spwndNext) 570 { 571 /* transparent window, check for non-transparent sibling to paint first, then skip it */ 572 if ( Child->ExStyle & WS_EX_TRANSPARENT && 573 ( Child->hrgnUpdate != NULL || Child->state & WNDS_INTERNALPAINT ) ) 574 { 575 PWND Next = Child->spwndNext; 576 while (Next) 577 { 578 if ( Next->hrgnUpdate != NULL || Next->state & WNDS_INTERNALPAINT ) break; 579 580 Next = Next->spwndNext; 581 } 582 583 if (Next) continue; 584 } 585 586 if (Child->style & WS_VISIBLE) 587 { 588 USER_REFERENCE_ENTRY Ref; 589 UserRefObjectCo(Child, &Ref); 590 co_IntUpdateWindows(Child, Flags, TRUE); 591 UserDerefObjectCo(Child); 592 } 593 } 594 } 595 } 596 597 VOID FASTCALL 598 UserUpdateWindows(PWND pWnd, ULONG Flags) 599 { 600 // If transparent and any sibling windows below needs to be painted, leave. 601 if (pWnd->ExStyle & WS_EX_TRANSPARENT) 602 { 603 PWND Next = pWnd->spwndNext; 604 605 while(Next) 606 { 607 if ( Next->head.pti == pWnd->head.pti && 608 ( Next->hrgnUpdate != NULL || Next->state & WNDS_INTERNALPAINT) ) 609 { 610 return; 611 } 612 613 Next = Next->spwndNext; 614 } 615 } 616 co_IntUpdateWindows(pWnd, Flags, FALSE); 617 } 618 619 VOID FASTCALL 620 UserSyncAndPaintWindows(PWND pWnd, ULONG Flags) 621 { 622 PWND Parent = pWnd; 623 // Find parent, if it needs to be painted, leave. 624 while(TRUE) 625 { 626 if ((Parent = Parent->spwndParent) == NULL) break; 627 if ( Parent->style & WS_CLIPCHILDREN ) break; 628 if ( Parent->hrgnUpdate != NULL || Parent->state & WNDS_INTERNALPAINT ) return; 629 } 630 631 IntSendSyncPaint(pWnd, Flags); 632 co_IntPaintWindows(pWnd, Flags, FALSE); 633 } 634 635 /* 636 * IntInvalidateWindows 637 * 638 * Internal function used by IntRedrawWindow, UserRedrawDesktop, 639 * co_WinPosSetWindowPos, co_UserRedrawWindow. 640 */ 641 VOID FASTCALL 642 IntInvalidateWindows(PWND Wnd, PREGION Rgn, ULONG Flags) 643 { 644 INT RgnType = NULLREGION; 645 BOOL HadPaintMessage; 646 647 TRACE("IntInvalidateWindows start Rgn %p\n",Rgn); 648 649 if ( Rgn > PRGN_WINDOW ) 650 { 651 /* 652 * If the nonclient is not to be redrawn, clip the region to the client 653 * rect 654 */ 655 if ((Flags & RDW_INVALIDATE) != 0 && (Flags & RDW_FRAME) == 0) 656 { 657 PREGION RgnClient; 658 659 RgnClient = IntSysCreateRectpRgnIndirect(&Wnd->rcClient); 660 if (RgnClient) 661 { 662 RgnType = IntGdiCombineRgn(Rgn, Rgn, RgnClient, RGN_AND); 663 REGION_Delete(RgnClient); 664 } 665 } 666 667 /* 668 * Clip the given region with window rectangle (or region) 669 */ 670 671 if (!Wnd->hrgnClip || (Wnd->style & WS_MINIMIZE)) 672 { 673 PREGION RgnWindow = IntSysCreateRectpRgnIndirect(&Wnd->rcWindow); 674 if (RgnWindow) 675 { 676 RgnType = IntGdiCombineRgn(Rgn, Rgn, RgnWindow, RGN_AND); 677 REGION_Delete(RgnWindow); 678 } 679 } 680 else 681 { 682 PREGION RgnClip = REGION_LockRgn(Wnd->hrgnClip); 683 if (RgnClip) 684 { 685 REGION_bOffsetRgn(Rgn, 686 -Wnd->rcWindow.left, 687 -Wnd->rcWindow.top); 688 RgnType = IntGdiCombineRgn(Rgn, Rgn, RgnClip, RGN_AND); 689 REGION_bOffsetRgn(Rgn, 690 Wnd->rcWindow.left, 691 Wnd->rcWindow.top); 692 REGION_UnlockRgn(RgnClip); 693 } 694 } 695 } 696 else 697 { 698 RgnType = NULLREGION; 699 } 700 701 /* 702 * Save current state of pending updates 703 */ 704 705 HadPaintMessage = IntIsWindowDirty(Wnd); 706 707 /* 708 * Update the region and flags 709 */ 710 711 // The following flags are used to invalidate the window. 712 if (Flags & (RDW_INVALIDATE|RDW_INTERNALPAINT|RDW_ERASE|RDW_FRAME)) 713 { 714 if (Flags & RDW_INTERNALPAINT) 715 { 716 Wnd->state |= WNDS_INTERNALPAINT; 717 } 718 719 if (Flags & RDW_INVALIDATE ) 720 { 721 PREGION RgnUpdate; 722 723 Wnd->state &= ~WNDS_NONCPAINT; 724 725 /* If not the same thread set it dirty. */ 726 if (Wnd->head.pti != PsGetCurrentThreadWin32Thread()) 727 { 728 Wnd->state |= WNDS_UPDATEDIRTY; 729 if (Wnd->state2 & WNDS2_WMPAINTSENT) 730 Wnd->state2 |= WNDS2_ENDPAINTINVALIDATE; 731 } 732 733 if (Flags & RDW_FRAME) 734 Wnd->state |= WNDS_SENDNCPAINT; 735 736 if (Flags & RDW_ERASE) 737 Wnd->state |= WNDS_SENDERASEBACKGROUND; 738 739 if (RgnType != NULLREGION && Rgn > PRGN_WINDOW) 740 { 741 if (Wnd->hrgnUpdate == NULL) 742 { 743 Wnd->hrgnUpdate = NtGdiCreateRectRgn(0, 0, 0, 0); 744 IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_PUBLIC); 745 } 746 747 if (Wnd->hrgnUpdate != HRGN_WINDOW) 748 { 749 RgnUpdate = REGION_LockRgn(Wnd->hrgnUpdate); 750 if (RgnUpdate) 751 { 752 RgnType = IntGdiCombineRgn(RgnUpdate, RgnUpdate, Rgn, RGN_OR); 753 REGION_UnlockRgn(RgnUpdate); 754 if (RgnType == NULLREGION) 755 { 756 IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_POWNED); 757 GreDeleteObject(Wnd->hrgnUpdate); 758 Wnd->hrgnUpdate = NULL; 759 } 760 } 761 } 762 } 763 764 Flags |= RDW_ERASE|RDW_FRAME; // For children. 765 766 } 767 768 if (!HadPaintMessage && IntIsWindowDirty(Wnd)) 769 { 770 MsqIncPaintCountQueue(Wnd->head.pti); 771 } 772 773 } // The following flags are used to validate the window. 774 else if (Flags & (RDW_VALIDATE|RDW_NOINTERNALPAINT|RDW_NOERASE|RDW_NOFRAME)) 775 { 776 if (Wnd->state & WNDS_UPDATEDIRTY && !(Flags & RDW_NOUPDATEDIRTY)) 777 return; 778 779 if (Flags & RDW_NOINTERNALPAINT) 780 { 781 Wnd->state &= ~WNDS_INTERNALPAINT; 782 } 783 784 if (Flags & RDW_VALIDATE) 785 { 786 if (Flags & RDW_NOFRAME) 787 Wnd->state &= ~WNDS_SENDNCPAINT; 788 789 if (Flags & RDW_NOERASE) 790 Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND); 791 792 if (Wnd->hrgnUpdate > HRGN_WINDOW && RgnType != NULLREGION && Rgn > PRGN_WINDOW) 793 { 794 PREGION RgnUpdate = REGION_LockRgn(Wnd->hrgnUpdate); 795 796 if (RgnUpdate) 797 { 798 RgnType = IntGdiCombineRgn(RgnUpdate, RgnUpdate, Rgn, RGN_DIFF); 799 REGION_UnlockRgn(RgnUpdate); 800 801 if (RgnType == NULLREGION) 802 { 803 IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_POWNED); 804 GreDeleteObject(Wnd->hrgnUpdate); 805 Wnd->hrgnUpdate = NULL; 806 } 807 } 808 } 809 // If update is null, do not erase. 810 if (Wnd->hrgnUpdate == NULL) 811 { 812 Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND); 813 } 814 } 815 816 if (HadPaintMessage && !IntIsWindowDirty(Wnd)) 817 { 818 MsqDecPaintCountQueue(Wnd->head.pti); 819 } 820 } 821 822 /* 823 * Process children if needed 824 */ 825 826 if (!(Flags & RDW_NOCHILDREN) && 827 !(Wnd->style & WS_MINIMIZE) && 828 ((Flags & RDW_ALLCHILDREN) || !(Wnd->style & WS_CLIPCHILDREN))) 829 { 830 PWND Child; 831 832 for (Child = Wnd->spwndChild; Child; Child = Child->spwndNext) 833 { 834 if (Child->style & WS_VISIBLE) 835 { 836 /* 837 * Recursive call to update children hrgnUpdate 838 */ 839 PREGION RgnTemp = IntSysCreateRectpRgn(0, 0, 0, 0); 840 if (RgnTemp) 841 { 842 if (Rgn > PRGN_WINDOW) IntGdiCombineRgn(RgnTemp, Rgn, 0, RGN_COPY); 843 IntInvalidateWindows(Child, ((Rgn > PRGN_WINDOW)?RgnTemp:Rgn), Flags); 844 REGION_Delete(RgnTemp); 845 } 846 } 847 } 848 } 849 TRACE("IntInvalidateWindows exit\n"); 850 } 851 852 /* 853 * IntIsWindowDrawable 854 * 855 * Remarks 856 * Window is drawable when it is visible and all parents are not 857 * minimized. 858 */ 859 860 BOOL FASTCALL 861 IntIsWindowDrawable(PWND Wnd) 862 { 863 PWND WndObject; 864 865 for (WndObject = Wnd; WndObject != NULL; WndObject = WndObject->spwndParent) 866 { 867 if ( WndObject->state2 & WNDS2_INDESTROY || 868 WndObject->state & WNDS_DESTROYED || 869 !WndObject || 870 !(WndObject->style & WS_VISIBLE) || 871 ((WndObject->style & WS_MINIMIZE) && (WndObject != Wnd))) 872 { 873 return FALSE; 874 } 875 } 876 877 return TRUE; 878 } 879 880 /* 881 * IntRedrawWindow 882 * 883 * Internal version of NtUserRedrawWindow that takes WND as 884 * first parameter. 885 */ 886 887 BOOL FASTCALL 888 co_UserRedrawWindow( 889 PWND Window, 890 const RECTL* UpdateRect, 891 PREGION UpdateRgn, 892 ULONG Flags) 893 { 894 PREGION TmpRgn = NULL; 895 TRACE("co_UserRedrawWindow start Rgn %p\n",UpdateRgn); 896 897 /* 898 * Step 1. 899 * Validation of passed parameters. 900 */ 901 902 if (!IntIsWindowDrawable(Window)) 903 { 904 return TRUE; // Just do nothing!!! 905 } 906 907 if (Window == NULL) 908 { 909 Window = UserGetDesktopWindow(); 910 } 911 912 /* 913 * Step 2. 914 * Transform the parameters UpdateRgn and UpdateRect into 915 * a region hRgn specified in screen coordinates. 916 */ 917 918 if (Flags & (RDW_INVALIDATE | RDW_VALIDATE)) // Both are OKAY! 919 { 920 /* We can't hold lock on GDI objects while doing roundtrips to user mode, 921 * so use a copy instead */ 922 if (UpdateRgn) 923 { 924 TmpRgn = IntSysCreateRectpRgn(0, 0, 0, 0); 925 926 if (UpdateRgn > PRGN_WINDOW) 927 { 928 IntGdiCombineRgn(TmpRgn, UpdateRgn, NULL, RGN_COPY); 929 } 930 931 if (Window != UserGetDesktopWindow()) 932 { 933 REGION_bOffsetRgn(TmpRgn, Window->rcClient.left, Window->rcClient.top); 934 } 935 } 936 else 937 { 938 if (UpdateRect != NULL) 939 { 940 if (Window == UserGetDesktopWindow()) 941 { 942 TmpRgn = IntSysCreateRectpRgnIndirect(UpdateRect); 943 } 944 else 945 { 946 TmpRgn = IntSysCreateRectpRgn(Window->rcClient.left + UpdateRect->left, 947 Window->rcClient.top + UpdateRect->top, 948 Window->rcClient.left + UpdateRect->right, 949 Window->rcClient.top + UpdateRect->bottom); 950 } 951 } 952 else 953 { 954 if ((Flags & (RDW_INVALIDATE | RDW_FRAME)) == (RDW_INVALIDATE | RDW_FRAME) || 955 (Flags & (RDW_VALIDATE | RDW_NOFRAME)) == (RDW_VALIDATE | RDW_NOFRAME)) 956 { 957 if (!RECTL_bIsEmptyRect(&Window->rcWindow)) 958 TmpRgn = IntSysCreateRectpRgnIndirect(&Window->rcWindow); 959 } 960 else 961 { 962 if (!RECTL_bIsEmptyRect(&Window->rcClient)) 963 TmpRgn = IntSysCreateRectpRgnIndirect(&Window->rcClient); 964 } 965 } 966 } 967 } 968 969 /* Fixes test RDW_INTERNALPAINT behavior */ 970 if (TmpRgn == NULL) 971 { 972 TmpRgn = PRGN_WINDOW; // Need a region so the bits can be set!!! 973 } 974 975 /* 976 * Step 3. 977 * Adjust the window update region depending on hRgn and flags. 978 */ 979 980 if (Flags & (RDW_INVALIDATE | RDW_VALIDATE | RDW_INTERNALPAINT | RDW_NOINTERNALPAINT) && 981 TmpRgn != NULL) 982 { 983 IntInvalidateWindows(Window, TmpRgn, Flags); 984 } 985 986 /* 987 * Step 4. 988 * Repaint and erase windows if needed. 989 */ 990 991 if (Flags & RDW_UPDATENOW) 992 { 993 UserUpdateWindows(Window, Flags); 994 } 995 else if (Flags & RDW_ERASENOW) 996 { 997 if ((Flags & (RDW_NOCHILDREN|RDW_ALLCHILDREN)) == 0) 998 Flags |= RDW_CLIPCHILDREN; 999 1000 UserSyncAndPaintWindows(Window, Flags); 1001 } 1002 1003 /* 1004 * Step 5. 1005 * Cleanup ;-) 1006 */ 1007 1008 if (TmpRgn > PRGN_WINDOW) 1009 { 1010 REGION_Delete(TmpRgn); 1011 } 1012 TRACE("co_UserRedrawWindow exit\n"); 1013 1014 return TRUE; 1015 } 1016 1017 VOID FASTCALL 1018 PaintSuspendedWindow(PWND pwnd, HRGN hrgnOrig) 1019 { 1020 if (pwnd->hrgnUpdate) 1021 { 1022 HDC hDC; 1023 INT Flags = DC_NC|DC_NOSENDMSG; 1024 HRGN hrgnTemp; 1025 RECT Rect; 1026 INT type; 1027 PREGION prgn; 1028 1029 if (pwnd->hrgnUpdate > HRGN_WINDOW) 1030 { 1031 hrgnTemp = NtGdiCreateRectRgn(0, 0, 0, 0); 1032 type = NtGdiCombineRgn( hrgnTemp, pwnd->hrgnUpdate, 0, RGN_COPY); 1033 if (type == ERROR) 1034 { 1035 GreDeleteObject(hrgnTemp); 1036 hrgnTemp = HRGN_WINDOW; 1037 } 1038 } 1039 else 1040 { 1041 hrgnTemp = GreCreateRectRgnIndirect(&pwnd->rcWindow); 1042 } 1043 1044 if ( hrgnOrig && 1045 hrgnTemp > HRGN_WINDOW && 1046 NtGdiCombineRgn(hrgnTemp, hrgnTemp, hrgnOrig, RGN_AND) == NULLREGION) 1047 { 1048 GreDeleteObject(hrgnTemp); 1049 return; 1050 } 1051 1052 hDC = UserGetDCEx(pwnd, hrgnTemp, DCX_WINDOW|DCX_INTERSECTRGN|DCX_USESTYLE|DCX_KEEPCLIPRGN); 1053 1054 Rect = pwnd->rcWindow; 1055 RECTL_vOffsetRect(&Rect, -pwnd->rcWindow.left, -pwnd->rcWindow.top); 1056 1057 // Clear out client area! 1058 FillRect(hDC, &Rect, IntGetSysColorBrush(COLOR_WINDOW)); 1059 1060 NC_DoNCPaint(pwnd, hDC, Flags); // Redraw without MENUs. 1061 1062 UserReleaseDC(pwnd, hDC, FALSE); 1063 1064 prgn = REGION_LockRgn(hrgnTemp); 1065 IntInvalidateWindows(pwnd, prgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN); 1066 REGION_UnlockRgn(prgn); 1067 1068 // Set updates for this window. 1069 pwnd->state |= WNDS_SENDNCPAINT|WNDS_SENDERASEBACKGROUND|WNDS_UPDATEDIRTY; 1070 1071 // DCX_KEEPCLIPRGN is set. Check it anyway. 1072 if (hrgnTemp > HRGN_WINDOW && GreIsHandleValid(hrgnTemp)) GreDeleteObject(hrgnTemp); 1073 } 1074 } 1075 1076 VOID FASTCALL 1077 UpdateTheadChildren(PWND pWnd, HRGN hRgn) 1078 { 1079 PaintSuspendedWindow( pWnd, hRgn ); 1080 1081 if (!(pWnd->style & WS_CLIPCHILDREN)) 1082 return; 1083 1084 pWnd = pWnd->spwndChild; // invalidate children if any. 1085 while (pWnd) 1086 { 1087 UpdateTheadChildren( pWnd, hRgn ); 1088 pWnd = pWnd->spwndNext; 1089 } 1090 } 1091 1092 VOID FASTCALL 1093 UpdateThreadWindows(PWND pWnd, PTHREADINFO pti, HRGN hRgn) 1094 { 1095 PWND pwndTemp; 1096 1097 for ( pwndTemp = pWnd; 1098 pwndTemp; 1099 pwndTemp = pwndTemp->spwndNext ) 1100 { 1101 if (pwndTemp->head.pti == pti) 1102 { 1103 UserUpdateWindows(pwndTemp, RDW_ALLCHILDREN); 1104 } 1105 else 1106 { 1107 if (IsThreadSuspended(pwndTemp->head.pti) || MsqIsHung(pwndTemp->head.pti, MSQ_HUNG)) 1108 { 1109 UpdateTheadChildren(pwndTemp, hRgn); 1110 } 1111 else 1112 UserUpdateWindows(pwndTemp, RDW_ALLCHILDREN); 1113 } 1114 } 1115 } 1116 1117 BOOL FASTCALL 1118 IntIsWindowDirty(PWND Wnd) 1119 { 1120 return ( Wnd->style & WS_VISIBLE && 1121 ( Wnd->hrgnUpdate != NULL || 1122 Wnd->state & WNDS_INTERNALPAINT ) ); 1123 } 1124 1125 /* 1126 Conditions to paint any window: 1127 1128 1. Update region is not null. 1129 2. Internal paint flag is set. 1130 3. Paint count is not zero. 1131 1132 */ 1133 PWND FASTCALL 1134 IntFindWindowToRepaint(PWND Window, PTHREADINFO Thread) 1135 { 1136 PWND hChild; 1137 PWND TempWindow; 1138 1139 for (; Window != NULL; Window = Window->spwndNext) 1140 { 1141 if (IntWndBelongsToThread(Window, Thread)) 1142 { 1143 if (IntIsWindowDirty(Window)) 1144 { 1145 /* Make sure all non-transparent siblings are already drawn. */ 1146 if (Window->ExStyle & WS_EX_TRANSPARENT) 1147 { 1148 for (TempWindow = Window->spwndNext; TempWindow != NULL; 1149 TempWindow = TempWindow->spwndNext) 1150 { 1151 if (!(TempWindow->ExStyle & WS_EX_TRANSPARENT) && 1152 IntWndBelongsToThread(TempWindow, Thread) && 1153 IntIsWindowDirty(TempWindow)) 1154 { 1155 return TempWindow; 1156 } 1157 } 1158 } 1159 return Window; 1160 } 1161 } 1162 /* find a child of the specified window that needs repainting */ 1163 if (Window->spwndChild) 1164 { 1165 hChild = IntFindWindowToRepaint(Window->spwndChild, Thread); 1166 if (hChild != NULL) 1167 return hChild; 1168 } 1169 } 1170 return Window; 1171 } 1172 1173 // 1174 // Internal painting of windows. 1175 // 1176 VOID FASTCALL 1177 IntPaintWindow( PWND Window ) 1178 { 1179 // Handle normal painting. 1180 co_IntPaintWindows( Window, RDW_NOCHILDREN, FALSE ); 1181 } 1182 1183 BOOL FASTCALL 1184 IntGetPaintMessage( 1185 PWND Window, 1186 UINT MsgFilterMin, 1187 UINT MsgFilterMax, 1188 PTHREADINFO Thread, 1189 MSG *Message, 1190 BOOL Remove) 1191 { 1192 PWND PaintWnd, StartWnd; 1193 1194 if ((MsgFilterMin != 0 || MsgFilterMax != 0) && 1195 (MsgFilterMin > WM_PAINT || MsgFilterMax < WM_PAINT)) 1196 return FALSE; 1197 1198 if (Thread->TIF_flags & TIF_SYSTEMTHREAD ) 1199 { 1200 ERR("WM_PAINT is in a System Thread!\n"); 1201 } 1202 1203 StartWnd = UserGetDesktopWindow(); 1204 PaintWnd = IntFindWindowToRepaint(StartWnd, Thread); 1205 1206 Message->hwnd = PaintWnd ? UserHMGetHandle(PaintWnd) : NULL; 1207 1208 if (Message->hwnd == NULL && Thread->cPaintsReady) 1209 { 1210 // Find note in window.c:"PAINTING BUG". 1211 ERR("WARNING SOMETHING HAS GONE WRONG: Thread marked as containing dirty windows, but no dirty windows found! Counts %u\n",Thread->cPaintsReady); 1212 /* Hack to stop spamming the debug log ! */ 1213 Thread->cPaintsReady = 0; 1214 return FALSE; 1215 } 1216 1217 if (Message->hwnd == NULL) 1218 return FALSE; 1219 1220 if (!(Window == NULL || 1221 PaintWnd == Window || 1222 IntIsChildWindow(Window, PaintWnd))) /* check that it is a child of the specified parent */ 1223 return FALSE; 1224 1225 if (PaintWnd->state & WNDS_INTERNALPAINT) 1226 { 1227 PaintWnd->state &= ~WNDS_INTERNALPAINT; 1228 if (!PaintWnd->hrgnUpdate) 1229 MsqDecPaintCountQueue(Thread); 1230 } 1231 PaintWnd->state2 &= ~WNDS2_STARTPAINT; 1232 PaintWnd->state &= ~WNDS_UPDATEDIRTY; 1233 1234 Window = PaintWnd; 1235 while (Window && !UserIsDesktopWindow(Window)) 1236 { 1237 // Role back and check for clip children, do not set if any. 1238 if (Window->spwndParent && !(Window->spwndParent->style & WS_CLIPCHILDREN)) 1239 { 1240 PaintWnd->state2 |= WNDS2_WMPAINTSENT; 1241 } 1242 Window = Window->spwndParent; 1243 } 1244 1245 Message->wParam = Message->lParam = 0; 1246 Message->message = WM_PAINT; 1247 return TRUE; 1248 } 1249 1250 BOOL 1251 FASTCALL 1252 IntPrintWindow( 1253 PWND pwnd, 1254 HDC hdcBlt, 1255 UINT nFlags) 1256 { 1257 HDC hdcSrc; 1258 INT cx, cy, xSrc, ySrc; 1259 1260 if ( nFlags & PW_CLIENTONLY) 1261 { 1262 cx = pwnd->rcClient.right - pwnd->rcClient.left; 1263 cy = pwnd->rcClient.bottom - pwnd->rcClient.top; 1264 xSrc = pwnd->rcClient.left - pwnd->rcWindow.left; 1265 ySrc = pwnd->rcClient.top - pwnd->rcWindow.top; 1266 } 1267 else 1268 { 1269 cx = pwnd->rcWindow.right - pwnd->rcWindow.left; 1270 cy = pwnd->rcWindow.bottom - pwnd->rcWindow.top; 1271 xSrc = 0; 1272 ySrc = 0; 1273 } 1274 1275 // TODO: Setup Redirection for Print. 1276 return FALSE; 1277 1278 /* Update the window just incase. */ 1279 co_IntUpdateWindows( pwnd, RDW_ALLCHILDREN, FALSE); 1280 1281 hdcSrc = UserGetDCEx( pwnd, NULL, DCX_CACHE|DCX_WINDOW); 1282 /* Print window to printer context. */ 1283 NtGdiBitBlt( hdcBlt, 1284 0, 1285 0, 1286 cx, 1287 cy, 1288 hdcSrc, 1289 xSrc, 1290 ySrc, 1291 SRCCOPY, 1292 0, 1293 0); 1294 1295 UserReleaseDC( pwnd, hdcSrc, FALSE); 1296 1297 // TODO: Release Redirection from Print. 1298 1299 return TRUE; 1300 } 1301 1302 BOOL 1303 FASTCALL 1304 IntFlashWindowEx(PWND pWnd, PFLASHWINFO pfwi) 1305 { 1306 DWORD_PTR FlashState; 1307 UINT uCount = pfwi->uCount; 1308 BOOL Activate = FALSE, Ret = FALSE; 1309 1310 ASSERT(pfwi); 1311 1312 FlashState = (DWORD_PTR)UserGetProp(pWnd, AtomFlashWndState, TRUE); 1313 1314 if (FlashState == FLASHW_FINISHED) 1315 { 1316 // Cycle has finished, kill timer and set this to Stop. 1317 FlashState |= FLASHW_KILLSYSTIMER; 1318 pfwi->dwFlags = FLASHW_STOP; 1319 } 1320 else 1321 { 1322 if (FlashState) 1323 { 1324 if (pfwi->dwFlags == FLASHW_SYSTIMER) 1325 { 1326 // Called from system timer, restore flags, counts and state. 1327 pfwi->dwFlags = LOWORD(FlashState); 1328 uCount = HIWORD(FlashState); 1329 FlashState = MAKELONG(LOWORD(FlashState),0); 1330 } 1331 else 1332 { 1333 // Clean out the trash! Fix SeaMonkey crash after restart. 1334 FlashState = 0; 1335 } 1336 } 1337 1338 if (FlashState == 0) 1339 { // First time in cycle, setup flash state. 1340 if ( pWnd->state & WNDS_ACTIVEFRAME || 1341 (pfwi->dwFlags & FLASHW_CAPTION && pWnd->style & (WS_BORDER|WS_DLGFRAME))) 1342 { 1343 FlashState = FLASHW_STARTED|FLASHW_ACTIVE; 1344 } 1345 } 1346 1347 // Set previous window state. 1348 Ret = !!(FlashState & FLASHW_ACTIVE); 1349 1350 if ( (pfwi->dwFlags & FLASHW_TIMERNOFG) == FLASHW_TIMERNOFG && 1351 gpqForeground == pWnd->head.pti->MessageQueue ) 1352 { 1353 // Flashing until foreground, set this to Stop. 1354 pfwi->dwFlags = FLASHW_STOP; 1355 } 1356 } 1357 1358 // Toggle activate flag. 1359 if ( pfwi->dwFlags == FLASHW_STOP ) 1360 { 1361 if (gpqForeground && gpqForeground->spwndActive == pWnd) 1362 Activate = TRUE; 1363 else 1364 Activate = FALSE; 1365 } 1366 else 1367 { 1368 Activate = (FlashState & FLASHW_ACTIVE) == 0; 1369 } 1370 1371 if ( pfwi->dwFlags == FLASHW_STOP || pfwi->dwFlags & FLASHW_CAPTION ) 1372 { 1373 co_IntSendMessage(UserHMGetHandle(pWnd), WM_NCACTIVATE, Activate, 0); 1374 } 1375 1376 // FIXME: Check for a Stop Sign here. 1377 if ( pfwi->dwFlags & FLASHW_TRAY ) 1378 { 1379 // Need some shell work here too. 1380 TRACE("FIXME: Flash window no Tray support!\n"); 1381 } 1382 1383 if ( pfwi->dwFlags == FLASHW_STOP ) 1384 { 1385 if (FlashState & FLASHW_KILLSYSTIMER) 1386 { 1387 IntKillTimer(pWnd, ID_EVENT_SYSTIMER_FLASHWIN, TRUE); 1388 } 1389 1390 UserRemoveProp(pWnd, AtomFlashWndState, TRUE); 1391 } 1392 else 1393 { // Have a count and started, set timer. 1394 if ( uCount ) 1395 { 1396 FlashState |= FLASHW_COUNT; 1397 1398 if (!(Activate ^ !!(FlashState & FLASHW_STARTED))) 1399 uCount--; 1400 1401 if (!(FlashState & FLASHW_KILLSYSTIMER)) 1402 pfwi->dwFlags |= FLASHW_TIMER; 1403 } 1404 1405 if (pfwi->dwFlags & FLASHW_TIMER) 1406 { 1407 FlashState |= FLASHW_KILLSYSTIMER; 1408 1409 IntSetTimer( pWnd, 1410 ID_EVENT_SYSTIMER_FLASHWIN, 1411 pfwi->dwTimeout ? pfwi->dwTimeout : gpsi->dtCaretBlink, 1412 SystemTimerProc, 1413 TMRF_SYSTEM ); 1414 } 1415 1416 if (FlashState & FLASHW_COUNT && uCount == 0) 1417 { 1418 // Keep spinning? Nothing else to do. 1419 FlashState = FLASHW_FINISHED; 1420 } 1421 else 1422 { 1423 // Save state and flags so this can be restored next time through. 1424 FlashState ^= (FlashState ^ -!!(Activate)) & FLASHW_ACTIVE; 1425 FlashState ^= (FlashState ^ pfwi->dwFlags) & (FLASHW_MASK & ~FLASHW_TIMER); 1426 } 1427 FlashState = MAKELONG(LOWORD(FlashState),uCount); 1428 UserSetProp(pWnd, AtomFlashWndState, (HANDLE)FlashState, TRUE); 1429 } 1430 return Ret; 1431 } 1432 1433 // Win: xxxBeginPaint 1434 HDC FASTCALL 1435 IntBeginPaint(PWND Window, PPAINTSTRUCT Ps) 1436 { 1437 RECT Rect; 1438 INT type; 1439 BOOL Erase = FALSE; 1440 1441 co_UserHideCaret(Window); 1442 1443 Window->state2 |= WNDS2_STARTPAINT; 1444 Window->state &= ~WNDS_PAINTNOTPROCESSED; 1445 1446 if (Window->state & WNDS_SENDNCPAINT) 1447 { 1448 HRGN hRgn; 1449 // Application can keep update dirty. 1450 do 1451 { 1452 Window->state &= ~WNDS_UPDATEDIRTY; 1453 hRgn = IntGetNCUpdateRgn(Window, FALSE); 1454 IntSendNCPaint(Window, hRgn); 1455 if (hRgn > HRGN_WINDOW && GreIsHandleValid(hRgn)) 1456 { 1457 /* NOTE: The region can already be deleted! */ 1458 GreDeleteObject(hRgn); 1459 } 1460 } 1461 while(Window->state & WNDS_UPDATEDIRTY); 1462 } 1463 else 1464 { 1465 Window->state &= ~WNDS_UPDATEDIRTY; 1466 } 1467 1468 RtlZeroMemory(Ps, sizeof(PAINTSTRUCT)); 1469 1470 if (Window->state2 & WNDS2_ENDPAINTINVALIDATE) 1471 { 1472 ERR("BP: Another thread invalidated this window\n"); 1473 } 1474 1475 Ps->hdc = UserGetDCEx( Window, 1476 Window->hrgnUpdate, 1477 DCX_INTERSECTRGN | DCX_USESTYLE); 1478 if (!Ps->hdc) 1479 { 1480 return NULL; 1481 } 1482 1483 // If set, always clear flags out due to the conditions later on for sending the message. 1484 if (Window->state & WNDS_SENDERASEBACKGROUND) 1485 { 1486 Window->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND); 1487 Erase = TRUE; 1488 } 1489 1490 if (Window->hrgnUpdate != NULL) 1491 { 1492 MsqDecPaintCountQueue(Window->head.pti); 1493 IntGdiSetRegionOwner(Window->hrgnUpdate, GDI_OBJ_HMGR_POWNED); 1494 /* The region is part of the dc now and belongs to the process! */ 1495 Window->hrgnUpdate = NULL; 1496 } 1497 else 1498 { 1499 if (Window->state & WNDS_INTERNALPAINT) 1500 MsqDecPaintCountQueue(Window->head.pti); 1501 } 1502 1503 type = GdiGetClipBox(Ps->hdc, &Ps->rcPaint); 1504 1505 IntGetClientRect(Window, &Rect); 1506 1507 Window->state &= ~WNDS_INTERNALPAINT; 1508 1509 if ( Erase && // Set to erase, 1510 type != NULLREGION && // don't erase if the clip box is empty, 1511 (!(Window->pcls->style & CS_PARENTDC) || // not parent dc or 1512 RECTL_bIntersectRect( &Rect, &Rect, &Ps->rcPaint) ) ) // intersecting. 1513 { 1514 Ps->fErase = !co_IntSendMessage(UserHMGetHandle(Window), WM_ERASEBKGND, (WPARAM)Ps->hdc, 0); 1515 if ( Ps->fErase ) 1516 { 1517 Window->state |= (WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND); 1518 } 1519 } 1520 else 1521 { 1522 Ps->fErase = FALSE; 1523 } 1524 1525 IntSendChildNCPaint(Window); 1526 1527 return Ps->hdc; 1528 } 1529 1530 // Win: xxxEndPaint 1531 BOOL FASTCALL 1532 IntEndPaint(PWND Wnd, PPAINTSTRUCT Ps) 1533 { 1534 HDC hdc = NULL; 1535 1536 hdc = Ps->hdc; 1537 1538 UserReleaseDC(Wnd, hdc, TRUE); 1539 1540 if (Wnd->state2 & WNDS2_ENDPAINTINVALIDATE) 1541 { 1542 ERR("EP: Another thread invalidated this window\n"); 1543 Wnd->state2 &= ~WNDS2_ENDPAINTINVALIDATE; 1544 } 1545 1546 Wnd->state2 &= ~(WNDS2_WMPAINTSENT|WNDS2_STARTPAINT); 1547 1548 co_UserShowCaret(Wnd); 1549 1550 return TRUE; 1551 } 1552 1553 // Win: xxxFillWindow 1554 BOOL FASTCALL 1555 IntFillWindow(PWND pWndParent, 1556 PWND pWnd, 1557 HDC hDC, 1558 HBRUSH hBrush) 1559 { 1560 RECT Rect, Rect1; 1561 INT type; 1562 1563 if (!pWndParent) 1564 pWndParent = pWnd; 1565 1566 type = GdiGetClipBox(hDC, &Rect); 1567 1568 IntGetClientRect(pWnd, &Rect1); 1569 1570 if ( type != NULLREGION && // Clip box is not empty, 1571 (!(pWnd->pcls->style & CS_PARENTDC) || // not parent dc or 1572 RECTL_bIntersectRect( &Rect, &Rect, &Rect1) ) ) // intersecting. 1573 { 1574 POINT ppt; 1575 INT x = 0, y = 0; 1576 1577 if (!UserIsDesktopWindow(pWndParent)) 1578 { 1579 x = pWndParent->rcClient.left - pWnd->rcClient.left; 1580 y = pWndParent->rcClient.top - pWnd->rcClient.top; 1581 } 1582 1583 GreSetBrushOrg(hDC, x, y, &ppt); 1584 1585 if ( hBrush < (HBRUSH)CTLCOLOR_MAX ) 1586 hBrush = GetControlColor( pWndParent, pWnd, hDC, HandleToUlong(hBrush) + WM_CTLCOLORMSGBOX); 1587 1588 FillRect(hDC, &Rect, hBrush); 1589 1590 GreSetBrushOrg(hDC, ppt.x, ppt.y, NULL); 1591 1592 return TRUE; 1593 } 1594 else 1595 return FALSE; 1596 } 1597 1598 /* PUBLIC FUNCTIONS ***********************************************************/ 1599 1600 /* 1601 * NtUserBeginPaint 1602 * 1603 * Status 1604 * @implemented 1605 */ 1606 1607 HDC APIENTRY 1608 NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs) 1609 { 1610 PWND Window; 1611 PAINTSTRUCT Ps; 1612 NTSTATUS Status; 1613 HDC hDC; 1614 USER_REFERENCE_ENTRY Ref; 1615 HDC Ret = NULL; 1616 1617 TRACE("Enter NtUserBeginPaint\n"); 1618 UserEnterExclusive(); 1619 1620 if (!(Window = UserGetWindowObject(hWnd))) 1621 { 1622 goto Cleanup; // Return NULL 1623 } 1624 1625 UserRefObjectCo(Window, &Ref); 1626 1627 hDC = IntBeginPaint(Window, &Ps); 1628 1629 Status = MmCopyToCaller(UnsafePs, &Ps, sizeof(PAINTSTRUCT)); 1630 if (! NT_SUCCESS(Status)) 1631 { 1632 SetLastNtError(Status); 1633 goto Cleanup; // Return NULL 1634 } 1635 1636 Ret = hDC; 1637 1638 Cleanup: 1639 if (Window) UserDerefObjectCo(Window); 1640 1641 TRACE("Leave NtUserBeginPaint, ret=%p\n", Ret); 1642 UserLeave(); 1643 return Ret; 1644 } 1645 1646 /* 1647 * NtUserEndPaint 1648 * 1649 * Status 1650 * @implemented 1651 */ 1652 1653 BOOL APIENTRY 1654 NtUserEndPaint(HWND hWnd, CONST PAINTSTRUCT* pUnsafePs) 1655 { 1656 NTSTATUS Status = STATUS_SUCCESS; 1657 PWND Window; 1658 PAINTSTRUCT Ps; 1659 USER_REFERENCE_ENTRY Ref; 1660 BOOL Ret = FALSE; 1661 1662 TRACE("Enter NtUserEndPaint\n"); 1663 UserEnterExclusive(); 1664 1665 if (!(Window = UserGetWindowObject(hWnd))) 1666 { 1667 goto Cleanup; // Return FALSE 1668 } 1669 1670 UserRefObjectCo(Window, &Ref); // Here for the exception. 1671 1672 _SEH2_TRY 1673 { 1674 ProbeForRead(pUnsafePs, sizeof(*pUnsafePs), 1); 1675 RtlCopyMemory(&Ps, pUnsafePs, sizeof(PAINTSTRUCT)); 1676 } 1677 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1678 { 1679 Status = _SEH2_GetExceptionCode(); 1680 } 1681 _SEH2_END 1682 if (!NT_SUCCESS(Status)) 1683 { 1684 goto Cleanup; // Return FALSE 1685 } 1686 1687 Ret = IntEndPaint(Window, &Ps); 1688 1689 Cleanup: 1690 if (Window) UserDerefObjectCo(Window); 1691 1692 TRACE("Leave NtUserEndPaint, ret=%i\n", Ret); 1693 UserLeave(); 1694 return Ret; 1695 } 1696 1697 /* 1698 * FillWindow: Called from User; Dialog, Edit and ListBox procs during a WM_ERASEBKGND. 1699 */ 1700 /* 1701 * @implemented 1702 */ 1703 BOOL APIENTRY 1704 NtUserFillWindow(HWND hWndParent, 1705 HWND hWnd, 1706 HDC hDC, 1707 HBRUSH hBrush) 1708 { 1709 BOOL ret = FALSE; 1710 PWND pWnd, pWndParent = NULL; 1711 USER_REFERENCE_ENTRY Ref; 1712 1713 TRACE("Enter NtUserFillWindow\n"); 1714 UserEnterExclusive(); 1715 1716 if (!hDC) 1717 { 1718 goto Exit; 1719 } 1720 1721 if (!(pWnd = UserGetWindowObject(hWnd))) 1722 { 1723 goto Exit; 1724 } 1725 1726 if (hWndParent && !(pWndParent = UserGetWindowObject(hWndParent))) 1727 { 1728 goto Exit; 1729 } 1730 1731 UserRefObjectCo(pWnd, &Ref); 1732 ret = IntFillWindow( pWndParent, pWnd, hDC, hBrush ); 1733 UserDerefObjectCo(pWnd); 1734 1735 Exit: 1736 TRACE("Leave NtUserFillWindow, ret=%i\n",ret); 1737 UserLeave(); 1738 return ret; 1739 } 1740 1741 /* 1742 * @implemented 1743 */ 1744 BOOL APIENTRY 1745 NtUserFlashWindowEx(IN PFLASHWINFO pfwi) 1746 { 1747 PWND pWnd; 1748 FLASHWINFO finfo = {0}; 1749 BOOL Ret = FALSE; 1750 1751 UserEnterExclusive(); 1752 1753 _SEH2_TRY 1754 { 1755 ProbeForRead(pfwi, sizeof(FLASHWINFO), 1); 1756 RtlCopyMemory(&finfo, pfwi, sizeof(FLASHWINFO)); 1757 } 1758 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1759 { 1760 SetLastNtError(_SEH2_GetExceptionCode()); 1761 _SEH2_YIELD(goto Exit); 1762 } 1763 _SEH2_END 1764 1765 if (!( pWnd = ValidateHwndNoErr(finfo.hwnd)) || 1766 finfo.cbSize != sizeof(FLASHWINFO) || 1767 finfo.dwFlags & ~(FLASHW_ALL|FLASHW_TIMER|FLASHW_TIMERNOFG) ) 1768 { 1769 EngSetLastError(ERROR_INVALID_PARAMETER); 1770 goto Exit; 1771 } 1772 1773 Ret = IntFlashWindowEx(pWnd, &finfo); 1774 1775 Exit: 1776 UserLeave(); 1777 return Ret; 1778 } 1779 1780 /* 1781 GetUpdateRgn, this fails the same as the old one. 1782 */ 1783 INT FASTCALL 1784 co_UserGetUpdateRgn(PWND Window, HRGN hRgn, BOOL bErase) 1785 { 1786 int RegionType; 1787 BOOL Type; 1788 RECTL Rect; 1789 1790 ASSERT_REFS_CO(Window); 1791 1792 if (bErase) 1793 { 1794 USER_REFERENCE_ENTRY Ref; 1795 UserRefObjectCo(Window, &Ref); 1796 co_IntPaintWindows(Window, RDW_NOCHILDREN, FALSE); 1797 UserDerefObjectCo(Window); 1798 } 1799 1800 Window->state &= ~WNDS_UPDATEDIRTY; 1801 1802 if (Window->hrgnUpdate == NULL) 1803 { 1804 NtGdiSetRectRgn(hRgn, 0, 0, 0, 0); 1805 return NULLREGION; 1806 } 1807 1808 Rect = Window->rcClient; 1809 Type = IntIntersectWithParents(Window, &Rect); 1810 1811 if (Window->hrgnUpdate == HRGN_WINDOW) 1812 { 1813 // Trap it out. 1814 ERR("GURn: Caller is passing Window Region 1\n"); 1815 if (!Type) 1816 { 1817 NtGdiSetRectRgn(hRgn, 0, 0, 0, 0); 1818 return NULLREGION; 1819 } 1820 1821 RegionType = SIMPLEREGION; 1822 1823 if (!UserIsDesktopWindow(Window)) 1824 { 1825 RECTL_vOffsetRect(&Rect, 1826 -Window->rcClient.left, 1827 -Window->rcClient.top); 1828 } 1829 GreSetRectRgnIndirect(hRgn, &Rect); 1830 } 1831 else 1832 { 1833 HRGN hrgnTemp = GreCreateRectRgnIndirect(&Rect); 1834 1835 RegionType = NtGdiCombineRgn(hRgn, hrgnTemp, Window->hrgnUpdate, RGN_AND); 1836 1837 if (RegionType == ERROR || RegionType == NULLREGION) 1838 { 1839 if (hrgnTemp) GreDeleteObject(hrgnTemp); 1840 NtGdiSetRectRgn(hRgn, 0, 0, 0, 0); 1841 return RegionType; 1842 } 1843 1844 if (!UserIsDesktopWindow(Window)) 1845 { 1846 NtGdiOffsetRgn(hRgn, 1847 -Window->rcClient.left, 1848 -Window->rcClient.top); 1849 } 1850 if (hrgnTemp) GreDeleteObject(hrgnTemp); 1851 } 1852 return RegionType; 1853 } 1854 1855 BOOL FASTCALL 1856 co_UserGetUpdateRect(PWND Window, PRECT pRect, BOOL bErase) 1857 { 1858 INT RegionType; 1859 BOOL Ret = TRUE; 1860 1861 if (bErase) 1862 { 1863 USER_REFERENCE_ENTRY Ref; 1864 UserRefObjectCo(Window, &Ref); 1865 co_IntPaintWindows(Window, RDW_NOCHILDREN, FALSE); 1866 UserDerefObjectCo(Window); 1867 } 1868 1869 Window->state &= ~WNDS_UPDATEDIRTY; 1870 1871 if (Window->hrgnUpdate == NULL) 1872 { 1873 pRect->left = pRect->top = pRect->right = pRect->bottom = 0; 1874 Ret = FALSE; 1875 } 1876 else 1877 { 1878 /* Get the update region bounding box. */ 1879 if (Window->hrgnUpdate == HRGN_WINDOW) 1880 { 1881 *pRect = Window->rcClient; 1882 ERR("GURt: Caller is retrieving Window Region 1\n"); 1883 } 1884 else 1885 { 1886 RegionType = IntGdiGetRgnBox(Window->hrgnUpdate, pRect); 1887 1888 if (RegionType != ERROR && RegionType != NULLREGION) 1889 RECTL_bIntersectRect(pRect, pRect, &Window->rcClient); 1890 } 1891 1892 if (IntIntersectWithParents(Window, pRect)) 1893 { 1894 if (!UserIsDesktopWindow(Window)) 1895 { 1896 RECTL_vOffsetRect(pRect, 1897 -Window->rcClient.left, 1898 -Window->rcClient.top); 1899 } 1900 if (Window->pcls->style & CS_OWNDC) 1901 { 1902 HDC hdc; 1903 //DWORD layout; 1904 hdc = UserGetDCEx(Window, NULL, DCX_USESTYLE); 1905 //layout = NtGdiSetLayout(hdc, -1, 0); 1906 //IntMapWindowPoints( 0, Window, (LPPOINT)pRect, 2 ); 1907 GreDPtoLP( hdc, (LPPOINT)pRect, 2 ); 1908 //NtGdiSetLayout(hdc, -1, layout); 1909 UserReleaseDC(Window, hdc, FALSE); 1910 } 1911 } 1912 else 1913 { 1914 pRect->left = pRect->top = pRect->right = pRect->bottom = 0; 1915 } 1916 } 1917 return Ret; 1918 } 1919 1920 /* 1921 * NtUserGetUpdateRgn 1922 * 1923 * Status 1924 * @implemented 1925 */ 1926 1927 INT APIENTRY 1928 NtUserGetUpdateRgn(HWND hWnd, HRGN hRgn, BOOL bErase) 1929 { 1930 PWND Window; 1931 INT ret = ERROR; 1932 1933 TRACE("Enter NtUserGetUpdateRgn\n"); 1934 UserEnterExclusive(); 1935 1936 Window = UserGetWindowObject(hWnd); 1937 if (Window) 1938 { 1939 ret = co_UserGetUpdateRgn(Window, hRgn, bErase); 1940 } 1941 1942 TRACE("Leave NtUserGetUpdateRgn, ret=%i\n", ret); 1943 UserLeave(); 1944 return ret; 1945 } 1946 1947 /* 1948 * NtUserGetUpdateRect 1949 * 1950 * Status 1951 * @implemented 1952 */ 1953 1954 BOOL APIENTRY 1955 NtUserGetUpdateRect(HWND hWnd, LPRECT UnsafeRect, BOOL bErase) 1956 { 1957 PWND Window; 1958 RECTL Rect; 1959 NTSTATUS Status; 1960 BOOL Ret = FALSE; 1961 1962 TRACE("Enter NtUserGetUpdateRect\n"); 1963 UserEnterExclusive(); 1964 1965 if (!(Window = UserGetWindowObject(hWnd))) 1966 { 1967 goto Exit; // Return FALSE 1968 } 1969 1970 Ret = co_UserGetUpdateRect(Window, &Rect, bErase); 1971 1972 if (UnsafeRect != NULL) 1973 { 1974 Status = MmCopyToCaller(UnsafeRect, &Rect, sizeof(RECTL)); 1975 if (!NT_SUCCESS(Status)) 1976 { 1977 EngSetLastError(ERROR_INVALID_PARAMETER); 1978 Ret = FALSE; 1979 } 1980 } 1981 1982 Exit: 1983 TRACE("Leave NtUserGetUpdateRect, ret=%i\n", Ret); 1984 UserLeave(); 1985 return Ret; 1986 } 1987 1988 /* 1989 * NtUserRedrawWindow 1990 * 1991 * Status 1992 * @implemented 1993 */ 1994 1995 BOOL APIENTRY 1996 NtUserRedrawWindow( 1997 HWND hWnd, 1998 CONST RECT *lprcUpdate, 1999 HRGN hrgnUpdate, 2000 UINT flags) 2001 { 2002 RECTL SafeUpdateRect; 2003 PWND Wnd; 2004 BOOL Ret = FALSE; 2005 USER_REFERENCE_ENTRY Ref; 2006 NTSTATUS Status = STATUS_SUCCESS; 2007 PREGION RgnUpdate = NULL; 2008 2009 TRACE("Enter NtUserRedrawWindow\n"); 2010 UserEnterExclusive(); 2011 2012 if (!(Wnd = UserGetWindowObject(hWnd ? hWnd : IntGetDesktopWindow()))) 2013 { 2014 goto Exit; // Return FALSE 2015 } 2016 2017 if (lprcUpdate) 2018 { 2019 _SEH2_TRY 2020 { 2021 ProbeForRead(lprcUpdate, sizeof(RECTL), 1); 2022 RtlCopyMemory(&SafeUpdateRect, lprcUpdate, sizeof(RECTL)); 2023 } 2024 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2025 { 2026 Status = _SEH2_GetExceptionCode(); 2027 } 2028 _SEH2_END 2029 if (!NT_SUCCESS(Status)) 2030 { 2031 EngSetLastError(RtlNtStatusToDosError(Status)); 2032 goto Exit; // Return FALSE 2033 } 2034 } 2035 2036 if ( flags & ~(RDW_ERASE|RDW_FRAME|RDW_INTERNALPAINT|RDW_INVALIDATE| 2037 RDW_NOERASE|RDW_NOFRAME|RDW_NOINTERNALPAINT|RDW_VALIDATE| 2038 RDW_ERASENOW|RDW_UPDATENOW|RDW_ALLCHILDREN|RDW_NOCHILDREN) ) 2039 { 2040 /* RedrawWindow fails only in case that flags are invalid */ 2041 EngSetLastError(ERROR_INVALID_FLAGS); 2042 goto Exit; // Return FALSE 2043 } 2044 2045 /* We can't hold lock on GDI objects while doing roundtrips to user mode, 2046 * so it will be copied. 2047 */ 2048 if (hrgnUpdate > HRGN_WINDOW) 2049 { 2050 RgnUpdate = REGION_LockRgn(hrgnUpdate); 2051 if (!RgnUpdate) 2052 { 2053 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 2054 goto Exit; // Return FALSE 2055 } 2056 REGION_UnlockRgn(RgnUpdate); 2057 } 2058 else if (hrgnUpdate == HRGN_WINDOW) // Trap it out. 2059 { 2060 ERR("NTRW: Caller is passing Window Region 1\n"); 2061 } 2062 2063 UserRefObjectCo(Wnd, &Ref); 2064 2065 Ret = co_UserRedrawWindow( Wnd, 2066 lprcUpdate ? &SafeUpdateRect : NULL, 2067 RgnUpdate, 2068 flags); 2069 2070 UserDerefObjectCo(Wnd); 2071 2072 Exit: 2073 TRACE("Leave NtUserRedrawWindow, ret=%i\n", Ret); 2074 UserLeave(); 2075 return Ret; 2076 } 2077 2078 BOOL 2079 UserDrawCaptionText( 2080 PWND pWnd, 2081 HDC hDc, 2082 const PUNICODE_STRING Text, 2083 const RECTL *lpRc, 2084 UINT uFlags, 2085 HFONT hFont) 2086 { 2087 HFONT hOldFont = NULL; 2088 COLORREF OldTextColor; 2089 NONCLIENTMETRICSW nclm; 2090 NTSTATUS Status; 2091 BOOLEAN bDeleteFont = FALSE; 2092 SIZE Size; 2093 BOOL Ret = TRUE; 2094 ULONG fit = 0, Length; 2095 RECTL r = *lpRc; 2096 2097 TRACE("UserDrawCaptionText: %wZ\n", Text); 2098 2099 nclm.cbSize = sizeof(nclm); 2100 if (!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS, nclm.cbSize, &nclm, 0)) 2101 { 2102 ERR("UserSystemParametersInfo() failed!\n"); 2103 return FALSE; 2104 } 2105 2106 if (!hFont) 2107 { 2108 if(uFlags & DC_SMALLCAP) 2109 Status = TextIntCreateFontIndirect(&nclm.lfSmCaptionFont, &hFont); 2110 else 2111 Status = TextIntCreateFontIndirect(&nclm.lfCaptionFont, &hFont); 2112 2113 if(!NT_SUCCESS(Status)) 2114 { 2115 ERR("TextIntCreateFontIndirect() failed! Status: 0x%x\n", Status); 2116 return FALSE; 2117 } 2118 2119 bDeleteFont = TRUE; 2120 } 2121 2122 IntGdiSetBkMode(hDc, TRANSPARENT); 2123 2124 hOldFont = NtGdiSelectFont(hDc, hFont); 2125 2126 if(uFlags & DC_INBUTTON) 2127 OldTextColor = IntGdiSetTextColor(hDc, IntGetSysColor(COLOR_BTNTEXT)); 2128 else 2129 OldTextColor = IntGdiSetTextColor(hDc, 2130 IntGetSysColor(uFlags & DC_ACTIVE ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT)); 2131 2132 // Adjust for system menu. 2133 if (pWnd && pWnd->style & WS_SYSMENU) 2134 { 2135 r.right -= UserGetSystemMetrics(SM_CYCAPTION) - 1; 2136 if ((pWnd->style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX)) && !(pWnd->ExStyle & WS_EX_TOOLWINDOW)) 2137 { 2138 r.right -= UserGetSystemMetrics(SM_CXSIZE) + 1; 2139 r.right -= UserGetSystemMetrics(SM_CXSIZE) + 1; 2140 } 2141 } 2142 2143 GreGetTextExtentExW(hDc, Text->Buffer, Text->Length/sizeof(WCHAR), r.right - r.left, &fit, 0, &Size, 0); 2144 2145 Length = (Text->Length/sizeof(WCHAR) == fit ? fit : fit+1); 2146 2147 if (Text->Length/sizeof(WCHAR) > Length) 2148 { 2149 Ret = FALSE; 2150 } 2151 2152 if (Ret) 2153 { // Faster while in setup. 2154 UserExtTextOutW( hDc, 2155 lpRc->left, 2156 lpRc->top + (lpRc->bottom - lpRc->top - Size.cy) / 2, // DT_SINGLELINE && DT_VCENTER 2157 ETO_CLIPPED, 2158 (RECTL *)lpRc, 2159 Text->Buffer, 2160 Length); 2161 } 2162 else 2163 { 2164 DrawTextW( hDc, 2165 Text->Buffer, 2166 Text->Length/sizeof(WCHAR), 2167 (RECTL *)&r, 2168 DT_END_ELLIPSIS|DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX|DT_LEFT); 2169 } 2170 2171 IntGdiSetTextColor(hDc, OldTextColor); 2172 2173 if (hOldFont) 2174 NtGdiSelectFont(hDc, hOldFont); 2175 2176 if (bDeleteFont) 2177 GreDeleteObject(hFont); 2178 2179 return Ret; 2180 } 2181 2182 // 2183 // This draws Buttons, Icons and Text... 2184 // 2185 BOOL UserDrawCaption( 2186 PWND pWnd, 2187 HDC hDc, 2188 RECTL *lpRc, 2189 HFONT hFont, 2190 HICON hIcon, 2191 const PUNICODE_STRING Str, 2192 UINT uFlags) 2193 { 2194 BOOL Ret = FALSE; 2195 HBRUSH hBgBrush, hOldBrush = NULL; 2196 RECTL Rect = *lpRc; 2197 BOOL HasIcon; 2198 2199 RECTL_vMakeWellOrdered(lpRc); 2200 2201 /* Determine whether the icon needs to be displayed */ 2202 if (!hIcon && pWnd != NULL) 2203 { 2204 HasIcon = (uFlags & DC_ICON) && !(uFlags & DC_SMALLCAP) && 2205 (pWnd->style & WS_SYSMENU) && !(pWnd->ExStyle & WS_EX_TOOLWINDOW); 2206 } 2207 else 2208 HasIcon = (hIcon != NULL); 2209 2210 // Draw the caption background 2211 if((uFlags & DC_GRADIENT) && !(uFlags & DC_INBUTTON)) 2212 { 2213 static GRADIENT_RECT gcap = {0, 1}; 2214 TRIVERTEX Vertices[2]; 2215 COLORREF Colors[2]; 2216 2217 Colors[0] = IntGetSysColor((uFlags & DC_ACTIVE) ? 2218 COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION); 2219 2220 Colors[1] = IntGetSysColor((uFlags & DC_ACTIVE) ? 2221 COLOR_GRADIENTACTIVECAPTION : COLOR_GRADIENTINACTIVECAPTION); 2222 2223 Vertices[0].x = Rect.left; 2224 Vertices[0].y = Rect.top; 2225 Vertices[0].Red = (WORD)Colors[0]<<8; 2226 Vertices[0].Green = (WORD)Colors[0] & 0xFF00; 2227 Vertices[0].Blue = (WORD)(Colors[0]>>8) & 0xFF00; 2228 Vertices[0].Alpha = 0; 2229 2230 Vertices[1].x = Rect.right; 2231 Vertices[1].y = Rect.bottom; 2232 Vertices[1].Red = (WORD)Colors[1]<<8; 2233 Vertices[1].Green = (WORD)Colors[1] & 0xFF00; 2234 Vertices[1].Blue = (WORD)(Colors[1]>>8) & 0xFF00; 2235 Vertices[1].Alpha = 0; 2236 2237 if(!GreGradientFill(hDc, Vertices, 2, &gcap, 1, GRADIENT_FILL_RECT_H)) 2238 { 2239 ERR("GreGradientFill() failed!\n"); 2240 goto cleanup; 2241 } 2242 } 2243 else 2244 { 2245 if(uFlags & DC_INBUTTON) 2246 hBgBrush = IntGetSysColorBrush(COLOR_3DFACE); 2247 else if(uFlags & DC_ACTIVE) 2248 hBgBrush = IntGetSysColorBrush(COLOR_ACTIVECAPTION); 2249 else 2250 hBgBrush = IntGetSysColorBrush(COLOR_INACTIVECAPTION); 2251 2252 hOldBrush = NtGdiSelectBrush(hDc, hBgBrush); 2253 2254 if(!hOldBrush) 2255 { 2256 ERR("NtGdiSelectBrush() failed!\n"); 2257 goto cleanup; 2258 } 2259 2260 if(!NtGdiPatBlt(hDc, Rect.left, Rect.top, 2261 Rect.right - Rect.left, 2262 Rect.bottom - Rect.top, 2263 PATCOPY)) 2264 { 2265 ERR("NtGdiPatBlt() failed!\n"); 2266 goto cleanup; 2267 } 2268 } 2269 2270 /* Draw icon */ 2271 if (HasIcon) 2272 { 2273 PCURICON_OBJECT pIcon = NULL; 2274 2275 if (hIcon) 2276 { 2277 pIcon = UserGetCurIconObject(hIcon); 2278 } 2279 else if (pWnd) 2280 { 2281 pIcon = NC_IconForWindow(pWnd); 2282 // FIXME: NC_IconForWindow should reference it for us */ 2283 if (pIcon) 2284 UserReferenceObject(pIcon); 2285 } 2286 2287 if (pIcon) 2288 { 2289 LONG cx = UserGetSystemMetrics(SM_CXSMICON); 2290 LONG cy = UserGetSystemMetrics(SM_CYSMICON); 2291 LONG x = Rect.left - cx/2 + 1 + (Rect.bottom - Rect.top)/2; // this is really what Window does 2292 LONG y = (Rect.top + Rect.bottom - cy)/2; // center 2293 UserDrawIconEx(hDc, x, y, pIcon, cx, cy, 0, NULL, DI_NORMAL); 2294 UserDereferenceObject(pIcon); 2295 } 2296 else 2297 { 2298 HasIcon = FALSE; 2299 } 2300 } 2301 2302 if (HasIcon) 2303 Rect.left += Rect.bottom - Rect.top; 2304 2305 if((uFlags & DC_TEXT)) 2306 { 2307 BOOL Set = FALSE; 2308 Rect.left += 2; 2309 2310 if (Str) 2311 Set = UserDrawCaptionText(pWnd, hDc, Str, &Rect, uFlags, hFont); 2312 else if (pWnd != NULL) // FIXME: Windows does not do that 2313 { 2314 UNICODE_STRING ustr; 2315 ustr.Buffer = pWnd->strName.Buffer; // FIXME: LARGE_STRING truncated! 2316 ustr.Length = (USHORT)min(pWnd->strName.Length, MAXUSHORT); 2317 ustr.MaximumLength = (USHORT)min(pWnd->strName.MaximumLength, MAXUSHORT); 2318 Set = UserDrawCaptionText(pWnd, hDc, &ustr, &Rect, uFlags, hFont); 2319 } 2320 if (pWnd) 2321 { 2322 if (Set) 2323 pWnd->state2 &= ~WNDS2_CAPTIONTEXTTRUNCATED; 2324 else 2325 pWnd->state2 |= WNDS2_CAPTIONTEXTTRUNCATED; 2326 } 2327 } 2328 2329 Ret = TRUE; 2330 2331 cleanup: 2332 if (hOldBrush) NtGdiSelectBrush(hDc, hOldBrush); 2333 2334 return Ret; 2335 } 2336 2337 INT 2338 FASTCALL 2339 UserRealizePalette(HDC hdc) 2340 { 2341 HWND hWnd, hWndDesktop; 2342 DWORD Ret; 2343 2344 Ret = IntGdiRealizePalette(hdc); 2345 if (Ret) // There was a change. 2346 { 2347 hWnd = IntWindowFromDC(hdc); 2348 if (hWnd) // Send broadcast if dc is associated with a window. 2349 { // FYI: Thread locked in CallOneParam. 2350 hWndDesktop = IntGetDesktopWindow(); 2351 if ( hWndDesktop != hWnd ) 2352 { 2353 PWND pWnd = UserGetWindowObject(hWndDesktop); 2354 ERR("RealizePalette Desktop.\n"); 2355 hdc = UserGetWindowDC(pWnd); 2356 IntPaintDesktop(hdc); 2357 UserReleaseDC(pWnd,hdc,FALSE); 2358 } 2359 UserSendNotifyMessage((HWND)HWND_BROADCAST, WM_PALETTECHANGED, (WPARAM)hWnd, 0); 2360 } 2361 } 2362 return Ret; 2363 } 2364 2365 BOOL 2366 APIENTRY 2367 NtUserDrawCaptionTemp( 2368 HWND hWnd, 2369 HDC hDC, 2370 LPCRECT lpRc, 2371 HFONT hFont, 2372 HICON hIcon, 2373 const PUNICODE_STRING str, 2374 UINT uFlags) 2375 { 2376 PWND pWnd = NULL; 2377 UNICODE_STRING SafeStr = {0}; 2378 NTSTATUS Status = STATUS_SUCCESS; 2379 RECTL SafeRect; 2380 BOOL Ret; 2381 2382 UserEnterExclusive(); 2383 2384 if (hWnd != NULL) 2385 { 2386 if(!(pWnd = UserGetWindowObject(hWnd))) 2387 { 2388 UserLeave(); 2389 return FALSE; 2390 } 2391 } 2392 2393 _SEH2_TRY 2394 { 2395 ProbeForRead(lpRc, sizeof(RECTL), sizeof(ULONG)); 2396 RtlCopyMemory(&SafeRect, lpRc, sizeof(RECTL)); 2397 if (str != NULL) 2398 { 2399 SafeStr = ProbeForReadUnicodeString(str); 2400 if (SafeStr.Length != 0) 2401 { 2402 ProbeForRead( SafeStr.Buffer, 2403 SafeStr.Length, 2404 sizeof(WCHAR)); 2405 } 2406 } 2407 } 2408 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2409 { 2410 Status = _SEH2_GetExceptionCode(); 2411 } 2412 _SEH2_END; 2413 2414 if (Status != STATUS_SUCCESS) 2415 { 2416 SetLastNtError(Status); 2417 UserLeave(); 2418 return FALSE; 2419 } 2420 2421 if (str != NULL) 2422 Ret = UserDrawCaption(pWnd, hDC, &SafeRect, hFont, hIcon, &SafeStr, uFlags); 2423 else 2424 { 2425 if ( RECTL_bIsEmptyRect(&SafeRect) && hFont == 0 && hIcon == 0 ) 2426 { 2427 Ret = TRUE; 2428 if (uFlags & DC_DRAWCAPTIONMD) 2429 { 2430 ERR("NC Caption Mode\n"); 2431 UserDrawCaptionBar(pWnd, hDC, uFlags); 2432 goto Exit; 2433 } 2434 else if (uFlags & DC_DRAWFRAMEMD) 2435 { 2436 ERR("NC Paint Mode\n"); 2437 NC_DoNCPaint(pWnd, hDC, uFlags); // Update Menus too! 2438 goto Exit; 2439 } 2440 } 2441 Ret = UserDrawCaption(pWnd, hDC, &SafeRect, hFont, hIcon, NULL, uFlags); 2442 } 2443 Exit: 2444 UserLeave(); 2445 return Ret; 2446 } 2447 2448 BOOL 2449 APIENTRY 2450 NtUserDrawCaption(HWND hWnd, 2451 HDC hDC, 2452 LPCRECT lpRc, 2453 UINT uFlags) 2454 { 2455 return NtUserDrawCaptionTemp(hWnd, hDC, lpRc, 0, 0, NULL, uFlags); 2456 } 2457 2458 INT FASTCALL 2459 co_UserExcludeUpdateRgn(HDC hDC, PWND Window) 2460 { 2461 POINT pt; 2462 RECT rc; 2463 2464 if (Window->hrgnUpdate) 2465 { 2466 if (Window->hrgnUpdate == HRGN_WINDOW) 2467 { 2468 return NtGdiIntersectClipRect(hDC, 0, 0, 0, 0); 2469 } 2470 else 2471 { 2472 INT ret = ERROR; 2473 HRGN hrgn = NtGdiCreateRectRgn(0,0,0,0); 2474 2475 if ( hrgn && GreGetDCPoint( hDC, GdiGetDCOrg, &pt) ) 2476 { 2477 if ( NtGdiGetRandomRgn( hDC, hrgn, CLIPRGN) == NULLREGION ) 2478 { 2479 NtGdiOffsetRgn(hrgn, pt.x, pt.y); 2480 } 2481 else 2482 { 2483 HRGN hrgnScreen; 2484 PMONITOR pm = UserGetPrimaryMonitor(); 2485 hrgnScreen = NtGdiCreateRectRgn(0,0,0,0); 2486 NtGdiCombineRgn(hrgnScreen, hrgnScreen, pm->hrgnMonitor, RGN_OR); 2487 2488 NtGdiCombineRgn(hrgn, hrgnScreen, NULL, RGN_COPY); 2489 2490 GreDeleteObject(hrgnScreen); 2491 } 2492 2493 NtGdiCombineRgn(hrgn, hrgn, Window->hrgnUpdate, RGN_DIFF); 2494 2495 NtGdiOffsetRgn(hrgn, -pt.x, -pt.y); 2496 2497 ret = NtGdiExtSelectClipRgn(hDC, hrgn, RGN_COPY); 2498 2499 GreDeleteObject(hrgn); 2500 } 2501 return ret; 2502 } 2503 } 2504 else 2505 { 2506 return GdiGetClipBox( hDC, &rc); 2507 } 2508 } 2509 2510 INT 2511 APIENTRY 2512 NtUserExcludeUpdateRgn( 2513 HDC hDC, 2514 HWND hWnd) 2515 { 2516 INT ret = ERROR; 2517 PWND pWnd; 2518 2519 TRACE("Enter NtUserExcludeUpdateRgn\n"); 2520 UserEnterExclusive(); 2521 2522 pWnd = UserGetWindowObject(hWnd); 2523 2524 if (hDC && pWnd) 2525 ret = co_UserExcludeUpdateRgn(hDC, pWnd); 2526 2527 TRACE("Leave NtUserExcludeUpdateRgn, ret=%i\n", ret); 2528 2529 UserLeave(); 2530 return ret; 2531 } 2532 2533 BOOL 2534 APIENTRY 2535 NtUserInvalidateRect( 2536 HWND hWnd, 2537 CONST RECT *lpUnsafeRect, 2538 BOOL bErase) 2539 { 2540 UINT flags = RDW_INVALIDATE | (bErase ? RDW_ERASE : 0); 2541 if (!hWnd) 2542 { 2543 flags = RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW; 2544 lpUnsafeRect = NULL; 2545 } 2546 return NtUserRedrawWindow(hWnd, lpUnsafeRect, NULL, flags); 2547 } 2548 2549 BOOL 2550 APIENTRY 2551 NtUserInvalidateRgn( 2552 HWND hWnd, 2553 HRGN hRgn, 2554 BOOL bErase) 2555 { 2556 if (!hWnd) 2557 { 2558 EngSetLastError( ERROR_INVALID_WINDOW_HANDLE ); 2559 return FALSE; 2560 } 2561 return NtUserRedrawWindow(hWnd, NULL, hRgn, RDW_INVALIDATE | (bErase? RDW_ERASE : 0)); 2562 } 2563 2564 BOOL 2565 APIENTRY 2566 NtUserPrintWindow( 2567 HWND hwnd, 2568 HDC hdcBlt, 2569 UINT nFlags) 2570 { 2571 PWND Window; 2572 BOOL Ret = FALSE; 2573 2574 UserEnterExclusive(); 2575 2576 if (hwnd) 2577 { 2578 if (!(Window = UserGetWindowObject(hwnd)) || 2579 UserIsDesktopWindow(Window) || UserIsMessageWindow(Window)) 2580 { 2581 goto Exit; 2582 } 2583 2584 if ( Window ) 2585 { 2586 /* Validate flags and check it as a mask for 0 or 1. */ 2587 if ( (nFlags & PW_CLIENTONLY) == nFlags) 2588 Ret = IntPrintWindow( Window, hdcBlt, nFlags); 2589 else 2590 EngSetLastError(ERROR_INVALID_PARAMETER); 2591 } 2592 } 2593 Exit: 2594 UserLeave(); 2595 return Ret; 2596 } 2597 2598 /* ValidateRect gets redirected to NtUserValidateRect: 2599 http://blog.csdn.net/ntdll/archive/2005/10/19/509299.aspx */ 2600 BOOL 2601 APIENTRY 2602 NtUserValidateRect( 2603 HWND hWnd, 2604 const RECT *lpRect) 2605 { 2606 UINT flags = RDW_VALIDATE; 2607 if (!hWnd) 2608 { 2609 flags = RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW; 2610 lpRect = NULL; 2611 } 2612 return NtUserRedrawWindow(hWnd, lpRect, NULL, flags); 2613 } 2614 2615 /* EOF */ 2616