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