1 /* 2 * PROJECT: ReactOS Win32k subsystem 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: win32ss/user/ntuser/windc.c 5 * PURPOSE: Window DC management 6 * COPYRIGHT: Copyright 2007 ReactOS Team 7 */ 8 9 #include <win32k.h> 10 DBG_DEFAULT_CHANNEL(UserDce); 11 12 /* GLOBALS *******************************************************************/ 13 14 /* NOTE: I think we should store this per window station (including GDI objects) */ 15 /* Answer: No, use the DCE pMonitor to compare with! */ 16 17 static LIST_ENTRY LEDce; 18 static INT DCECount = 0; // Count of DCE in system. 19 20 #define DCX_CACHECOMPAREMASK (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | \ 21 DCX_NORESETATTRS | DCX_LOCKWINDOWUPDATE | \ 22 DCX_LAYEREDWIN | DCX_CACHE | DCX_WINDOW | \ 23 DCX_PARENTCLIP) 24 25 /* FUNCTIONS *****************************************************************/ 26 27 CODE_SEG("INIT") 28 NTSTATUS 29 NTAPI 30 InitDCEImpl(VOID) 31 { 32 InitializeListHead(&LEDce); 33 return STATUS_SUCCESS; 34 } 35 36 // 37 // This should be moved to dc.c or dcutil.c. 38 // 39 HDC FASTCALL 40 DceCreateDisplayDC(VOID) 41 { 42 UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"DISPLAY"); 43 44 if (!co_IntGraphicsCheck(TRUE)) 45 KeBugCheckEx(VIDEO_DRIVER_INIT_FAILURE, 0, 0, 0, USER_VERSION); 46 47 return IntGdiCreateDC(&DriverName, NULL, NULL, NULL, FALSE); 48 } 49 50 /* Returns the DCE pointer from the HDC handle */ 51 DCE* 52 FASTCALL 53 DceGetDceFromDC(HDC hdc) 54 { 55 PLIST_ENTRY ListEntry; 56 DCE* dce; 57 58 ListEntry = LEDce.Flink; 59 while (ListEntry != &LEDce) 60 { 61 dce = CONTAINING_RECORD(ListEntry, DCE, List); 62 ListEntry = ListEntry->Flink; 63 if (dce->hDC == hdc) 64 return dce; 65 } 66 67 return NULL; 68 } 69 70 static 71 PREGION FASTCALL 72 DceGetVisRgn(PWND Window, ULONG Flags, HWND hWndChild, ULONG CFlags) 73 { 74 PREGION Rgn; 75 Rgn = VIS_ComputeVisibleRegion( Window, 76 0 == (Flags & DCX_WINDOW), 77 0 != (Flags & DCX_CLIPCHILDREN), 78 0 != (Flags & DCX_CLIPSIBLINGS)); 79 /* Caller expects a non-null region */ 80 if (!Rgn) 81 Rgn = IntSysCreateRectpRgn(0, 0, 0, 0); 82 return Rgn; 83 } 84 85 PDCE FASTCALL 86 DceAllocDCE(PWND Window OPTIONAL, DCE_TYPE Type) 87 { 88 PDCE pDce; 89 90 pDce = ExAllocatePoolWithTag(PagedPool, sizeof(DCE), USERTAG_DCE); 91 if(!pDce) 92 return NULL; 93 94 pDce->hDC = DceCreateDisplayDC(); 95 if (!pDce->hDC) 96 { 97 ExFreePoolWithTag(pDce, USERTAG_DCE); 98 return NULL; 99 } 100 DCECount++; 101 TRACE("Alloc DCE's! %d\n",DCECount); 102 pDce->hwndCurrent = (Window ? UserHMGetHandle(Window) : NULL); 103 pDce->pwndOrg = Window; 104 pDce->pwndClip = Window; 105 pDce->hrgnClip = NULL; 106 pDce->hrgnClipPublic = NULL; 107 pDce->hrgnSavedVis = NULL; 108 pDce->ppiOwner = NULL; 109 110 InsertTailList(&LEDce, &pDce->List); 111 112 DCU_SetDcUndeletable(pDce->hDC); 113 114 if (Type == DCE_WINDOW_DC || Type == DCE_CLASS_DC) // Window DCE have ownership. 115 { 116 pDce->ptiOwner = GetW32ThreadInfo(); 117 } 118 else 119 { 120 TRACE("FREE DCATTR!!!! NOT DCE_WINDOW_DC!!!!! hDC-> %p\n", pDce->hDC); 121 GreSetDCOwner(pDce->hDC, GDI_OBJ_HMGR_NONE); 122 pDce->ptiOwner = NULL; 123 } 124 125 if (Type == DCE_CACHE_DC) 126 { 127 pDce->DCXFlags = DCX_CACHE | DCX_DCEEMPTY; 128 } 129 else 130 { 131 pDce->DCXFlags = DCX_DCEBUSY; 132 if (Window) 133 { 134 if (Type == DCE_WINDOW_DC) 135 { 136 if (Window->style & WS_CLIPCHILDREN) pDce->DCXFlags |= DCX_CLIPCHILDREN; 137 if (Window->style & WS_CLIPSIBLINGS) pDce->DCXFlags |= DCX_CLIPSIBLINGS; 138 } 139 } 140 } 141 return(pDce); 142 } 143 144 static VOID APIENTRY 145 DceSetDrawable( PWND Window OPTIONAL, 146 HDC hDC, 147 ULONG Flags, 148 BOOL SetClipOrigin) 149 { 150 RECTL rect = {0,0,0,0}; 151 152 if (Window) 153 { 154 if (Flags & DCX_WINDOW) 155 { 156 rect = Window->rcWindow; 157 } 158 else 159 { 160 rect = Window->rcClient; 161 } 162 } 163 164 /* Set DC Origin and Window Rectangle */ 165 GreSetDCOrg( hDC, rect.left, rect.top, &rect); 166 } 167 168 169 static VOID FASTCALL 170 DceDeleteClipRgn(DCE* Dce) 171 { 172 Dce->DCXFlags &= ~(DCX_EXCLUDERGN | DCX_INTERSECTRGN); 173 174 if (Dce->DCXFlags & DCX_KEEPCLIPRGN ) 175 { 176 Dce->DCXFlags &= ~DCX_KEEPCLIPRGN; 177 } 178 else if (Dce->hrgnClip != NULL) 179 { 180 GreDeleteObject(Dce->hrgnClip); 181 } 182 183 Dce->hrgnClip = NULL; 184 185 /* Make it dirty so that the vis rgn gets recomputed next time */ 186 Dce->DCXFlags |= DCX_DCEDIRTY; 187 IntGdiSetHookFlags(Dce->hDC, DCHF_INVALIDATEVISRGN); 188 } 189 190 VOID 191 FASTCALL 192 DceUpdateVisRgn(DCE *Dce, PWND Window, ULONG Flags) 193 { 194 PREGION RgnVisible = NULL; 195 ULONG DcxFlags; 196 PWND DesktopWindow; 197 198 if (Flags & DCX_PARENTCLIP) 199 { 200 PWND Parent; 201 202 Parent = Window->spwndParent; 203 if (!Parent) 204 { 205 RgnVisible = NULL; 206 goto noparent; 207 } 208 209 if (Parent->style & WS_CLIPSIBLINGS) 210 { 211 DcxFlags = DCX_CLIPSIBLINGS | 212 (Flags & ~(DCX_CLIPCHILDREN | DCX_WINDOW)); 213 } 214 else 215 { 216 DcxFlags = Flags & ~(DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | DCX_WINDOW); 217 } 218 RgnVisible = DceGetVisRgn(Parent, DcxFlags, UserHMGetHandle(Window), Flags); 219 } 220 else if (Window == NULL) 221 { 222 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow()); 223 if (NULL != DesktopWindow) 224 { 225 RgnVisible = IntSysCreateRectpRgnIndirect(&DesktopWindow->rcWindow); 226 } 227 else 228 { 229 RgnVisible = NULL; 230 } 231 } 232 else 233 { 234 RgnVisible = DceGetVisRgn(Window, Flags, 0, 0); 235 } 236 237 noparent: 238 if (Flags & DCX_INTERSECTRGN) 239 { 240 PREGION RgnClip = NULL; 241 242 if (Dce->hrgnClip != NULL) 243 RgnClip = REGION_LockRgn(Dce->hrgnClip); 244 245 if (RgnClip) 246 { 247 IntGdiCombineRgn(RgnVisible, RgnVisible, RgnClip, RGN_AND); 248 REGION_UnlockRgn(RgnClip); 249 } 250 else 251 { 252 if (RgnVisible != NULL) 253 { 254 REGION_Delete(RgnVisible); 255 } 256 RgnVisible = IntSysCreateRectpRgn(0, 0, 0, 0); 257 } 258 } 259 else if ((Flags & DCX_EXCLUDERGN) && Dce->hrgnClip != NULL) 260 { 261 PREGION RgnClip = REGION_LockRgn(Dce->hrgnClip); 262 IntGdiCombineRgn(RgnVisible, RgnVisible, RgnClip, RGN_DIFF); 263 REGION_UnlockRgn(RgnClip); 264 } 265 266 Dce->DCXFlags &= ~DCX_DCEDIRTY; 267 GdiSelectVisRgn(Dce->hDC, RgnVisible); 268 /* Tell GDI driver */ 269 if (Window) 270 IntEngWindowChanged(Window, WOC_RGN_CLIENT); 271 272 if (RgnVisible != NULL) 273 { 274 REGION_Delete(RgnVisible); 275 } 276 } 277 278 static INT FASTCALL 279 DceReleaseDC(DCE* dce, BOOL EndPaint) 280 { 281 if (DCX_DCEBUSY != (dce->DCXFlags & (DCX_INDESTROY | DCX_DCEEMPTY | DCX_DCEBUSY))) 282 { 283 return 0; 284 } 285 286 /* Restore previous visible region */ 287 if (EndPaint) 288 { 289 DceUpdateVisRgn(dce, dce->pwndOrg, dce->DCXFlags); 290 } 291 292 if ((dce->DCXFlags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN)) && 293 ((dce->DCXFlags & DCX_CACHE) || EndPaint)) 294 { 295 DceDeleteClipRgn(dce); 296 } 297 298 if (dce->DCXFlags & DCX_CACHE) 299 { 300 if (!(dce->DCXFlags & DCX_NORESETATTRS)) 301 { 302 // Clean the DC 303 if (!IntGdiCleanDC(dce->hDC)) return 0; 304 305 if (dce->DCXFlags & DCX_DCEDIRTY) 306 { 307 /* Don't keep around invalidated entries 308 * because SetDCState() disables hVisRgn updates 309 * by removing dirty bit. */ 310 dce->hwndCurrent = 0; 311 dce->pwndOrg = NULL; 312 dce->pwndClip = NULL; 313 dce->DCXFlags &= DCX_CACHE; 314 dce->DCXFlags |= DCX_DCEEMPTY; 315 } 316 } 317 dce->DCXFlags &= ~DCX_DCEBUSY; 318 TRACE("Exit!!!!! DCX_CACHE!!!!!! hDC-> %p \n", dce->hDC); 319 if (!GreSetDCOwner(dce->hDC, GDI_OBJ_HMGR_NONE)) 320 return 0; 321 dce->ptiOwner = NULL; // Reset ownership. 322 dce->ppiOwner = NULL; 323 324 #if 0 // Need to research and fix before this is a "growing" issue. 325 if (++DCECache > 32) 326 { 327 ListEntry = LEDce.Flink; 328 while (ListEntry != &LEDce) 329 { 330 pDCE = CONTAINING_RECORD(ListEntry, DCE, List); 331 ListEntry = ListEntry->Flink; 332 if (!(pDCE->DCXFlags & DCX_DCEBUSY)) 333 { /* Free the unused cache DCEs. */ 334 DceFreeDCE(pDCE, TRUE); 335 } 336 } 337 } 338 #endif 339 } 340 return 1; // Released! 341 } 342 343 344 HDC FASTCALL 345 UserGetDCEx(PWND Wnd OPTIONAL, HANDLE ClipRegion, ULONG Flags) 346 { 347 PWND Parent; 348 ULONG DcxFlags; 349 DCE* Dce = NULL; 350 BOOL UpdateClipOrigin = FALSE; 351 BOOL bUpdateVisRgn = TRUE; 352 HDC hDC = NULL; 353 PPROCESSINFO ppi; 354 PLIST_ENTRY ListEntry; 355 356 if (NULL == Wnd) 357 { 358 Flags &= ~DCX_USESTYLE; 359 Flags |= DCX_CACHE; 360 } 361 362 if (Flags & DCX_PARENTCLIP) Flags |= DCX_CACHE; 363 364 // When GetDC is called with hWnd nz, DCX_CACHE & _WINDOW are clear w _USESTYLE set. 365 if (Flags & DCX_USESTYLE) 366 { 367 Flags &= ~(DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS | DCX_PARENTCLIP); 368 if (!(Flags & DCX_WINDOW)) // Not window rectangle 369 { 370 if (Wnd->pcls->style & CS_PARENTDC) 371 { 372 Flags |= DCX_PARENTCLIP; 373 } 374 375 if (!(Flags & DCX_CACHE) && // Not on the cheap wine list. 376 !(Wnd->pcls->style & CS_OWNDC) ) 377 { 378 if (!(Wnd->pcls->style & CS_CLASSDC)) 379 // The window is not POWNED or has any CLASS, so we are looking for cheap wine. 380 Flags |= DCX_CACHE; 381 else 382 { 383 if (Wnd->pcls->pdce) hDC = ((PDCE)Wnd->pcls->pdce)->hDC; 384 TRACE("We have CLASS!!\n"); 385 } 386 } 387 388 if (Wnd->style & WS_CLIPSIBLINGS) 389 { 390 Flags |= DCX_CLIPSIBLINGS; 391 } 392 393 if (Wnd->style & WS_CLIPCHILDREN && 394 !(Wnd->style & WS_MINIMIZE)) 395 { 396 Flags |= DCX_CLIPCHILDREN; 397 } 398 /* If minized with icon in the set, we are forced to be cheap! */ 399 if (Wnd->style & WS_MINIMIZE && Wnd->pcls->spicn) 400 { 401 Flags |= DCX_CACHE; 402 } 403 } 404 else 405 { 406 if (Wnd->style & WS_CLIPSIBLINGS) Flags |= DCX_CLIPSIBLINGS; 407 Flags |= DCX_CACHE; 408 } 409 } 410 411 if (Flags & DCX_WINDOW) Flags &= ~DCX_CLIPCHILDREN; 412 413 if (Flags & DCX_NOCLIPCHILDREN) 414 { 415 Flags |= DCX_CACHE; 416 Flags &= ~(DCX_PARENTCLIP | DCX_CLIPCHILDREN); 417 } 418 419 Parent = (Wnd ? Wnd->spwndParent : NULL); 420 421 if (NULL == Wnd || !(Wnd->style & WS_CHILD) || NULL == Parent) 422 { 423 Flags &= ~DCX_PARENTCLIP; 424 Flags |= DCX_CLIPSIBLINGS; 425 } 426 427 /* It seems parent clip is ignored when clipping siblings or children */ 428 if (Flags & (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN)) Flags &= ~DCX_PARENTCLIP; 429 430 if (Flags & DCX_PARENTCLIP) 431 { 432 if ((Wnd->style & WS_VISIBLE) && 433 (Parent->style & WS_VISIBLE)) 434 { 435 Flags &= ~DCX_CLIPCHILDREN; 436 if (Parent->style & WS_CLIPSIBLINGS) 437 { 438 Flags |= DCX_CLIPSIBLINGS; 439 } 440 } 441 } 442 443 // Window nz, check to see if we still own this or it is just cheap wine tonight. 444 if (!(Flags & DCX_CACHE)) 445 { 446 if ( Wnd->head.pti != GetW32ThreadInfo()) 447 Flags |= DCX_CACHE; // Ah~ Not Powned! Forced to be cheap~ 448 } 449 450 DcxFlags = Flags & DCX_CACHECOMPAREMASK; 451 452 if (Flags & DCX_CACHE) 453 { // Scan the cheap wine list for our match. 454 DCE* DceEmpty = NULL; 455 DCE* DceUnused = NULL; 456 KeEnterCriticalRegion(); 457 ListEntry = LEDce.Flink; 458 while (ListEntry != &LEDce) 459 { 460 Dce = CONTAINING_RECORD(ListEntry, DCE, List); 461 ListEntry = ListEntry->Flink; 462 // 463 // The way I understand this, you can have more than one DC per window. 464 // Only one Owned if one was requested and saved and one Cached. 465 // 466 if ((Dce->DCXFlags & (DCX_CACHE | DCX_DCEBUSY)) == DCX_CACHE) 467 { 468 DceUnused = Dce; 469 if (Dce->DCXFlags & DCX_DCEEMPTY) 470 { 471 DceEmpty = Dce; 472 } 473 else if (Dce->hwndCurrent == (Wnd ? UserHMGetHandle(Wnd) : NULL) && 474 ((Dce->DCXFlags & DCX_CACHECOMPAREMASK) == DcxFlags)) 475 { 476 UpdateClipOrigin = TRUE; 477 break; 478 } 479 } 480 Dce = NULL; // Loop issue? 481 } 482 KeLeaveCriticalRegion(); 483 484 Dce = (DceEmpty == NULL) ? DceUnused : DceEmpty; 485 486 if (Dce == NULL) 487 { 488 Dce = DceAllocDCE(NULL, DCE_CACHE_DC); 489 } 490 if (Dce == NULL) return NULL; 491 492 Dce->hwndCurrent = (Wnd ? UserHMGetHandle(Wnd) : NULL); 493 Dce->pwndOrg = Dce->pwndClip = Wnd; 494 } 495 else // If we are here, we are POWNED or having CLASS. 496 { 497 KeEnterCriticalRegion(); 498 ListEntry = LEDce.Flink; 499 while (ListEntry != &LEDce) 500 { 501 Dce = CONTAINING_RECORD(ListEntry, DCE, List); 502 ListEntry = ListEntry->Flink; 503 504 // Skip Cache DCE entries. 505 if (!(Dce->DCXFlags & DCX_CACHE)) 506 { 507 // Check for Window handle than HDC match for CLASS. 508 if (Dce->hwndCurrent == UserHMGetHandle(Wnd)) 509 { 510 bUpdateVisRgn = FALSE; 511 break; 512 } 513 else if (Dce->hDC == hDC) break; 514 } 515 Dce = NULL; // Loop issue? 516 } 517 KeLeaveCriticalRegion(); 518 519 if (Dce == NULL) 520 { 521 return(NULL); 522 } 523 524 if ( (Flags & (DCX_INTERSECTRGN|DCX_EXCLUDERGN)) && 525 (Dce->DCXFlags & (DCX_INTERSECTRGN|DCX_EXCLUDERGN)) ) 526 { 527 DceDeleteClipRgn(Dce); 528 } 529 } 530 // First time use hax, need to use DceAllocDCE during window display init. 531 if (NULL == Dce) 532 { 533 return(NULL); 534 } 535 536 if (!GreIsHandleValid(Dce->hDC)) 537 { 538 ERR("FIXME: Got DCE with invalid hDC! %p\n", Dce->hDC); 539 Dce->hDC = DceCreateDisplayDC(); 540 /* FIXME: Handle error */ 541 } 542 543 Dce->DCXFlags = Flags | DCX_DCEBUSY; 544 545 /* 546 * Bump it up! This prevents the random errors in wine dce tests and with 547 * proper bits set in DCX_CACHECOMPAREMASK. 548 * Reference: 549 * https://reactos.org/archives/public/ros-dev/2008-July/010498.html 550 * https://reactos.org/archives/public/ros-dev/2008-July/010499.html 551 */ 552 RemoveEntryList(&Dce->List); 553 InsertHeadList(&LEDce, &Dce->List); 554 555 /* Introduced in rev 6691 and modified later. */ 556 if ( (Flags & DCX_INTERSECTUPDATE) && !ClipRegion ) 557 { 558 Flags |= DCX_INTERSECTRGN | DCX_KEEPCLIPRGN; 559 Dce->DCXFlags |= DCX_INTERSECTRGN | DCX_KEEPCLIPRGN; 560 ClipRegion = Wnd->hrgnUpdate; 561 bUpdateVisRgn = TRUE; 562 } 563 564 if (ClipRegion == HRGN_WINDOW) 565 { 566 if (!(Flags & DCX_WINDOW)) 567 { 568 Dce->hrgnClip = NtGdiCreateRectRgn( 569 Wnd->rcClient.left, 570 Wnd->rcClient.top, 571 Wnd->rcClient.right, 572 Wnd->rcClient.bottom); 573 } 574 else 575 { 576 Dce->hrgnClip = NtGdiCreateRectRgn( 577 Wnd->rcWindow.left, 578 Wnd->rcWindow.top, 579 Wnd->rcWindow.right, 580 Wnd->rcWindow.bottom); 581 } 582 Dce->DCXFlags &= ~DCX_KEEPCLIPRGN; 583 bUpdateVisRgn = TRUE; 584 } 585 else if (ClipRegion != NULL) 586 { 587 if (Dce->hrgnClip != NULL) 588 { 589 ERR("Should not be called!!\n"); 590 GreDeleteObject(Dce->hrgnClip); 591 Dce->hrgnClip = NULL; 592 } 593 Dce->hrgnClip = ClipRegion; 594 bUpdateVisRgn = TRUE; 595 } 596 597 if (IntGdiSetHookFlags(Dce->hDC, DCHF_VALIDATEVISRGN)) bUpdateVisRgn = TRUE; 598 599 DceSetDrawable(Wnd, Dce->hDC, Flags, UpdateClipOrigin); 600 601 if (bUpdateVisRgn) DceUpdateVisRgn(Dce, Wnd, Flags); 602 603 if (Dce->DCXFlags & DCX_CACHE) 604 { 605 TRACE("ENTER!!!!!! DCX_CACHE!!!!!! hDC-> %p\n", Dce->hDC); 606 // Need to set ownership so Sync dcattr will work. 607 GreSetDCOwner(Dce->hDC, GDI_OBJ_HMGR_POWNED); 608 Dce->ptiOwner = GetW32ThreadInfo(); // Set the temp owning 609 } 610 611 if ( Wnd && 612 Wnd->ExStyle & WS_EX_LAYOUTRTL && 613 !(Flags & DCX_KEEPLAYOUT) ) 614 { 615 NtGdiSetLayout(Dce->hDC, -1, LAYOUT_RTL); 616 } 617 618 if (Dce->DCXFlags & DCX_PROCESSOWNED) 619 { 620 ppi = PsGetCurrentProcessWin32Process(); 621 ppi->W32PF_flags |= W32PF_OWNDCCLEANUP; 622 Dce->ptiOwner = NULL; 623 Dce->ppiOwner = ppi; 624 } 625 626 return(Dce->hDC); 627 } 628 629 /*********************************************************************** 630 * DceFreeDCE 631 */ 632 void FASTCALL 633 DceFreeDCE(PDCE pdce, BOOLEAN Force) 634 { 635 BOOL Hit = FALSE; 636 637 ASSERT(pdce != NULL); 638 if (NULL == pdce) return; 639 640 pdce->DCXFlags |= DCX_INDESTROY; 641 642 if (Force && 643 GreGetObjectOwner(pdce->hDC) != GDI_OBJ_HMGR_POWNED) 644 { 645 TRACE("Change ownership for DCE! -> %p\n" , pdce); 646 // NOTE: Windows sets W32PF_OWNDCCLEANUP and moves on. 647 if (GreIsHandleValid(pdce->hDC)) 648 { 649 GreSetDCOwner(pdce->hDC, GDI_OBJ_HMGR_POWNED); 650 } 651 else 652 { 653 ERR("Attempted to change ownership of an DCEhDC %p currently being destroyed!!!\n", 654 pdce->hDC); 655 Hit = TRUE; 656 } 657 } 658 else 659 { 660 if (GreGetObjectOwner(pdce->hDC) == GDI_OBJ_HMGR_PUBLIC) 661 GreSetDCOwner(pdce->hDC, GDI_OBJ_HMGR_POWNED); 662 } 663 664 if (!Hit) IntGdiDeleteDC(pdce->hDC, TRUE); 665 666 if (pdce->hrgnClip && !(pdce->DCXFlags & DCX_KEEPCLIPRGN)) 667 { 668 GreDeleteObject(pdce->hrgnClip); 669 pdce->hrgnClip = NULL; 670 } 671 672 RemoveEntryList(&pdce->List); 673 674 ExFreePoolWithTag(pdce, USERTAG_DCE); 675 676 DCECount--; 677 TRACE("Freed DCE's! %d \n", DCECount); 678 } 679 680 /*********************************************************************** 681 * DceFreeWindowDCE 682 * 683 * Remove owned DCE and reset unreleased cache DCEs. 684 */ 685 void FASTCALL 686 DceFreeWindowDCE(PWND Window) 687 { 688 PDCE pDCE; 689 PLIST_ENTRY ListEntry; 690 691 if (DCECount <= 0) 692 { 693 ERR("FreeWindowDCE No Entry! %d\n",DCECount); 694 return; 695 } 696 697 ListEntry = LEDce.Flink; 698 while (ListEntry != &LEDce) 699 { 700 pDCE = CONTAINING_RECORD(ListEntry, DCE, List); 701 ListEntry = ListEntry->Flink; 702 if ( pDCE->hwndCurrent == UserHMGetHandle(Window) && 703 !(pDCE->DCXFlags & DCX_DCEEMPTY) ) 704 { 705 if (!(pDCE->DCXFlags & DCX_CACHE)) /* Owned or Class DCE */ 706 { 707 if (Window->pcls->style & CS_CLASSDC) /* Test Class first */ 708 { 709 if (pDCE->DCXFlags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN)) /* Class DCE */ 710 DceDeleteClipRgn(pDCE); 711 // Update and reset Vis Rgn and clear the dirty bit. 712 // Should release VisRgn than reset it to default. 713 DceUpdateVisRgn(pDCE, Window, pDCE->DCXFlags); 714 pDCE->DCXFlags = DCX_DCEEMPTY|DCX_CACHE; 715 pDCE->hwndCurrent = 0; 716 pDCE->pwndOrg = pDCE->pwndClip = NULL; 717 718 TRACE("POWNED DCE going Cheap!! DCX_CACHE!! hDC-> %p \n", 719 pDCE->hDC); 720 if (!GreSetDCOwner( pDCE->hDC, GDI_OBJ_HMGR_NONE)) 721 { 722 ERR("Fail Owner Switch hDC-> %p \n", pDCE->hDC); 723 break; 724 } 725 /* Do not change owner so thread can clean up! */ 726 } 727 else if (Window->pcls->style & CS_OWNDC) /* Owned DCE */ 728 { 729 DceFreeDCE(pDCE, FALSE); 730 continue; 731 } 732 else 733 { 734 ERR("Not POWNED or CLASSDC hwndCurrent -> %p \n", 735 pDCE->hwndCurrent); 736 // ASSERT(FALSE); /* bug 5320 */ 737 } 738 } 739 else 740 { 741 if (pDCE->DCXFlags & DCX_DCEBUSY) /* Shared cache DCE */ 742 { 743 /* FIXME: AFAICS we are doing the right thing here so 744 * this should be a TRACE. But this is best left as an ERR 745 * because the 'application error' is likely to come from 746 * another part of Wine (i.e. it's our fault after all). 747 * We should change this to TRACE when ReactOS is more stable 748 * (for 1.0?). 749 */ 750 ERR("[%p] GetDC() without ReleaseDC()!\n", UserHMGetHandle(Window)); 751 DceReleaseDC(pDCE, FALSE); 752 } 753 pDCE->DCXFlags |= DCX_DCEEMPTY; 754 pDCE->hwndCurrent = 0; 755 pDCE->pwndOrg = pDCE->pwndClip = NULL; 756 } 757 } 758 } 759 } 760 761 void FASTCALL 762 DceFreeClassDCE(PDCE pdceClass) 763 { 764 PDCE pDCE; 765 PLIST_ENTRY ListEntry; 766 767 ListEntry = LEDce.Flink; 768 while (ListEntry != &LEDce) 769 { 770 pDCE = CONTAINING_RECORD(ListEntry, DCE, List); 771 ListEntry = ListEntry->Flink; 772 if (pDCE == pdceClass) 773 { 774 DceFreeDCE(pDCE, TRUE); // Might have gone cheap! 775 } 776 } 777 } 778 779 void FASTCALL 780 DceFreeThreadDCE(PTHREADINFO pti) 781 { 782 PDCE pDCE; 783 PLIST_ENTRY ListEntry; 784 785 ListEntry = LEDce.Flink; 786 while (ListEntry != &LEDce) 787 { 788 pDCE = CONTAINING_RECORD(ListEntry, DCE, List); 789 ListEntry = ListEntry->Flink; 790 if (pDCE->ptiOwner == pti) 791 { 792 if (pDCE->DCXFlags & DCX_CACHE) 793 { 794 DceFreeDCE(pDCE, TRUE); 795 } 796 } 797 } 798 } 799 800 VOID FASTCALL 801 DceEmptyCache(VOID) 802 { 803 PDCE pDCE; 804 PLIST_ENTRY ListEntry; 805 806 ListEntry = LEDce.Flink; 807 while (ListEntry != &LEDce) 808 { 809 pDCE = CONTAINING_RECORD(ListEntry, DCE, List); 810 ListEntry = ListEntry->Flink; 811 DceFreeDCE(pDCE, TRUE); 812 } 813 } 814 815 VOID FASTCALL 816 DceResetActiveDCEs(PWND Window) 817 { 818 DCE *pDCE; 819 PDC dc; 820 PWND CurrentWindow; 821 INT DeltaX; 822 INT DeltaY; 823 PLIST_ENTRY ListEntry; 824 825 if (NULL == Window) 826 { 827 return; 828 } 829 830 ListEntry = LEDce.Flink; 831 while (ListEntry != &LEDce) 832 { 833 pDCE = CONTAINING_RECORD(ListEntry, DCE, List); 834 ListEntry = ListEntry->Flink; 835 if (0 == (pDCE->DCXFlags & (DCX_DCEEMPTY|DCX_INDESTROY))) 836 { 837 if (UserHMGetHandle(Window) == pDCE->hwndCurrent) 838 { 839 CurrentWindow = Window; 840 } 841 else 842 { 843 if (!pDCE->hwndCurrent) 844 CurrentWindow = NULL; 845 else 846 CurrentWindow = UserGetWindowObject(pDCE->hwndCurrent); 847 if (NULL == CurrentWindow) 848 { 849 continue; 850 } 851 } 852 853 if (!GreIsHandleValid(pDCE->hDC) || 854 (dc = DC_LockDc(pDCE->hDC)) == NULL) 855 { 856 continue; 857 } 858 if (Window == CurrentWindow || IntIsChildWindow(Window, CurrentWindow)) 859 { 860 if (pDCE->DCXFlags & DCX_WINDOW) 861 { 862 DeltaX = CurrentWindow->rcWindow.left - dc->ptlDCOrig.x; 863 DeltaY = CurrentWindow->rcWindow.top - dc->ptlDCOrig.y; 864 dc->ptlDCOrig.x = CurrentWindow->rcWindow.left; 865 dc->ptlDCOrig.y = CurrentWindow->rcWindow.top; 866 } 867 else 868 { 869 DeltaX = CurrentWindow->rcClient.left - dc->ptlDCOrig.x; 870 DeltaY = CurrentWindow->rcClient.top - dc->ptlDCOrig.y; 871 dc->ptlDCOrig.x = CurrentWindow->rcClient.left; 872 dc->ptlDCOrig.y = CurrentWindow->rcClient.top; 873 } 874 875 if (NULL != dc->dclevel.prgnClip) 876 { 877 REGION_bOffsetRgn(dc->dclevel.prgnClip, DeltaX, DeltaY); 878 dc->fs |= DC_DIRTY_RAO; 879 } 880 if (NULL != pDCE->hrgnClip) 881 { 882 NtGdiOffsetRgn(pDCE->hrgnClip, DeltaX, DeltaY); 883 } 884 } 885 DC_UnlockDc(dc); 886 887 DceUpdateVisRgn(pDCE, CurrentWindow, pDCE->DCXFlags); 888 IntGdiSetHookFlags(pDCE->hDC, DCHF_VALIDATEVISRGN); 889 } 890 } 891 } 892 893 HWND FASTCALL 894 IntWindowFromDC(HDC hDc) 895 { 896 DCE *Dce; 897 PLIST_ENTRY ListEntry; 898 HWND Ret = NULL; 899 900 ListEntry = LEDce.Flink; 901 while (ListEntry != &LEDce) 902 { 903 Dce = CONTAINING_RECORD(ListEntry, DCE, List); 904 ListEntry = ListEntry->Flink; 905 if (Dce->hDC == hDc) 906 { 907 if (Dce->DCXFlags & DCX_INDESTROY) 908 Ret = NULL; 909 else 910 Ret = Dce->hwndCurrent; 911 break; 912 } 913 } 914 return Ret; 915 } 916 917 INT FASTCALL 918 UserReleaseDC(PWND Window, HDC hDc, BOOL EndPaint) 919 { 920 PDCE dce; 921 PLIST_ENTRY ListEntry; 922 INT nRet = 0; 923 BOOL Hit = FALSE; 924 925 TRACE("%p %p\n", Window, hDc); 926 ListEntry = LEDce.Flink; 927 while (ListEntry != &LEDce) 928 { 929 dce = CONTAINING_RECORD(ListEntry, DCE, List); 930 ListEntry = ListEntry->Flink; 931 if (dce->hDC == hDc) 932 { 933 Hit = TRUE; 934 break; 935 } 936 } 937 938 if ( Hit && (dce->DCXFlags & DCX_DCEBUSY)) 939 { 940 nRet = DceReleaseDC(dce, EndPaint); 941 } 942 943 return nRet; 944 } 945 946 HDC FASTCALL 947 UserGetWindowDC(PWND Wnd) 948 { 949 return UserGetDCEx(Wnd, 0, DCX_USESTYLE | DCX_WINDOW); 950 } 951 952 HWND FASTCALL 953 UserGethWnd( HDC hdc, PWNDOBJ *pwndo) 954 { 955 EWNDOBJ* Clip; 956 PWND Wnd; 957 HWND hWnd; 958 959 hWnd = IntWindowFromDC(hdc); 960 961 if (hWnd && (Wnd = UserGetWindowObject(hWnd))) 962 { 963 Clip = (EWNDOBJ*)UserGetProp(Wnd, AtomWndObj, TRUE); 964 965 if ( Clip && Clip->Hwnd == hWnd ) 966 { 967 if (pwndo) *pwndo = (PWNDOBJ)Clip; 968 } 969 } 970 return hWnd; 971 } 972 973 HDC APIENTRY 974 NtUserGetDCEx(HWND hWnd OPTIONAL, HANDLE ClipRegion, ULONG Flags) 975 { 976 PWND Wnd=NULL; 977 HDC Ret = NULL; 978 979 TRACE("Enter NtUserGetDCEx: hWnd %p, ClipRegion %p, Flags %x.\n", 980 hWnd, ClipRegion, Flags); 981 UserEnterExclusive(); 982 983 if (hWnd && !(Wnd = UserGetWindowObject(hWnd))) 984 { 985 goto Exit; // Return NULL 986 } 987 Ret = UserGetDCEx(Wnd, ClipRegion, Flags); 988 989 Exit: 990 TRACE("Leave NtUserGetDCEx, ret=%p\n", Ret); 991 UserLeave(); 992 return Ret; 993 } 994 995 /* 996 * NtUserGetWindowDC 997 * 998 * The NtUserGetWindowDC function retrieves the device context (DC) for the 999 * entire window, including title bar, menus, and scroll bars. A window device 1000 * context permits painting anywhere in a window, because the origin of the 1001 * device context is the upper-left corner of the window instead of the client 1002 * area. 1003 * 1004 * Status 1005 * @implemented 1006 */ 1007 HDC APIENTRY 1008 NtUserGetWindowDC(HWND hWnd) 1009 { 1010 return NtUserGetDCEx(hWnd, 0, DCX_USESTYLE | DCX_WINDOW); 1011 } 1012 1013 HDC APIENTRY 1014 NtUserGetDC(HWND hWnd) 1015 { 1016 TRACE("NtUGetDC -> %p:%x\n", hWnd, !hWnd ? DCX_CACHE | DCX_WINDOW : DCX_USESTYLE); 1017 1018 return NtUserGetDCEx(hWnd, NULL, NULL == hWnd ? DCX_CACHE | DCX_WINDOW : DCX_USESTYLE); 1019 } 1020 1021 /*! 1022 * Select logical palette into device context. 1023 * \param hDC handle to the device context 1024 * \param hpal handle to the palette 1025 * \param ForceBackground If this value is FALSE the logical palette will be copied to the device palette only when the application 1026 * is in the foreground. If this value is TRUE then map the colors in the logical palette to the device 1027 * palette colors in the best way. 1028 * \return old palette 1029 * 1030 * \todo implement ForceBackground == TRUE 1031 */ 1032 HPALETTE 1033 APIENTRY 1034 NtUserSelectPalette(HDC hDC, 1035 HPALETTE hpal, 1036 BOOL ForceBackground) 1037 { 1038 HPALETTE oldPal; 1039 UserEnterExclusive(); 1040 // Implement window checks 1041 oldPal = GdiSelectPalette( hDC, hpal, ForceBackground); 1042 UserLeave(); 1043 return oldPal; 1044 } 1045 1046 /* EOF */ 1047