Synchronize with trunk's revision r57659.
[reactos.git] / 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-> %x\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-> %x \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 //bUpdateVisRgn = FALSE;
466 break;
467 }
468 }
469 pLE = Dce->List.Flink;
470 Dce = CONTAINING_RECORD(pLE, DCE, List);
471 }
472 while (pLE != &LEDce);
473 KeLeaveCriticalRegion();
474
475 Dce = (DceEmpty == NULL) ? DceUnused : DceEmpty;
476
477 if (Dce == NULL)
478 {
479 Dce = DceAllocDCE(NULL, DCE_CACHE_DC);
480 }
481 if (!Dce) return NULL;
482
483 Dce->hwndCurrent = (Wnd ? Wnd->head.h : NULL);
484 Dce->pwndOrg = Dce->pwndClip = Wnd;
485 }
486 else // If we are here, we are POWNED or having CLASS.
487 {
488 KeEnterCriticalRegion();
489 pLE = LEDce.Flink;
490 Dce = CONTAINING_RECORD(pLE, DCE, List);
491 do
492 { // Check for Window handle than HDC match for CLASS.
493 if (Dce->hwndCurrent == Wnd->head.h)
494 {
495 bUpdateVisRgn = FALSE;
496 break;
497 }
498 if (Dce->hDC == hDC) break;
499 pLE = Dce->List.Flink;
500 Dce = CONTAINING_RECORD(pLE, DCE, List);
501 }
502 while (pLE != &LEDce);
503 KeLeaveCriticalRegion();
504
505 if ( (Flags & (DCX_INTERSECTRGN|DCX_EXCLUDERGN)) &&
506 (Dce->DCXFlags & (DCX_INTERSECTRGN|DCX_EXCLUDERGN)) )
507 {
508 DceDeleteClipRgn(Dce);
509 }
510 }
511 // First time use hax, need to use DceAllocDCE during window display init.
512 if (NULL == Dce)
513 {
514 return(NULL);
515 }
516
517 if (!GreIsHandleValid(Dce->hDC))
518 {
519 ERR("FIXME: Got DCE with invalid hDC! 0x%x\n", Dce->hDC);
520 Dce->hDC = DceCreateDisplayDC();
521 /* FIXME: Handle error */
522 }
523
524 Dce->DCXFlags = Flags | DCX_DCEBUSY;
525
526 /*
527 * Bump it up! This prevents the random errors in wine dce tests and with
528 * proper bits set in DCX_CACHECOMPAREMASK.
529 * Reference:
530 * http://www.reactos.org/archives/public/ros-dev/2008-July/010498.html
531 * http://www.reactos.org/archives/public/ros-dev/2008-July/010499.html
532 */
533 if (pLE != &LEDce)
534 {
535 RemoveEntryList(&Dce->List);
536 InsertHeadList(&LEDce, &Dce->List);
537 }
538
539 /* Introduced in rev 6691 and modified later. */
540 if ( (Flags & DCX_INTERSECTUPDATE) && !ClipRegion )
541 {
542 Flags |= DCX_INTERSECTRGN | DCX_KEEPCLIPRGN;
543 Dce->DCXFlags |= DCX_INTERSECTRGN | DCX_KEEPCLIPRGN;
544 ClipRegion = Wnd->hrgnUpdate;
545 bUpdateVisRgn = TRUE;
546 }
547
548 if (ClipRegion == HRGN_WINDOW)
549 {
550 if (!(Flags & DCX_WINDOW))
551 {
552 Dce->hrgnClip = IntSysCreateRectRgnIndirect(&Wnd->rcClient);
553 }
554 else
555 {
556 Dce->hrgnClip = IntSysCreateRectRgnIndirect(&Wnd->rcWindow);
557 }
558 Dce->DCXFlags &= ~DCX_KEEPCLIPRGN;
559 bUpdateVisRgn = TRUE;
560 }
561 else if (ClipRegion != NULL)
562 {
563 if (Dce->hrgnClip != NULL)
564 {
565 ERR("Should not be called!!\n");
566 GreDeleteObject(Dce->hrgnClip);
567 Dce->hrgnClip = NULL;
568 }
569 Dce->hrgnClip = ClipRegion;
570 bUpdateVisRgn = TRUE;
571 }
572
573 if (IntGdiSetHookFlags(Dce->hDC, DCHF_VALIDATEVISRGN)) bUpdateVisRgn = TRUE;
574
575 DceSetDrawable(Wnd, Dce->hDC, Flags, UpdateClipOrigin);
576
577 if (bUpdateVisRgn) DceUpdateVisRgn(Dce, Wnd, Flags);
578
579 if (Dce->DCXFlags & DCX_CACHE)
580 {
581 TRACE("ENTER!!!!!! DCX_CACHE!!!!!! hDC-> %x\n", Dce->hDC);
582 // Need to set ownership so Sync dcattr will work.
583 GreSetDCOwner(Dce->hDC, GDI_OBJ_HMGR_POWNED);
584 Dce->ptiOwner = GetW32ThreadInfo(); // Set the temp owning
585 }
586
587 if ( Wnd &&
588 Wnd->ExStyle & WS_EX_LAYOUTRTL &&
589 !(Flags & DCX_KEEPLAYOUT) )
590 {
591 NtGdiSetLayout(Dce->hDC, -1, LAYOUT_RTL);
592 }
593
594 if (Dce->DCXFlags & DCX_PROCESSOWNED)
595 {
596 ppi = PsGetCurrentProcessWin32Process();
597 ppi->W32PF_flags |= W32PF_OWNDCCLEANUP;
598 Dce->ptiOwner = NULL;
599 Dce->ppiOwner = ppi;
600 }
601
602 return(Dce->hDC);
603 }
604
605 /***********************************************************************
606 * DceFreeDCE
607 */
608 PDCE FASTCALL
609 DceFreeDCE(PDCE pdce, BOOLEAN Force)
610 {
611 DCE *ret;
612 PLIST_ENTRY pLE;
613 BOOL Hit = FALSE;
614
615 if (NULL == pdce) return NULL;
616
617 pLE = pdce->List.Flink;
618 ret = CONTAINING_RECORD(pLE, DCE, List);
619
620 pdce->DCXFlags |= DCX_INDESTROY;
621
622 if (Force &&
623 GreGetObjectOwner(pdce->hDC) != GDI_OBJ_HMGR_POWNED)
624 {
625 TRACE("Change ownership for DCE! -> %x\n" , pdce);
626 // NOTE: Windows sets W32PF_OWNDCCLEANUP and moves on.
627 if (GreIsHandleValid(pdce->hDC))
628 {
629 GreSetDCOwner(pdce->hDC, GDI_OBJ_HMGR_POWNED);
630 }
631 else
632 {
633 ERR("Attempted to change ownership of an DCEhDC 0x%x currently being destroyed!!!\n",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! -> %x\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-> %x \n", pDCE->hDC);
715 if (!GreSetDCOwner( pDCE->hDC, GDI_OBJ_HMGR_NONE))
716 {
717 ERR("Fail Owner Switch hDC-> %x \n", pDCE->hDC);
718 break;
719 }
720 /* Do not change owner so thread can clean up! */
721 }
722 else if (Window->pcls->style & CS_OWNDC) /* Owned DCE */
723 {
724 pDCE = DceFreeDCE(pDCE, FALSE);
725 if (!pDCE) break;
726 continue;
727 }
728 else
729 {
730 ERR("Not POWNED or CLASSDC hwndCurrent -> %x \n", pDCE->hwndCurrent);
731 // ASSERT(FALSE); /* bug 5320 */
732 }
733 }
734 else
735 {
736 if (pDCE->DCXFlags & DCX_DCEBUSY) /* Shared cache DCE */
737 {
738 /* FIXME: AFAICS we are doing the right thing here so
739 * this should be a TRACE. But this is best left as an ERR
740 * because the 'application error' is likely to come from
741 * another part of Wine (i.e. it's our fault after all).
742 * We should change this to TRACE when ReactOS is more stable
743 * (for 1.0?).
744 */
745 ERR("[%p] GetDC() without ReleaseDC()!\n", Window->head.h);
746 DceReleaseDC(pDCE, FALSE);
747 }
748 pDCE->DCXFlags |= DCX_DCEEMPTY;
749 pDCE->hwndCurrent = 0;
750 pDCE->pwndOrg = pDCE->pwndClip = NULL;
751 }
752 }
753 pLE = pDCE->List.Flink;
754 pDCE = CONTAINING_RECORD(pLE, DCE, List);
755 }
756 while (pLE != &LEDce);
757 }
758
759 void FASTCALL
760 DceFreeClassDCE(HDC hDC)
761 {
762 PDCE pDCE;
763 PLIST_ENTRY pLE;
764 pLE = LEDce.Flink;
765 pDCE = CONTAINING_RECORD(pLE, DCE, List);
766
767 do
768 {
769 if(!pDCE) break;
770 if (pDCE->hDC == hDC)
771 {
772 pDCE = DceFreeDCE(pDCE, TRUE); // Might have gone cheap!
773 if (!pDCE) break;
774 continue;
775 }
776 pLE = pDCE->List.Flink;
777 pDCE = CONTAINING_RECORD(pLE, DCE, List);
778 }
779 while (pLE != &LEDce);
780 }
781
782 void FASTCALL
783 DceFreeThreadDCE(PTHREADINFO pti)
784 {
785 PDCE pDCE;
786 PLIST_ENTRY pLE;
787 pLE = LEDce.Flink;
788 pDCE = CONTAINING_RECORD(pLE, DCE, List);
789
790 do
791 {
792 if(!pDCE) break;
793 if (pDCE->ptiOwner == pti)
794 {
795 if (pDCE->DCXFlags & DCX_CACHE)
796 {
797 pDCE = DceFreeDCE(pDCE, TRUE);
798 if (!pDCE) break;
799 continue;
800 }
801 }
802 pLE = pDCE->List.Flink;
803 pDCE = CONTAINING_RECORD(pLE, DCE, List);
804 }
805 while (pLE != &LEDce);
806 }
807
808 VOID FASTCALL
809 DceEmptyCache(VOID)
810 {
811 PDCE pDCE;
812 PLIST_ENTRY pLE;
813 pLE = LEDce.Flink;
814 pDCE = CONTAINING_RECORD(pLE, DCE, List);
815
816 do
817 {
818 if(!pDCE) break;
819 pDCE = DceFreeDCE(pDCE, TRUE);
820 if(!pDCE) break;
821 }
822 while (pLE != &LEDce);
823 }
824
825 VOID FASTCALL
826 DceResetActiveDCEs(PWND Window)
827 {
828 DCE *pDCE;
829 PDC dc;
830 PWND CurrentWindow;
831 INT DeltaX;
832 INT DeltaY;
833 PLIST_ENTRY pLE;
834
835 if (NULL == Window)
836 {
837 return;
838 }
839 pLE = LEDce.Flink;
840 pDCE = CONTAINING_RECORD(pLE, DCE, List);
841
842 do
843 {
844 if(!pDCE) break;
845 if(pLE == &LEDce) break;
846 if (0 == (pDCE->DCXFlags & (DCX_DCEEMPTY|DCX_INDESTROY)))
847 {
848 if (Window->head.h == pDCE->hwndCurrent)
849 {
850 CurrentWindow = Window;
851 }
852 else
853 {
854 if (!pDCE->hwndCurrent)
855 CurrentWindow = NULL;
856 else
857 CurrentWindow = UserGetWindowObject(pDCE->hwndCurrent);
858 if (NULL == CurrentWindow)
859 {
860 pLE = pDCE->List.Flink;
861 pDCE = CONTAINING_RECORD(pLE, DCE, List);
862 continue;
863 }
864 }
865
866 if (!GreIsHandleValid(pDCE->hDC) ||
867 (dc = DC_LockDc(pDCE->hDC)) == NULL)
868 {
869 pLE = pDCE->List.Flink;
870 pDCE = CONTAINING_RECORD(pLE, DCE, List);
871 continue;
872 }
873 if (Window == CurrentWindow || IntIsChildWindow(Window, CurrentWindow))
874 {
875 if (pDCE->DCXFlags & DCX_WINDOW)
876 {
877 DeltaX = CurrentWindow->rcWindow.left - dc->ptlDCOrig.x;
878 DeltaY = CurrentWindow->rcWindow.top - dc->ptlDCOrig.y;
879 dc->ptlDCOrig.x = CurrentWindow->rcWindow.left;
880 dc->ptlDCOrig.y = CurrentWindow->rcWindow.top;
881 }
882 else
883 {
884 DeltaX = CurrentWindow->rcClient.left - dc->ptlDCOrig.x;
885 DeltaY = CurrentWindow->rcClient.top - dc->ptlDCOrig.y;
886 dc->ptlDCOrig.x = CurrentWindow->rcClient.left;
887 dc->ptlDCOrig.y = CurrentWindow->rcClient.top;
888 }
889
890 if (NULL != dc->rosdc.hClipRgn)
891 {
892 NtGdiOffsetRgn(dc->rosdc.hClipRgn, DeltaX, DeltaY);
893 CLIPPING_UpdateGCRegion(dc);
894 }
895 if (NULL != pDCE->hrgnClip)
896 {
897 NtGdiOffsetRgn(pDCE->hrgnClip, DeltaX, DeltaY);
898 }
899 }
900 DC_UnlockDc(dc);
901
902 DceUpdateVisRgn(pDCE, CurrentWindow, pDCE->DCXFlags);
903 IntGdiSetHookFlags(pDCE->hDC, DCHF_VALIDATEVISRGN);
904
905 if (Window->head.h != pDCE->hwndCurrent)
906 {
907 // IntEngWindowChanged(CurrentWindow, WOC_RGN_CLIENT);
908 // UserDerefObject(CurrentWindow);
909 }
910 }
911 pLE = pDCE->List.Flink;
912 pDCE = CONTAINING_RECORD(pLE, DCE, List);
913 }
914 while (pLE != &LEDce);
915 }
916
917 HWND FASTCALL
918 IntWindowFromDC(HDC hDc)
919 {
920 DCE *Dce;
921 PLIST_ENTRY pLE;
922 HWND Ret = NULL;
923
924 pLE = LEDce.Flink;
925 Dce = CONTAINING_RECORD(pLE, DCE, List);
926 do
927 {
928 if (Dce->hDC == hDc)
929 {
930 if (Dce->DCXFlags & DCX_INDESTROY)
931 Ret = NULL;
932 else
933 Ret = Dce->hwndCurrent;
934 break;
935 }
936 pLE = Dce->List.Flink;
937 Dce = CONTAINING_RECORD(pLE, DCE, List);
938 }
939 while (pLE != &LEDce);
940 return Ret;
941 }
942
943 INT FASTCALL
944 UserReleaseDC(PWND Window, HDC hDc, BOOL EndPaint)
945 {
946 PDCE dce;
947 PLIST_ENTRY pLE;
948 INT nRet = 0;
949 BOOL Hit = FALSE;
950
951 TRACE("%p %p\n", Window, hDc);
952 pLE = LEDce.Flink;
953 dce = CONTAINING_RECORD(pLE, DCE, List);
954 do
955 {
956 if(!dce) break;
957 if (dce->hDC == hDc)
958 {
959 Hit = TRUE;
960 break;
961 }
962 pLE = dce->List.Flink;
963 dce = CONTAINING_RECORD(pLE, DCE, List);
964 }
965 while (pLE != &LEDce );
966
967 if ( Hit && (dce->DCXFlags & DCX_DCEBUSY))
968 {
969 nRet = DceReleaseDC(dce, EndPaint);
970 }
971
972 return nRet;
973 }
974
975 HDC FASTCALL
976 UserGetWindowDC(PWND Wnd)
977 {
978 return UserGetDCEx(Wnd, 0, DCX_USESTYLE | DCX_WINDOW);
979 }
980
981 HWND FASTCALL
982 UserGethWnd( HDC hdc, PWNDOBJ *pwndo)
983 {
984 PWNDGDI pWndgdi;
985 PWND Wnd;
986 HWND hWnd;
987 PPROPERTY pprop;
988
989 hWnd = IntWindowFromDC(hdc);
990
991 if (hWnd && !(Wnd = UserGetWindowObject(hWnd)))
992 {
993 pprop = IntGetProp(Wnd, AtomWndObj);
994
995 pWndgdi = (WNDGDI *)pprop->Data;
996
997 if ( pWndgdi && pWndgdi->Hwnd == hWnd )
998 {
999 if (pwndo) *pwndo = (PWNDOBJ)pWndgdi;
1000 }
1001 }
1002 return hWnd;
1003 }
1004
1005 HDC APIENTRY
1006 NtUserGetDCEx(HWND hWnd OPTIONAL, HANDLE ClipRegion, ULONG Flags)
1007 {
1008 PWND Wnd=NULL;
1009 DECLARE_RETURN(HDC);
1010
1011 TRACE("Enter NtUserGetDCEx\n");
1012 UserEnterExclusive();
1013
1014 if (hWnd && !(Wnd = UserGetWindowObject(hWnd)))
1015 {
1016 RETURN(NULL);
1017 }
1018 RETURN( UserGetDCEx(Wnd, ClipRegion, Flags));
1019
1020 CLEANUP:
1021 TRACE("Leave NtUserGetDCEx, ret=%i\n",_ret_);
1022 UserLeave();
1023 END_CLEANUP;
1024 }
1025
1026 /*
1027 * NtUserGetWindowDC
1028 *
1029 * The NtUserGetWindowDC function retrieves the device context (DC) for the
1030 * entire window, including title bar, menus, and scroll bars. A window device
1031 * context permits painting anywhere in a window, because the origin of the
1032 * device context is the upper-left corner of the window instead of the client
1033 * area.
1034 *
1035 * Status
1036 * @implemented
1037 */
1038 HDC APIENTRY
1039 NtUserGetWindowDC(HWND hWnd)
1040 {
1041 return NtUserGetDCEx(hWnd, 0, DCX_USESTYLE | DCX_WINDOW);
1042 }
1043
1044 HDC APIENTRY
1045 NtUserGetDC(HWND hWnd)
1046 {
1047 TRACE("NtUGetDC -> %x:%x\n", hWnd, !hWnd ? DCX_CACHE | DCX_WINDOW : DCX_USESTYLE );
1048
1049 return NtUserGetDCEx(hWnd, NULL, NULL == hWnd ? DCX_CACHE | DCX_WINDOW : DCX_USESTYLE);
1050 }
1051
1052 /*!
1053 * Select logical palette into device context.
1054 * \param hDC handle to the device context
1055 * \param hpal handle to the palette
1056 * \param ForceBackground If this value is FALSE the logical palette will be copied to the device palette only when the applicatioon
1057 * is in the foreground. If this value is TRUE then map the colors in the logical palette to the device
1058 * palette colors in the best way.
1059 * \return old palette
1060 *
1061 * \todo implement ForceBackground == TRUE
1062 */
1063 HPALETTE
1064 APIENTRY
1065 NtUserSelectPalette(HDC hDC,
1066 HPALETTE hpal,
1067 BOOL ForceBackground)
1068 {
1069 HPALETTE oldPal;
1070 UserEnterExclusive();
1071 // Implement window checks
1072 oldPal = GdiSelectPalette( hDC, hpal, ForceBackground);
1073 UserLeave();
1074 return oldPal;
1075 }
1076
1077 /* EOF */