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 HDC FASTCALL 1434 IntBeginPaint(PWND Window, PPAINTSTRUCT Ps) 1435 { 1436 RECT Rect; 1437 INT type; 1438 BOOL Erase = FALSE; 1439 1440 co_UserHideCaret(Window); 1441 1442 Window->state2 |= WNDS2_STARTPAINT; 1443 Window->state &= ~WNDS_PAINTNOTPROCESSED; 1444 1445 if (Window->state & WNDS_SENDNCPAINT) 1446 { 1447 HRGN hRgn; 1448 // Application can keep update dirty. 1449 do 1450 { 1451 Window->state &= ~WNDS_UPDATEDIRTY; 1452 hRgn = IntGetNCUpdateRgn(Window, FALSE); 1453 IntSendNCPaint(Window, hRgn); 1454 if (hRgn > HRGN_WINDOW && GreIsHandleValid(hRgn)) 1455 { 1456 /* NOTE: The region can already be deleted! */ 1457 GreDeleteObject(hRgn); 1458 } 1459 } 1460 while(Window->state & WNDS_UPDATEDIRTY); 1461 } 1462 else 1463 { 1464 Window->state &= ~WNDS_UPDATEDIRTY; 1465 } 1466 1467 RtlZeroMemory(Ps, sizeof(PAINTSTRUCT)); 1468 1469 if (Window->state2 & WNDS2_ENDPAINTINVALIDATE) 1470 { 1471 ERR("BP: Another thread invalidated this window\n"); 1472 } 1473 1474 Ps->hdc = UserGetDCEx( Window, 1475 Window->hrgnUpdate, 1476 DCX_INTERSECTRGN | DCX_USESTYLE); 1477 if (!Ps->hdc) 1478 { 1479 return NULL; 1480 } 1481 1482 // If set, always clear flags out due to the conditions later on for sending the message. 1483 if (Window->state & WNDS_SENDERASEBACKGROUND) 1484 { 1485 Window->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND); 1486 Erase = TRUE; 1487 } 1488 1489 if (Window->hrgnUpdate != NULL) 1490 { 1491 MsqDecPaintCountQueue(Window->head.pti); 1492 IntGdiSetRegionOwner(Window->hrgnUpdate, GDI_OBJ_HMGR_POWNED); 1493 /* The region is part of the dc now and belongs to the process! */ 1494 Window->hrgnUpdate = NULL; 1495 } 1496 else 1497 { 1498 if (Window->state & WNDS_INTERNALPAINT) 1499 MsqDecPaintCountQueue(Window->head.pti); 1500 } 1501 1502 type = GdiGetClipBox(Ps->hdc, &Ps->rcPaint); 1503 1504 IntGetClientRect(Window, &Rect); 1505 1506 Window->state &= ~WNDS_INTERNALPAINT; 1507 1508 if ( Erase && // Set to erase, 1509 type != NULLREGION && // don't erase if the clip box is empty, 1510 (!(Window->pcls->style & CS_PARENTDC) || // not parent dc or 1511 RECTL_bIntersectRect( &Rect, &Rect, &Ps->rcPaint) ) ) // intersecting. 1512 { 1513 Ps->fErase = !co_IntSendMessage(UserHMGetHandle(Window), WM_ERASEBKGND, (WPARAM)Ps->hdc, 0); 1514 if ( Ps->fErase ) 1515 { 1516 Window->state |= (WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND); 1517 } 1518 } 1519 else 1520 { 1521 Ps->fErase = FALSE; 1522 } 1523 1524 IntSendChildNCPaint(Window); 1525 1526 return Ps->hdc; 1527 } 1528 1529 BOOL FASTCALL 1530 IntEndPaint(PWND Wnd, PPAINTSTRUCT Ps) 1531 { 1532 HDC hdc = NULL; 1533 1534 hdc = Ps->hdc; 1535 1536 UserReleaseDC(Wnd, hdc, TRUE); 1537 1538 if (Wnd->state2 & WNDS2_ENDPAINTINVALIDATE) 1539 { 1540 ERR("EP: Another thread invalidated this window\n"); 1541 Wnd->state2 &= ~WNDS2_ENDPAINTINVALIDATE; 1542 } 1543 1544 Wnd->state2 &= ~(WNDS2_WMPAINTSENT|WNDS2_STARTPAINT); 1545 1546 co_UserShowCaret(Wnd); 1547 1548 return TRUE; 1549 } 1550 1551 BOOL FASTCALL 1552 IntFillWindow(PWND pWndParent, 1553 PWND pWnd, 1554 HDC hDC, 1555 HBRUSH hBrush) 1556 { 1557 RECT Rect, Rect1; 1558 INT type; 1559 1560 if (!pWndParent) 1561 pWndParent = pWnd; 1562 1563 type = GdiGetClipBox(hDC, &Rect); 1564 1565 IntGetClientRect(pWnd, &Rect1); 1566 1567 if ( type != NULLREGION && // Clip box is not empty, 1568 (!(pWnd->pcls->style & CS_PARENTDC) || // not parent dc or 1569 RECTL_bIntersectRect( &Rect, &Rect, &Rect1) ) ) // intersecting. 1570 { 1571 POINT ppt; 1572 INT x = 0, y = 0; 1573 1574 if (!UserIsDesktopWindow(pWndParent)) 1575 { 1576 x = pWndParent->rcClient.left - pWnd->rcClient.left; 1577 y = pWndParent->rcClient.top - pWnd->rcClient.top; 1578 } 1579 1580 GreSetBrushOrg(hDC, x, y, &ppt); 1581 1582 if ( hBrush < (HBRUSH)CTLCOLOR_MAX ) 1583 hBrush = GetControlColor( pWndParent, pWnd, hDC, HandleToUlong(hBrush) + WM_CTLCOLORMSGBOX); 1584 1585 FillRect(hDC, &Rect, hBrush); 1586 1587 GreSetBrushOrg(hDC, ppt.x, ppt.y, NULL); 1588 1589 return TRUE; 1590 } 1591 else 1592 return FALSE; 1593 } 1594 1595 /* PUBLIC FUNCTIONS ***********************************************************/ 1596 1597 /* 1598 * NtUserBeginPaint 1599 * 1600 * Status 1601 * @implemented 1602 */ 1603 1604 HDC APIENTRY 1605 NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs) 1606 { 1607 PWND Window = NULL; 1608 PAINTSTRUCT Ps; 1609 NTSTATUS Status; 1610 HDC hDC; 1611 USER_REFERENCE_ENTRY Ref; 1612 DECLARE_RETURN(HDC); 1613 1614 TRACE("Enter NtUserBeginPaint\n"); 1615 UserEnterExclusive(); 1616 1617 if (!(Window = UserGetWindowObject(hWnd))) 1618 { 1619 RETURN( NULL); 1620 } 1621 1622 UserRefObjectCo(Window, &Ref); 1623 1624 hDC = IntBeginPaint(Window, &Ps); 1625 1626 Status = MmCopyToCaller(UnsafePs, &Ps, sizeof(PAINTSTRUCT)); 1627 if (! NT_SUCCESS(Status)) 1628 { 1629 SetLastNtError(Status); 1630 RETURN(NULL); 1631 } 1632 1633 RETURN(hDC); 1634 1635 CLEANUP: 1636 if (Window) UserDerefObjectCo(Window); 1637 1638 TRACE("Leave NtUserBeginPaint, ret=%p\n",_ret_); 1639 UserLeave(); 1640 END_CLEANUP; 1641 1642 } 1643 1644 /* 1645 * NtUserEndPaint 1646 * 1647 * Status 1648 * @implemented 1649 */ 1650 1651 BOOL APIENTRY 1652 NtUserEndPaint(HWND hWnd, CONST PAINTSTRUCT* pUnsafePs) 1653 { 1654 NTSTATUS Status = STATUS_SUCCESS; 1655 PWND Window = NULL; 1656 PAINTSTRUCT Ps; 1657 USER_REFERENCE_ENTRY Ref; 1658 DECLARE_RETURN(BOOL); 1659 1660 TRACE("Enter NtUserEndPaint\n"); 1661 UserEnterExclusive(); 1662 1663 if (!(Window = UserGetWindowObject(hWnd))) 1664 { 1665 RETURN(FALSE); 1666 } 1667 1668 UserRefObjectCo(Window, &Ref); // Here for the exception. 1669 1670 _SEH2_TRY 1671 { 1672 ProbeForRead(pUnsafePs, sizeof(*pUnsafePs), 1); 1673 RtlCopyMemory(&Ps, pUnsafePs, sizeof(PAINTSTRUCT)); 1674 } 1675 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1676 { 1677 Status = _SEH2_GetExceptionCode(); 1678 } 1679 _SEH2_END 1680 if (!NT_SUCCESS(Status)) 1681 { 1682 RETURN(FALSE); 1683 } 1684 1685 RETURN(IntEndPaint(Window, &Ps)); 1686 1687 CLEANUP: 1688 if (Window) UserDerefObjectCo(Window); 1689 1690 TRACE("Leave NtUserEndPaint, ret=%i\n",_ret_); 1691 UserLeave(); 1692 END_CLEANUP; 1693 } 1694 1695 /* 1696 * FillWindow: Called from User; Dialog, Edit and ListBox procs during a WM_ERASEBKGND. 1697 */ 1698 /* 1699 * @implemented 1700 */ 1701 BOOL APIENTRY 1702 NtUserFillWindow(HWND hWndParent, 1703 HWND hWnd, 1704 HDC hDC, 1705 HBRUSH hBrush) 1706 { 1707 BOOL ret = FALSE; 1708 PWND pWnd, pWndParent = NULL; 1709 USER_REFERENCE_ENTRY Ref; 1710 1711 TRACE("Enter NtUserFillWindow\n"); 1712 UserEnterExclusive(); 1713 1714 if (!hDC) 1715 { 1716 goto Exit; 1717 } 1718 1719 if (!(pWnd = UserGetWindowObject(hWnd))) 1720 { 1721 goto Exit; 1722 } 1723 1724 if (hWndParent && !(pWndParent = UserGetWindowObject(hWndParent))) 1725 { 1726 goto Exit; 1727 } 1728 1729 UserRefObjectCo(pWnd, &Ref); 1730 ret = IntFillWindow( pWndParent, pWnd, hDC, hBrush ); 1731 UserDerefObjectCo(pWnd); 1732 1733 Exit: 1734 TRACE("Leave NtUserFillWindow, ret=%i\n",ret); 1735 UserLeave(); 1736 return ret; 1737 } 1738 1739 /* 1740 * @implemented 1741 */ 1742 BOOL APIENTRY 1743 NtUserFlashWindowEx(IN PFLASHWINFO pfwi) 1744 { 1745 PWND pWnd; 1746 FLASHWINFO finfo = {0}; 1747 BOOL Ret = FALSE; 1748 1749 UserEnterExclusive(); 1750 1751 _SEH2_TRY 1752 { 1753 ProbeForRead(pfwi, sizeof(FLASHWINFO), 1); 1754 RtlCopyMemory(&finfo, pfwi, sizeof(FLASHWINFO)); 1755 } 1756 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1757 { 1758 SetLastNtError(_SEH2_GetExceptionCode()); 1759 _SEH2_YIELD(goto Exit); 1760 } 1761 _SEH2_END 1762 1763 if (!( pWnd = ValidateHwndNoErr(finfo.hwnd)) || 1764 finfo.cbSize != sizeof(FLASHWINFO) || 1765 finfo.dwFlags & ~(FLASHW_ALL|FLASHW_TIMER|FLASHW_TIMERNOFG) ) 1766 { 1767 EngSetLastError(ERROR_INVALID_PARAMETER); 1768 goto Exit; 1769 } 1770 1771 Ret = IntFlashWindowEx(pWnd, &finfo); 1772 1773 Exit: 1774 UserLeave(); 1775 return Ret; 1776 } 1777 1778 /* 1779 GetUpdateRgn, this fails the same as the old one. 1780 */ 1781 INT FASTCALL 1782 co_UserGetUpdateRgn(PWND Window, HRGN hRgn, BOOL bErase) 1783 { 1784 int RegionType; 1785 BOOL Type; 1786 RECTL Rect; 1787 1788 ASSERT_REFS_CO(Window); 1789 1790 if (bErase) 1791 { 1792 USER_REFERENCE_ENTRY Ref; 1793 UserRefObjectCo(Window, &Ref); 1794 co_IntPaintWindows(Window, RDW_NOCHILDREN, FALSE); 1795 UserDerefObjectCo(Window); 1796 } 1797 1798 Window->state &= ~WNDS_UPDATEDIRTY; 1799 1800 if (Window->hrgnUpdate == NULL) 1801 { 1802 NtGdiSetRectRgn(hRgn, 0, 0, 0, 0); 1803 return NULLREGION; 1804 } 1805 1806 Rect = Window->rcClient; 1807 Type = IntIntersectWithParents(Window, &Rect); 1808 1809 if (Window->hrgnUpdate == HRGN_WINDOW) 1810 { 1811 // Trap it out. 1812 ERR("GURn: Caller is passing Window Region 1\n"); 1813 if (!Type) 1814 { 1815 NtGdiSetRectRgn(hRgn, 0, 0, 0, 0); 1816 return NULLREGION; 1817 } 1818 1819 RegionType = SIMPLEREGION; 1820 1821 if (!UserIsDesktopWindow(Window)) 1822 { 1823 RECTL_vOffsetRect(&Rect, 1824 -Window->rcClient.left, 1825 -Window->rcClient.top); 1826 } 1827 GreSetRectRgnIndirect(hRgn, &Rect); 1828 } 1829 else 1830 { 1831 HRGN hrgnTemp = GreCreateRectRgnIndirect(&Rect); 1832 1833 RegionType = NtGdiCombineRgn(hRgn, hrgnTemp, Window->hrgnUpdate, RGN_AND); 1834 1835 if (RegionType == ERROR || RegionType == NULLREGION) 1836 { 1837 if (hrgnTemp) GreDeleteObject(hrgnTemp); 1838 NtGdiSetRectRgn(hRgn, 0, 0, 0, 0); 1839 return RegionType; 1840 } 1841 1842 if (!UserIsDesktopWindow(Window)) 1843 { 1844 NtGdiOffsetRgn(hRgn, 1845 -Window->rcClient.left, 1846 -Window->rcClient.top); 1847 } 1848 if (hrgnTemp) GreDeleteObject(hrgnTemp); 1849 } 1850 return RegionType; 1851 } 1852 1853 BOOL FASTCALL 1854 co_UserGetUpdateRect(PWND Window, PRECT pRect, BOOL bErase) 1855 { 1856 INT RegionType; 1857 BOOL Ret = TRUE; 1858 1859 if (bErase) 1860 { 1861 USER_REFERENCE_ENTRY Ref; 1862 UserRefObjectCo(Window, &Ref); 1863 co_IntPaintWindows(Window, RDW_NOCHILDREN, FALSE); 1864 UserDerefObjectCo(Window); 1865 } 1866 1867 Window->state &= ~WNDS_UPDATEDIRTY; 1868 1869 if (Window->hrgnUpdate == NULL) 1870 { 1871 pRect->left = pRect->top = pRect->right = pRect->bottom = 0; 1872 Ret = FALSE; 1873 } 1874 else 1875 { 1876 /* Get the update region bounding box. */ 1877 if (Window->hrgnUpdate == HRGN_WINDOW) 1878 { 1879 *pRect = Window->rcClient; 1880 ERR("GURt: Caller is retrieving Window Region 1\n"); 1881 } 1882 else 1883 { 1884 RegionType = IntGdiGetRgnBox(Window->hrgnUpdate, pRect); 1885 1886 if (RegionType != ERROR && RegionType != NULLREGION) 1887 RECTL_bIntersectRect(pRect, pRect, &Window->rcClient); 1888 } 1889 1890 if (IntIntersectWithParents(Window, pRect)) 1891 { 1892 if (!UserIsDesktopWindow(Window)) 1893 { 1894 RECTL_vOffsetRect(pRect, 1895 -Window->rcClient.left, 1896 -Window->rcClient.top); 1897 } 1898 if (Window->pcls->style & CS_OWNDC) 1899 { 1900 HDC hdc; 1901 //DWORD layout; 1902 hdc = UserGetDCEx(Window, NULL, DCX_USESTYLE); 1903 //layout = NtGdiSetLayout(hdc, -1, 0); 1904 //IntMapWindowPoints( 0, Window, (LPPOINT)pRect, 2 ); 1905 GreDPtoLP( hdc, (LPPOINT)pRect, 2 ); 1906 //NtGdiSetLayout(hdc, -1, layout); 1907 UserReleaseDC(Window, hdc, FALSE); 1908 } 1909 } 1910 else 1911 { 1912 pRect->left = pRect->top = pRect->right = pRect->bottom = 0; 1913 } 1914 } 1915 return Ret; 1916 } 1917 1918 /* 1919 * NtUserGetUpdateRgn 1920 * 1921 * Status 1922 * @implemented 1923 */ 1924 1925 INT APIENTRY 1926 NtUserGetUpdateRgn(HWND hWnd, HRGN hRgn, BOOL bErase) 1927 { 1928 DECLARE_RETURN(INT); 1929 PWND Window; 1930 INT ret; 1931 1932 TRACE("Enter NtUserGetUpdateRgn\n"); 1933 UserEnterExclusive(); 1934 1935 if (!(Window = UserGetWindowObject(hWnd))) 1936 { 1937 RETURN(ERROR); 1938 } 1939 1940 ret = co_UserGetUpdateRgn(Window, hRgn, bErase); 1941 1942 RETURN(ret); 1943 1944 CLEANUP: 1945 TRACE("Leave NtUserGetUpdateRgn, ret=%i\n",_ret_); 1946 UserLeave(); 1947 END_CLEANUP; 1948 } 1949 1950 /* 1951 * NtUserGetUpdateRect 1952 * 1953 * Status 1954 * @implemented 1955 */ 1956 1957 BOOL APIENTRY 1958 NtUserGetUpdateRect(HWND hWnd, LPRECT UnsafeRect, BOOL bErase) 1959 { 1960 PWND Window; 1961 RECTL Rect; 1962 NTSTATUS Status; 1963 BOOL Ret; 1964 DECLARE_RETURN(BOOL); 1965 1966 TRACE("Enter NtUserGetUpdateRect\n"); 1967 UserEnterExclusive(); 1968 1969 if (!(Window = UserGetWindowObject(hWnd))) 1970 { 1971 RETURN(FALSE); 1972 } 1973 1974 Ret = co_UserGetUpdateRect(Window, &Rect, bErase); 1975 1976 if (UnsafeRect != NULL) 1977 { 1978 Status = MmCopyToCaller(UnsafeRect, &Rect, sizeof(RECTL)); 1979 if (!NT_SUCCESS(Status)) 1980 { 1981 EngSetLastError(ERROR_INVALID_PARAMETER); 1982 RETURN(FALSE); 1983 } 1984 } 1985 1986 RETURN(Ret); 1987 1988 CLEANUP: 1989 TRACE("Leave NtUserGetUpdateRect, ret=%i\n",_ret_); 1990 UserLeave(); 1991 END_CLEANUP; 1992 } 1993 1994 /* 1995 * NtUserRedrawWindow 1996 * 1997 * Status 1998 * @implemented 1999 */ 2000 2001 BOOL APIENTRY 2002 NtUserRedrawWindow( 2003 HWND hWnd, 2004 CONST RECT *lprcUpdate, 2005 HRGN hrgnUpdate, 2006 UINT flags) 2007 { 2008 RECTL SafeUpdateRect; 2009 PWND Wnd; 2010 BOOL Ret; 2011 USER_REFERENCE_ENTRY Ref; 2012 NTSTATUS Status = STATUS_SUCCESS; 2013 PREGION RgnUpdate = NULL; 2014 DECLARE_RETURN(BOOL); 2015 2016 TRACE("Enter NtUserRedrawWindow\n"); 2017 UserEnterExclusive(); 2018 2019 if (!(Wnd = UserGetWindowObject(hWnd ? hWnd : IntGetDesktopWindow()))) 2020 { 2021 RETURN( FALSE); 2022 } 2023 2024 if (lprcUpdate) 2025 { 2026 _SEH2_TRY 2027 { 2028 ProbeForRead(lprcUpdate, sizeof(RECTL), 1); 2029 RtlCopyMemory(&SafeUpdateRect, lprcUpdate, sizeof(RECTL)); 2030 } 2031 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2032 { 2033 Status = _SEH2_GetExceptionCode(); 2034 } 2035 _SEH2_END 2036 if (!NT_SUCCESS(Status)) 2037 { 2038 EngSetLastError(RtlNtStatusToDosError(Status)); 2039 RETURN( FALSE); 2040 } 2041 } 2042 2043 if ( flags & ~(RDW_ERASE|RDW_FRAME|RDW_INTERNALPAINT|RDW_INVALIDATE| 2044 RDW_NOERASE|RDW_NOFRAME|RDW_NOINTERNALPAINT|RDW_VALIDATE| 2045 RDW_ERASENOW|RDW_UPDATENOW|RDW_ALLCHILDREN|RDW_NOCHILDREN) ) 2046 { 2047 /* RedrawWindow fails only in case that flags are invalid */ 2048 EngSetLastError(ERROR_INVALID_FLAGS); 2049 RETURN( FALSE); 2050 } 2051 2052 /* We can't hold lock on GDI objects while doing roundtrips to user mode, 2053 * so it will be copied. 2054 */ 2055 if (hrgnUpdate > HRGN_WINDOW) 2056 { 2057 RgnUpdate = REGION_LockRgn(hrgnUpdate); 2058 if (!RgnUpdate) 2059 { 2060 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 2061 RETURN(FALSE); 2062 } 2063 REGION_UnlockRgn(RgnUpdate); 2064 } 2065 else if (hrgnUpdate == HRGN_WINDOW) // Trap it out. 2066 { 2067 ERR("NTRW: Caller is passing Window Region 1\n"); 2068 } 2069 2070 UserRefObjectCo(Wnd, &Ref); 2071 2072 Ret = co_UserRedrawWindow( Wnd, 2073 lprcUpdate ? &SafeUpdateRect : NULL, 2074 RgnUpdate, 2075 flags); 2076 2077 UserDerefObjectCo(Wnd); 2078 2079 RETURN( Ret); 2080 2081 CLEANUP: 2082 TRACE("Leave NtUserRedrawWindow, ret=%i\n",_ret_); 2083 UserLeave(); 2084 END_CLEANUP; 2085 } 2086 2087 BOOL 2088 UserDrawCaptionText( 2089 PWND pWnd, 2090 HDC hDc, 2091 const PUNICODE_STRING Text, 2092 const RECTL *lpRc, 2093 UINT uFlags, 2094 HFONT hFont) 2095 { 2096 HFONT hOldFont = NULL; 2097 COLORREF OldTextColor; 2098 NONCLIENTMETRICSW nclm; 2099 NTSTATUS Status; 2100 BOOLEAN bDeleteFont = FALSE; 2101 SIZE Size; 2102 BOOL Ret = TRUE; 2103 ULONG fit = 0, Length; 2104 RECTL r = *lpRc; 2105 2106 TRACE("UserDrawCaptionText: %wZ\n", Text); 2107 2108 nclm.cbSize = sizeof(nclm); 2109 if (!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS, nclm.cbSize, &nclm, 0)) 2110 { 2111 ERR("UserSystemParametersInfo() failed!\n"); 2112 return FALSE; 2113 } 2114 2115 if (!hFont) 2116 { 2117 if(uFlags & DC_SMALLCAP) 2118 Status = TextIntCreateFontIndirect(&nclm.lfSmCaptionFont, &hFont); 2119 else 2120 Status = TextIntCreateFontIndirect(&nclm.lfCaptionFont, &hFont); 2121 2122 if(!NT_SUCCESS(Status)) 2123 { 2124 ERR("TextIntCreateFontIndirect() failed! Status: 0x%x\n", Status); 2125 return FALSE; 2126 } 2127 2128 bDeleteFont = TRUE; 2129 } 2130 2131 IntGdiSetBkMode(hDc, TRANSPARENT); 2132 2133 hOldFont = NtGdiSelectFont(hDc, hFont); 2134 2135 if(uFlags & DC_INBUTTON) 2136 OldTextColor = IntGdiSetTextColor(hDc, IntGetSysColor(COLOR_BTNTEXT)); 2137 else 2138 OldTextColor = IntGdiSetTextColor(hDc, 2139 IntGetSysColor(uFlags & DC_ACTIVE ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT)); 2140 2141 // Adjust for system menu. 2142 if (pWnd && pWnd->style & WS_SYSMENU) 2143 { 2144 r.right -= UserGetSystemMetrics(SM_CYCAPTION) - 1; 2145 if ((pWnd->style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX)) && !(pWnd->ExStyle & WS_EX_TOOLWINDOW)) 2146 { 2147 r.right -= UserGetSystemMetrics(SM_CXSIZE) + 1; 2148 r.right -= UserGetSystemMetrics(SM_CXSIZE) + 1; 2149 } 2150 } 2151 2152 GreGetTextExtentExW(hDc, Text->Buffer, Text->Length/sizeof(WCHAR), r.right - r.left, &fit, 0, &Size, 0); 2153 2154 Length = (Text->Length/sizeof(WCHAR) == fit ? fit : fit+1); 2155 2156 if (Text->Length/sizeof(WCHAR) > Length) 2157 { 2158 Ret = FALSE; 2159 } 2160 2161 if (Ret) 2162 { // Faster while in setup. 2163 UserExtTextOutW( hDc, 2164 lpRc->left, 2165 lpRc->top + (lpRc->bottom - lpRc->top - Size.cy) / 2, // DT_SINGLELINE && DT_VCENTER 2166 ETO_CLIPPED, 2167 (RECTL *)lpRc, 2168 Text->Buffer, 2169 Length); 2170 } 2171 else 2172 { 2173 DrawTextW( hDc, 2174 Text->Buffer, 2175 Text->Length/sizeof(WCHAR), 2176 (RECTL *)&r, 2177 DT_END_ELLIPSIS|DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX|DT_LEFT); 2178 } 2179 2180 IntGdiSetTextColor(hDc, OldTextColor); 2181 2182 if (hOldFont) 2183 NtGdiSelectFont(hDc, hOldFont); 2184 2185 if (bDeleteFont) 2186 GreDeleteObject(hFont); 2187 2188 return Ret; 2189 } 2190 2191 // 2192 // This draws Buttons, Icons and Text... 2193 // 2194 BOOL UserDrawCaption( 2195 PWND pWnd, 2196 HDC hDc, 2197 RECTL *lpRc, 2198 HFONT hFont, 2199 HICON hIcon, 2200 const PUNICODE_STRING Str, 2201 UINT uFlags) 2202 { 2203 BOOL Ret = FALSE; 2204 HBRUSH hBgBrush, hOldBrush = NULL; 2205 RECTL Rect = *lpRc; 2206 BOOL HasIcon; 2207 2208 RECTL_vMakeWellOrdered(lpRc); 2209 2210 /* Determine whether the icon needs to be displayed */ 2211 if (!hIcon && pWnd != NULL) 2212 { 2213 HasIcon = (uFlags & DC_ICON) && !(uFlags & DC_SMALLCAP) && 2214 (pWnd->style & WS_SYSMENU) && !(pWnd->ExStyle & WS_EX_TOOLWINDOW); 2215 } 2216 else 2217 HasIcon = (hIcon != NULL); 2218 2219 // Draw the caption background 2220 if((uFlags & DC_GRADIENT) && !(uFlags & DC_INBUTTON)) 2221 { 2222 static GRADIENT_RECT gcap = {0, 1}; 2223 TRIVERTEX Vertices[2]; 2224 COLORREF Colors[2]; 2225 2226 Colors[0] = IntGetSysColor((uFlags & DC_ACTIVE) ? 2227 COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION); 2228 2229 Colors[1] = IntGetSysColor((uFlags & DC_ACTIVE) ? 2230 COLOR_GRADIENTACTIVECAPTION : COLOR_GRADIENTINACTIVECAPTION); 2231 2232 Vertices[0].x = Rect.left; 2233 Vertices[0].y = Rect.top; 2234 Vertices[0].Red = (WORD)Colors[0]<<8; 2235 Vertices[0].Green = (WORD)Colors[0] & 0xFF00; 2236 Vertices[0].Blue = (WORD)(Colors[0]>>8) & 0xFF00; 2237 Vertices[0].Alpha = 0; 2238 2239 Vertices[1].x = Rect.right; 2240 Vertices[1].y = Rect.bottom; 2241 Vertices[1].Red = (WORD)Colors[1]<<8; 2242 Vertices[1].Green = (WORD)Colors[1] & 0xFF00; 2243 Vertices[1].Blue = (WORD)(Colors[1]>>8) & 0xFF00; 2244 Vertices[1].Alpha = 0; 2245 2246 if(!GreGradientFill(hDc, Vertices, 2, &gcap, 1, GRADIENT_FILL_RECT_H)) 2247 { 2248 ERR("GreGradientFill() failed!\n"); 2249 goto cleanup; 2250 } 2251 } 2252 else 2253 { 2254 if(uFlags & DC_INBUTTON) 2255 hBgBrush = IntGetSysColorBrush(COLOR_3DFACE); 2256 else if(uFlags & DC_ACTIVE) 2257 hBgBrush = IntGetSysColorBrush(COLOR_ACTIVECAPTION); 2258 else 2259 hBgBrush = IntGetSysColorBrush(COLOR_INACTIVECAPTION); 2260 2261 hOldBrush = NtGdiSelectBrush(hDc, hBgBrush); 2262 2263 if(!hOldBrush) 2264 { 2265 ERR("NtGdiSelectBrush() failed!\n"); 2266 goto cleanup; 2267 } 2268 2269 if(!NtGdiPatBlt(hDc, Rect.left, Rect.top, 2270 Rect.right - Rect.left, 2271 Rect.bottom - Rect.top, 2272 PATCOPY)) 2273 { 2274 ERR("NtGdiPatBlt() failed!\n"); 2275 goto cleanup; 2276 } 2277 } 2278 2279 /* Draw icon */ 2280 if (HasIcon) 2281 { 2282 PCURICON_OBJECT pIcon = NULL; 2283 2284 if (hIcon) 2285 { 2286 pIcon = UserGetCurIconObject(hIcon); 2287 } 2288 else if (pWnd) 2289 { 2290 pIcon = NC_IconForWindow(pWnd); 2291 // FIXME: NC_IconForWindow should reference it for us */ 2292 if (pIcon) 2293 UserReferenceObject(pIcon); 2294 } 2295 2296 if (pIcon) 2297 { 2298 LONG cx = UserGetSystemMetrics(SM_CXSMICON); 2299 LONG cy = UserGetSystemMetrics(SM_CYSMICON); 2300 LONG x = Rect.left - cx/2 + 1 + (Rect.bottom - Rect.top)/2; // this is really what Window does 2301 LONG y = (Rect.top + Rect.bottom - cy)/2; // center 2302 UserDrawIconEx(hDc, x, y, pIcon, cx, cy, 0, NULL, DI_NORMAL); 2303 UserDereferenceObject(pIcon); 2304 } 2305 else 2306 { 2307 HasIcon = FALSE; 2308 } 2309 } 2310 2311 if (HasIcon) 2312 Rect.left += Rect.bottom - Rect.top; 2313 2314 if((uFlags & DC_TEXT)) 2315 { 2316 BOOL Set = FALSE; 2317 Rect.left += 2; 2318 2319 if (Str) 2320 Set = UserDrawCaptionText(pWnd, hDc, Str, &Rect, uFlags, hFont); 2321 else if (pWnd != NULL) // FIXME: Windows does not do that 2322 { 2323 UNICODE_STRING ustr; 2324 ustr.Buffer = pWnd->strName.Buffer; // FIXME: LARGE_STRING truncated! 2325 ustr.Length = (USHORT)min(pWnd->strName.Length, MAXUSHORT); 2326 ustr.MaximumLength = (USHORT)min(pWnd->strName.MaximumLength, MAXUSHORT); 2327 Set = UserDrawCaptionText(pWnd, hDc, &ustr, &Rect, uFlags, hFont); 2328 } 2329 if (pWnd) 2330 { 2331 if (Set) 2332 pWnd->state2 &= ~WNDS2_CAPTIONTEXTTRUNCATED; 2333 else 2334 pWnd->state2 |= WNDS2_CAPTIONTEXTTRUNCATED; 2335 } 2336 } 2337 2338 Ret = TRUE; 2339 2340 cleanup: 2341 if (hOldBrush) NtGdiSelectBrush(hDc, hOldBrush); 2342 2343 return Ret; 2344 } 2345 2346 INT 2347 FASTCALL 2348 UserRealizePalette(HDC hdc) 2349 { 2350 HWND hWnd, hWndDesktop; 2351 DWORD Ret; 2352 2353 Ret = IntGdiRealizePalette(hdc); 2354 if (Ret) // There was a change. 2355 { 2356 hWnd = IntWindowFromDC(hdc); 2357 if (hWnd) // Send broadcast if dc is associated with a window. 2358 { // FYI: Thread locked in CallOneParam. 2359 hWndDesktop = IntGetDesktopWindow(); 2360 if ( hWndDesktop != hWnd ) 2361 { 2362 PWND pWnd = UserGetWindowObject(hWndDesktop); 2363 ERR("RealizePalette Desktop."); 2364 hdc = UserGetWindowDC(pWnd); 2365 IntPaintDesktop(hdc); 2366 UserReleaseDC(pWnd,hdc,FALSE); 2367 } 2368 UserSendNotifyMessage((HWND)HWND_BROADCAST, WM_PALETTECHANGED, (WPARAM)hWnd, 0); 2369 } 2370 } 2371 return Ret; 2372 } 2373 2374 BOOL 2375 APIENTRY 2376 NtUserDrawCaptionTemp( 2377 HWND hWnd, 2378 HDC hDC, 2379 LPCRECT lpRc, 2380 HFONT hFont, 2381 HICON hIcon, 2382 const PUNICODE_STRING str, 2383 UINT uFlags) 2384 { 2385 PWND pWnd = NULL; 2386 UNICODE_STRING SafeStr = {0}; 2387 NTSTATUS Status = STATUS_SUCCESS; 2388 RECTL SafeRect; 2389 BOOL Ret; 2390 2391 UserEnterExclusive(); 2392 2393 if (hWnd != NULL) 2394 { 2395 if(!(pWnd = UserGetWindowObject(hWnd))) 2396 { 2397 UserLeave(); 2398 return FALSE; 2399 } 2400 } 2401 2402 _SEH2_TRY 2403 { 2404 ProbeForRead(lpRc, sizeof(RECTL), sizeof(ULONG)); 2405 RtlCopyMemory(&SafeRect, lpRc, sizeof(RECTL)); 2406 if (str != NULL) 2407 { 2408 SafeStr = ProbeForReadUnicodeString(str); 2409 if (SafeStr.Length != 0) 2410 { 2411 ProbeForRead( SafeStr.Buffer, 2412 SafeStr.Length, 2413 sizeof(WCHAR)); 2414 } 2415 } 2416 } 2417 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2418 { 2419 Status = _SEH2_GetExceptionCode(); 2420 } 2421 _SEH2_END; 2422 2423 if (Status != STATUS_SUCCESS) 2424 { 2425 SetLastNtError(Status); 2426 UserLeave(); 2427 return FALSE; 2428 } 2429 2430 if (str != NULL) 2431 Ret = UserDrawCaption(pWnd, hDC, &SafeRect, hFont, hIcon, &SafeStr, uFlags); 2432 else 2433 { 2434 if ( RECTL_bIsEmptyRect(&SafeRect) && hFont == 0 && hIcon == 0 ) 2435 { 2436 Ret = TRUE; 2437 if (uFlags & DC_DRAWCAPTIONMD) 2438 { 2439 ERR("NC Caption Mode\n"); 2440 UserDrawCaptionBar(pWnd, hDC, uFlags); 2441 goto Exit; 2442 } 2443 else if (uFlags & DC_DRAWFRAMEMD) 2444 { 2445 ERR("NC Paint Mode\n"); 2446 NC_DoNCPaint(pWnd, hDC, uFlags); // Update Menus too! 2447 goto Exit; 2448 } 2449 } 2450 Ret = UserDrawCaption(pWnd, hDC, &SafeRect, hFont, hIcon, NULL, uFlags); 2451 } 2452 Exit: 2453 UserLeave(); 2454 return Ret; 2455 } 2456 2457 BOOL 2458 APIENTRY 2459 NtUserDrawCaption(HWND hWnd, 2460 HDC hDC, 2461 LPCRECT lpRc, 2462 UINT uFlags) 2463 { 2464 return NtUserDrawCaptionTemp(hWnd, hDC, lpRc, 0, 0, NULL, uFlags); 2465 } 2466 2467 INT FASTCALL 2468 co_UserExcludeUpdateRgn(HDC hDC, PWND Window) 2469 { 2470 POINT pt; 2471 RECT rc; 2472 2473 if (Window->hrgnUpdate) 2474 { 2475 if (Window->hrgnUpdate == HRGN_WINDOW) 2476 { 2477 return NtGdiIntersectClipRect(hDC, 0, 0, 0, 0); 2478 } 2479 else 2480 { 2481 INT ret = ERROR; 2482 HRGN hrgn = NtGdiCreateRectRgn(0,0,0,0); 2483 2484 if ( hrgn && GreGetDCPoint( hDC, GdiGetDCOrg, &pt) ) 2485 { 2486 if ( NtGdiGetRandomRgn( hDC, hrgn, CLIPRGN) == NULLREGION ) 2487 { 2488 NtGdiOffsetRgn(hrgn, pt.x, pt.y); 2489 } 2490 else 2491 { 2492 HRGN hrgnScreen; 2493 PMONITOR pm = UserGetPrimaryMonitor(); 2494 hrgnScreen = NtGdiCreateRectRgn(0,0,0,0); 2495 NtGdiCombineRgn(hrgnScreen, hrgnScreen, pm->hrgnMonitor, RGN_OR); 2496 2497 NtGdiCombineRgn(hrgn, hrgnScreen, NULL, RGN_COPY); 2498 2499 GreDeleteObject(hrgnScreen); 2500 } 2501 2502 NtGdiCombineRgn(hrgn, hrgn, Window->hrgnUpdate, RGN_DIFF); 2503 2504 NtGdiOffsetRgn(hrgn, -pt.x, -pt.y); 2505 2506 ret = NtGdiExtSelectClipRgn(hDC, hrgn, RGN_COPY); 2507 2508 GreDeleteObject(hrgn); 2509 } 2510 return ret; 2511 } 2512 } 2513 else 2514 { 2515 return GdiGetClipBox( hDC, &rc); 2516 } 2517 } 2518 2519 INT 2520 APIENTRY 2521 NtUserExcludeUpdateRgn( 2522 HDC hDC, 2523 HWND hWnd) 2524 { 2525 INT ret = ERROR; 2526 PWND pWnd; 2527 2528 TRACE("Enter NtUserExcludeUpdateRgn\n"); 2529 UserEnterExclusive(); 2530 2531 pWnd = UserGetWindowObject(hWnd); 2532 2533 if (hDC && pWnd) 2534 ret = co_UserExcludeUpdateRgn(hDC, pWnd); 2535 2536 TRACE("Leave NtUserExcludeUpdateRgn, ret=%i\n", ret); 2537 2538 UserLeave(); 2539 return ret; 2540 } 2541 2542 BOOL 2543 APIENTRY 2544 NtUserInvalidateRect( 2545 HWND hWnd, 2546 CONST RECT *lpUnsafeRect, 2547 BOOL bErase) 2548 { 2549 UINT flags = RDW_INVALIDATE | (bErase ? RDW_ERASE : 0); 2550 if (!hWnd) 2551 { 2552 flags = RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW; 2553 lpUnsafeRect = NULL; 2554 } 2555 return NtUserRedrawWindow(hWnd, lpUnsafeRect, NULL, flags); 2556 } 2557 2558 BOOL 2559 APIENTRY 2560 NtUserInvalidateRgn( 2561 HWND hWnd, 2562 HRGN hRgn, 2563 BOOL bErase) 2564 { 2565 if (!hWnd) 2566 { 2567 EngSetLastError( ERROR_INVALID_WINDOW_HANDLE ); 2568 return FALSE; 2569 } 2570 return NtUserRedrawWindow(hWnd, NULL, hRgn, RDW_INVALIDATE | (bErase? RDW_ERASE : 0)); 2571 } 2572 2573 BOOL 2574 APIENTRY 2575 NtUserPrintWindow( 2576 HWND hwnd, 2577 HDC hdcBlt, 2578 UINT nFlags) 2579 { 2580 PWND Window; 2581 BOOL Ret = FALSE; 2582 2583 UserEnterExclusive(); 2584 2585 if (hwnd) 2586 { 2587 if (!(Window = UserGetWindowObject(hwnd)) || 2588 UserIsDesktopWindow(Window) || UserIsMessageWindow(Window)) 2589 { 2590 goto Exit; 2591 } 2592 2593 if ( Window ) 2594 { 2595 /* Validate flags and check it as a mask for 0 or 1. */ 2596 if ( (nFlags & PW_CLIENTONLY) == nFlags) 2597 Ret = IntPrintWindow( Window, hdcBlt, nFlags); 2598 else 2599 EngSetLastError(ERROR_INVALID_PARAMETER); 2600 } 2601 } 2602 Exit: 2603 UserLeave(); 2604 return Ret; 2605 } 2606 2607 /* ValidateRect gets redirected to NtUserValidateRect: 2608 http://blog.csdn.net/ntdll/archive/2005/10/19/509299.aspx */ 2609 BOOL 2610 APIENTRY 2611 NtUserValidateRect( 2612 HWND hWnd, 2613 const RECT *lpRect) 2614 { 2615 UINT flags = RDW_VALIDATE; 2616 if (!hWnd) 2617 { 2618 flags = RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW; 2619 lpRect = NULL; 2620 } 2621 return NtUserRedrawWindow(hWnd, lpRect, NULL, flags); 2622 } 2623 2624 /* EOF */ 2625