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