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