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