[WIN32K: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: 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 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 if (Wnd->style & WS_MINIMIZE && Wnd->pcls->spicn)
407 {
408 Flags |= DCX_CACHE;
409 }
410 }
411 else
412 {
413 if (Wnd->style & WS_CLIPSIBLINGS) Flags |= DCX_CLIPSIBLINGS;
414 Flags |= DCX_CACHE;
415 }
416 }
417
418 if (Flags & DCX_WINDOW) Flags &= ~DCX_CLIPCHILDREN;
419
420 if (Flags & DCX_NOCLIPCHILDREN)
421 {
422 Flags |= DCX_CACHE;
423 Flags &= ~(DCX_PARENTCLIP | DCX_CLIPCHILDREN);
424 }
425
426 Parent = (Wnd ? Wnd->spwndParent : NULL);
427
428 if (NULL == Wnd || !(Wnd->style & WS_CHILD) || NULL == Parent)
429 {
430 Flags &= ~DCX_PARENTCLIP;
431 Flags |= DCX_CLIPSIBLINGS;
432 }
433
434 /* It seems parent clip is ignored when clipping siblings or children */
435 if (Flags & (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN)) Flags &= ~DCX_PARENTCLIP;
436
437 if (Flags & DCX_PARENTCLIP)
438 {
439 if ((Wnd->style & WS_VISIBLE) &&
440 (Parent->style & WS_VISIBLE))
441 {
442 Flags &= ~DCX_CLIPCHILDREN;
443 if (Parent->style & WS_CLIPSIBLINGS)
444 {
445 Flags |= DCX_CLIPSIBLINGS;
446 }
447 }
448 }
449
450 // Window nz, check to see if we still own this or it is just cheap wine tonight.
451 if (!(Flags & DCX_CACHE))
452 {
453 if ( Wnd->head.pti != GetW32ThreadInfo())
454 Flags |= DCX_CACHE; // Ah~ Not Powned! Forced to be cheap~
455 }
456
457 DcxFlags = Flags & DCX_CACHECOMPAREMASK;
458
459 if (Flags & DCX_CACHE)
460 { // Scan the cheap wine list for our match.
461 DCE* DceEmpty = NULL;
462 DCE* DceUnused = NULL;
463 KeEnterCriticalRegion();
464 ListEntry = LEDce.Flink;
465 while (ListEntry != &LEDce)
466 {
467 Dce = CONTAINING_RECORD(ListEntry, DCE, List);
468 ListEntry = ListEntry->Flink;
469 //
470 // The way I understand this, you can have more than one DC per window.
471 // Only one Owned if one was requested and saved and one Cached.
472 //
473 if ((Dce->DCXFlags & (DCX_CACHE | DCX_DCEBUSY)) == DCX_CACHE)
474 {
475 DceUnused = Dce;
476 if (Dce->DCXFlags & DCX_DCEEMPTY)
477 {
478 DceEmpty = Dce;
479 }
480 else if (Dce->hwndCurrent == (Wnd ? Wnd->head.h : NULL) &&
481 ((Dce->DCXFlags & DCX_CACHECOMPAREMASK) == DcxFlags))
482 {
483 UpdateClipOrigin = TRUE;
484 break;
485 }
486 }
487 Dce = NULL; // Loop issue?
488 }
489 KeLeaveCriticalRegion();
490
491 Dce = (DceEmpty == NULL) ? DceUnused : DceEmpty;
492
493 if (Dce == NULL)
494 {
495 Dce = DceAllocDCE(NULL, DCE_CACHE_DC);
496 }
497 if (Dce == NULL) return NULL;
498
499 Dce->hwndCurrent = (Wnd ? Wnd->head.h : NULL);
500 Dce->pwndOrg = Dce->pwndClip = Wnd;
501 }
502 else // If we are here, we are POWNED or having CLASS.
503 {
504 KeEnterCriticalRegion();
505 ListEntry = LEDce.Flink;
506 while (ListEntry != &LEDce)
507 {
508 Dce = CONTAINING_RECORD(ListEntry, DCE, List);
509 ListEntry = ListEntry->Flink;
510
511 // Skip Cache DCE entries.
512 if (!(Dce->DCXFlags & DCX_CACHE))
513 {
514 // Check for Window handle than HDC match for CLASS.
515 if (Dce->hwndCurrent == Wnd->head.h)
516 {
517 bUpdateVisRgn = FALSE;
518 break;
519 }
520 else if (Dce->hDC == hDC) break;
521 }
522 Dce = NULL; // Loop issue?
523 }
524 KeLeaveCriticalRegion();
525
526 if (Dce == NULL)
527 {
528 return(NULL);
529 }
530
531 if ( (Flags & (DCX_INTERSECTRGN|DCX_EXCLUDERGN)) &&
532 (Dce->DCXFlags & (DCX_INTERSECTRGN|DCX_EXCLUDERGN)) )
533 {
534 DceDeleteClipRgn(Dce);
535 }
536 }
537 // First time use hax, need to use DceAllocDCE during window display init.
538 if (NULL == Dce)
539 {
540 return(NULL);
541 }
542
543 if (!GreIsHandleValid(Dce->hDC))
544 {
545 ERR("FIXME: Got DCE with invalid hDC! %p\n", Dce->hDC);
546 Dce->hDC = DceCreateDisplayDC();
547 /* FIXME: Handle error */
548 }
549
550 Dce->DCXFlags = Flags | DCX_DCEBUSY;
551
552 /*
553 * Bump it up! This prevents the random errors in wine dce tests and with
554 * proper bits set in DCX_CACHECOMPAREMASK.
555 * Reference:
556 * http://www.reactos.org/archives/public/ros-dev/2008-July/010498.html
557 * http://www.reactos.org/archives/public/ros-dev/2008-July/010499.html
558 */
559 RemoveEntryList(&Dce->List);
560 InsertHeadList(&LEDce, &Dce->List);
561
562 /* Introduced in rev 6691 and modified later. */
563 if ( (Flags & DCX_INTERSECTUPDATE) && !ClipRegion )
564 {
565 Flags |= DCX_INTERSECTRGN | DCX_KEEPCLIPRGN;
566 Dce->DCXFlags |= DCX_INTERSECTRGN | DCX_KEEPCLIPRGN;
567 ClipRegion = Wnd->hrgnUpdate;
568 bUpdateVisRgn = TRUE;
569 }
570
571 if (ClipRegion == HRGN_WINDOW)
572 {
573 if (!(Flags & DCX_WINDOW))
574 {
575 Dce->hrgnClip = NtGdiCreateRectRgn(
576 Wnd->rcClient.left,
577 Wnd->rcClient.top,
578 Wnd->rcClient.right,
579 Wnd->rcClient.bottom);
580 }
581 else
582 {
583 Dce->hrgnClip = NtGdiCreateRectRgn(
584 Wnd->rcWindow.left,
585 Wnd->rcWindow.top,
586 Wnd->rcWindow.right,
587 Wnd->rcWindow.bottom);
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 void FASTCALL
640 DceFreeDCE(PDCE pdce, BOOLEAN Force)
641 {
642 BOOL Hit = FALSE;
643
644 ASSERT(pdce != NULL);
645 if (NULL == pdce) return;
646
647 pdce->DCXFlags |= DCX_INDESTROY;
648
649 if (Force &&
650 GreGetObjectOwner(pdce->hDC) != GDI_OBJ_HMGR_POWNED)
651 {
652 TRACE("Change ownership for DCE! -> %p\n" , pdce);
653 // NOTE: Windows sets W32PF_OWNDCCLEANUP and moves on.
654 if (GreIsHandleValid(pdce->hDC))
655 {
656 GreSetDCOwner(pdce->hDC, GDI_OBJ_HMGR_POWNED);
657 }
658 else
659 {
660 ERR("Attempted to change ownership of an DCEhDC %p currently being destroyed!!!\n",
661 pdce->hDC);
662 Hit = TRUE;
663 }
664 }
665 else
666 {
667 if (GreGetObjectOwner(pdce->hDC) == GDI_OBJ_HMGR_PUBLIC)
668 GreSetDCOwner(pdce->hDC, GDI_OBJ_HMGR_POWNED);
669 }
670
671 if (!Hit) IntGdiDeleteDC(pdce->hDC, TRUE);
672
673 if (pdce->hrgnClip && !(pdce->DCXFlags & DCX_KEEPCLIPRGN))
674 {
675 GreDeleteObject(pdce->hrgnClip);
676 pdce->hrgnClip = NULL;
677 }
678
679 RemoveEntryList(&pdce->List);
680
681 ExFreePoolWithTag(pdce, USERTAG_DCE);
682
683 DCECount--;
684 TRACE("Freed DCE's! %d \n", DCECount);
685 }
686
687 /***********************************************************************
688 * DceFreeWindowDCE
689 *
690 * Remove owned DCE and reset unreleased cache DCEs.
691 */
692 void FASTCALL
693 DceFreeWindowDCE(PWND Window)
694 {
695 PDCE pDCE;
696 PLIST_ENTRY ListEntry;
697
698 if (DCECount <= 0)
699 {
700 ERR("FreeWindowDCE No Entry! %d\n",DCECount);
701 return;
702 }
703
704 ListEntry = LEDce.Flink;
705 while (ListEntry != &LEDce)
706 {
707 pDCE = CONTAINING_RECORD(ListEntry, DCE, List);
708 ListEntry = ListEntry->Flink;
709 if ( pDCE->hwndCurrent == Window->head.h &&
710 !(pDCE->DCXFlags & DCX_DCEEMPTY) )
711 {
712 if (!(pDCE->DCXFlags & DCX_CACHE)) /* Owned or Class DCE */
713 {
714 if (Window->pcls->style & CS_CLASSDC) /* Test Class first */
715 {
716 if (pDCE->DCXFlags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN)) /* Class DCE */
717 DceDeleteClipRgn(pDCE);
718 // Update and reset Vis Rgn and clear the dirty bit.
719 // Should release VisRgn than reset it to default.
720 DceUpdateVisRgn(pDCE, Window, pDCE->DCXFlags);
721 pDCE->DCXFlags = DCX_DCEEMPTY|DCX_CACHE;
722 pDCE->hwndCurrent = 0;
723 pDCE->pwndOrg = pDCE->pwndClip = NULL;
724
725 TRACE("POWNED DCE going Cheap!! DCX_CACHE!! hDC-> %p \n",
726 pDCE->hDC);
727 if (!GreSetDCOwner( pDCE->hDC, GDI_OBJ_HMGR_NONE))
728 {
729 ERR("Fail Owner Switch hDC-> %p \n", pDCE->hDC);
730 break;
731 }
732 /* Do not change owner so thread can clean up! */
733 }
734 else if (Window->pcls->style & CS_OWNDC) /* Owned DCE */
735 {
736 DceFreeDCE(pDCE, FALSE);
737 continue;
738 }
739 else
740 {
741 ERR("Not POWNED or CLASSDC hwndCurrent -> %p \n",
742 pDCE->hwndCurrent);
743 // ASSERT(FALSE); /* bug 5320 */
744 }
745 }
746 else
747 {
748 if (pDCE->DCXFlags & DCX_DCEBUSY) /* Shared cache DCE */
749 {
750 /* FIXME: AFAICS we are doing the right thing here so
751 * this should be a TRACE. But this is best left as an ERR
752 * because the 'application error' is likely to come from
753 * another part of Wine (i.e. it's our fault after all).
754 * We should change this to TRACE when ReactOS is more stable
755 * (for 1.0?).
756 */
757 ERR("[%p] GetDC() without ReleaseDC()!\n", Window->head.h);
758 DceReleaseDC(pDCE, FALSE);
759 }
760 pDCE->DCXFlags |= DCX_DCEEMPTY;
761 pDCE->hwndCurrent = 0;
762 pDCE->pwndOrg = pDCE->pwndClip = NULL;
763 }
764 }
765 }
766 }
767
768 void FASTCALL
769 DceFreeClassDCE(PDCE pdceClass)
770 {
771 PDCE pDCE;
772 PLIST_ENTRY ListEntry;
773
774 ListEntry = LEDce.Flink;
775 while (ListEntry != &LEDce)
776 {
777 pDCE = CONTAINING_RECORD(ListEntry, DCE, List);
778 ListEntry = ListEntry->Flink;
779 if (pDCE == pdceClass)
780 {
781 DceFreeDCE(pDCE, TRUE); // Might have gone cheap!
782 }
783 }
784 }
785
786 void FASTCALL
787 DceFreeThreadDCE(PTHREADINFO pti)
788 {
789 PDCE pDCE;
790 PLIST_ENTRY ListEntry;
791
792 ListEntry = LEDce.Flink;
793 while (ListEntry != &LEDce)
794 {
795 pDCE = CONTAINING_RECORD(ListEntry, DCE, List);
796 ListEntry = ListEntry->Flink;
797 if (pDCE->ptiOwner == pti)
798 {
799 if (pDCE->DCXFlags & DCX_CACHE)
800 {
801 DceFreeDCE(pDCE, TRUE);
802 }
803 }
804 }
805 }
806
807 VOID FASTCALL
808 DceEmptyCache(VOID)
809 {
810 PDCE pDCE;
811 PLIST_ENTRY ListEntry;
812
813 ListEntry = LEDce.Flink;
814 while (ListEntry != &LEDce)
815 {
816 pDCE = CONTAINING_RECORD(ListEntry, DCE, List);
817 ListEntry = ListEntry->Flink;
818 DceFreeDCE(pDCE, TRUE);
819 }
820 }
821
822 VOID FASTCALL
823 DceResetActiveDCEs(PWND Window)
824 {
825 DCE *pDCE;
826 PDC dc;
827 PWND CurrentWindow;
828 INT DeltaX;
829 INT DeltaY;
830 PLIST_ENTRY ListEntry;
831
832 if (NULL == Window)
833 {
834 return;
835 }
836
837 ListEntry = LEDce.Flink;
838 while (ListEntry != &LEDce)
839 {
840 pDCE = CONTAINING_RECORD(ListEntry, DCE, List);
841 ListEntry = ListEntry->Flink;
842 if (0 == (pDCE->DCXFlags & (DCX_DCEEMPTY|DCX_INDESTROY)))
843 {
844 if (Window->head.h == pDCE->hwndCurrent)
845 {
846 CurrentWindow = Window;
847 }
848 else
849 {
850 if (!pDCE->hwndCurrent)
851 CurrentWindow = NULL;
852 else
853 CurrentWindow = UserGetWindowObject(pDCE->hwndCurrent);
854 if (NULL == CurrentWindow)
855 {
856 continue;
857 }
858 }
859
860 if (!GreIsHandleValid(pDCE->hDC) ||
861 (dc = DC_LockDc(pDCE->hDC)) == NULL)
862 {
863 continue;
864 }
865 if (Window == CurrentWindow || IntIsChildWindow(Window, CurrentWindow))
866 {
867 if (pDCE->DCXFlags & DCX_WINDOW)
868 {
869 DeltaX = CurrentWindow->rcWindow.left - dc->ptlDCOrig.x;
870 DeltaY = CurrentWindow->rcWindow.top - dc->ptlDCOrig.y;
871 dc->ptlDCOrig.x = CurrentWindow->rcWindow.left;
872 dc->ptlDCOrig.y = CurrentWindow->rcWindow.top;
873 }
874 else
875 {
876 DeltaX = CurrentWindow->rcClient.left - dc->ptlDCOrig.x;
877 DeltaY = CurrentWindow->rcClient.top - dc->ptlDCOrig.y;
878 dc->ptlDCOrig.x = CurrentWindow->rcClient.left;
879 dc->ptlDCOrig.y = CurrentWindow->rcClient.top;
880 }
881
882 if (NULL != dc->dclevel.prgnClip)
883 {
884 REGION_bOffsetRgn(dc->dclevel.prgnClip, DeltaX, DeltaY);
885 dc->fs |= DC_FLAG_DIRTY_RAO;
886 }
887 if (NULL != pDCE->hrgnClip)
888 {
889 NtGdiOffsetRgn(pDCE->hrgnClip, DeltaX, DeltaY);
890 }
891 }
892 DC_UnlockDc(dc);
893
894 DceUpdateVisRgn(pDCE, CurrentWindow, pDCE->DCXFlags);
895 IntGdiSetHookFlags(pDCE->hDC, DCHF_VALIDATEVISRGN);
896 }
897 }
898 }
899
900 HWND FASTCALL
901 IntWindowFromDC(HDC hDc)
902 {
903 DCE *Dce;
904 PLIST_ENTRY ListEntry;
905 HWND Ret = NULL;
906
907 ListEntry = LEDce.Flink;
908 while (ListEntry != &LEDce)
909 {
910 Dce = CONTAINING_RECORD(ListEntry, DCE, List);
911 ListEntry = ListEntry->Flink;
912 if (Dce->hDC == hDc)
913 {
914 if (Dce->DCXFlags & DCX_INDESTROY)
915 Ret = NULL;
916 else
917 Ret = Dce->hwndCurrent;
918 break;
919 }
920 }
921 return Ret;
922 }
923
924 INT FASTCALL
925 UserReleaseDC(PWND Window, HDC hDc, BOOL EndPaint)
926 {
927 PDCE dce;
928 PLIST_ENTRY ListEntry;
929 INT nRet = 0;
930 BOOL Hit = FALSE;
931
932 TRACE("%p %p\n", Window, hDc);
933 ListEntry = LEDce.Flink;
934 while (ListEntry != &LEDce)
935 {
936 dce = CONTAINING_RECORD(ListEntry, DCE, List);
937 ListEntry = ListEntry->Flink;
938 if (dce->hDC == hDc)
939 {
940 Hit = TRUE;
941 break;
942 }
943 }
944
945 if ( Hit && (dce->DCXFlags & DCX_DCEBUSY))
946 {
947 nRet = DceReleaseDC(dce, EndPaint);
948 }
949
950 return nRet;
951 }
952
953 HDC FASTCALL
954 UserGetWindowDC(PWND Wnd)
955 {
956 return UserGetDCEx(Wnd, 0, DCX_USESTYLE | DCX_WINDOW);
957 }
958
959 HWND FASTCALL
960 UserGethWnd( HDC hdc, PWNDOBJ *pwndo)
961 {
962 XCLIPOBJ* Clip;
963 PWND Wnd;
964 HWND hWnd;
965
966 hWnd = IntWindowFromDC(hdc);
967
968 if (hWnd && (Wnd = UserGetWindowObject(hWnd)))
969 {
970 Clip = (XCLIPOBJ*)UserGetProp(Wnd, AtomWndObj, TRUE);
971
972 if ( Clip && Clip->Hwnd == hWnd )
973 {
974 if (pwndo) *pwndo = &Clip->WndObj;
975 }
976 }
977 return hWnd;
978 }
979
980 HDC APIENTRY
981 NtUserGetDCEx(HWND hWnd OPTIONAL, HANDLE ClipRegion, ULONG Flags)
982 {
983 PWND Wnd=NULL;
984 DECLARE_RETURN(HDC);
985
986 TRACE("Enter NtUserGetDCEx: hWnd %p, ClipRegion %p, Flags %x.\n",
987 hWnd, ClipRegion, Flags);
988 UserEnterExclusive();
989
990 if (hWnd && !(Wnd = UserGetWindowObject(hWnd)))
991 {
992 RETURN(NULL);
993 }
994 RETURN( UserGetDCEx(Wnd, ClipRegion, Flags));
995
996 CLEANUP:
997 TRACE("Leave NtUserGetDCEx, ret=%p\n", _ret_);
998 UserLeave();
999 END_CLEANUP;
1000 }
1001
1002 /*
1003 * NtUserGetWindowDC
1004 *
1005 * The NtUserGetWindowDC function retrieves the device context (DC) for the
1006 * entire window, including title bar, menus, and scroll bars. A window device
1007 * context permits painting anywhere in a window, because the origin of the
1008 * device context is the upper-left corner of the window instead of the client
1009 * area.
1010 *
1011 * Status
1012 * @implemented
1013 */
1014 HDC APIENTRY
1015 NtUserGetWindowDC(HWND hWnd)
1016 {
1017 return NtUserGetDCEx(hWnd, 0, DCX_USESTYLE | DCX_WINDOW);
1018 }
1019
1020 HDC APIENTRY
1021 NtUserGetDC(HWND hWnd)
1022 {
1023 TRACE("NtUGetDC -> %p:%x\n", hWnd, !hWnd ? DCX_CACHE | DCX_WINDOW : DCX_USESTYLE);
1024
1025 return NtUserGetDCEx(hWnd, NULL, NULL == hWnd ? DCX_CACHE | DCX_WINDOW : DCX_USESTYLE);
1026 }
1027
1028 /*!
1029 * Select logical palette into device context.
1030 * \param hDC handle to the device context
1031 * \param hpal handle to the palette
1032 * \param ForceBackground If this value is FALSE the logical palette will be copied to the device palette only when the applicatioon
1033 * is in the foreground. If this value is TRUE then map the colors in the logical palette to the device
1034 * palette colors in the best way.
1035 * \return old palette
1036 *
1037 * \todo implement ForceBackground == TRUE
1038 */
1039 HPALETTE
1040 APIENTRY
1041 NtUserSelectPalette(HDC hDC,
1042 HPALETTE hpal,
1043 BOOL ForceBackground)
1044 {
1045 HPALETTE oldPal;
1046 UserEnterExclusive();
1047 // Implement window checks
1048 oldPal = GdiSelectPalette( hDC, hpal, ForceBackground);
1049 UserLeave();
1050 return oldPal;
1051 }
1052
1053 /* EOF */