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