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