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