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