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