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