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