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