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