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