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