[DDK]: Merge 46183 from header-branch.
[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 GDIOBJ_FreeObjByHandle(Dce->hrgnClip, GDI_OBJECT_TYPE_REGION|GDI_OBJECT_TYPE_SILENT);
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_INDESTROY | 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 if (Dce->hrgnClip != NULL)
577 {
578 DPRINT1("Should not be called!!\n");
579 GDIOBJ_FreeObjByHandle(Dce->hrgnClip, GDI_OBJECT_TYPE_REGION|GDI_OBJECT_TYPE_SILENT);
580 Dce->hrgnClip = NULL;
581 }
582 Dce->hrgnClip = ClipRegion;
583 }
584
585 DceSetDrawable(Window, Dce->hDC, Flags, UpdateClipOrigin);
586
587 DceUpdateVisRgn(Dce, Window, Flags);
588
589 if (Dce->DCXFlags & DCX_CACHE)
590 {
591 DPRINT("ENTER!!!!!! DCX_CACHE!!!!!! hDC-> %x\n", Dce->hDC);
592 // Need to set ownership so Sync dcattr will work.
593 IntGdiSetDCOwnerEx( Dce->hDC, GDI_OBJ_HMGR_POWNED, FALSE);
594 Dce->ptiOwner = GetW32ThreadInfo(); // Set the temp owning
595 }
596
597 if ( Wnd &&
598 Wnd->ExStyle & WS_EX_LAYOUTRTL &&
599 !(Flags & DCX_KEEPLAYOUT) )
600 {
601 NtGdiSetLayout(Dce->hDC, -1, LAYOUT_RTL);
602 }
603
604 if (Dce->DCXFlags & DCX_PROCESSOWNED)
605 {
606 ppi = PsGetCurrentProcessWin32Process();
607 ppi->W32PF_flags |= W32PF_OWNDCCLEANUP;
608 Dce->ptiOwner = NULL;
609 Dce->ppiOwner = ppi;
610 }
611
612 return(Dce->hDC);
613 }
614
615 /***********************************************************************
616 * DceFreeDCE
617 */
618 PDCE FASTCALL
619 DceFreeDCE(PDCE pdce, BOOLEAN Force)
620 {
621 DCE *ret;
622 PLIST_ENTRY pLE;
623 BOOL Hit = FALSE;
624
625 if (NULL == pdce) return NULL;
626
627 pLE = pdce->List.Flink;
628 ret = CONTAINING_RECORD(pLE, DCE, List);
629
630 pdce->DCXFlags |= DCX_INDESTROY;
631
632 if (Force && !GDIOBJ_OwnedByCurrentProcess(pdce->hDC))
633 {
634 DPRINT("Change ownership for DCE! -> %x\n" , pdce);
635 // Note: Windows sets W32PF_OWNDCCLEANUP and moves on.
636 if (!IsObjectDead((HGDIOBJ) pdce->hDC))
637 {
638 DC_SetOwnership( pdce->hDC, PsGetCurrentProcess());
639 }
640 else
641 {
642 DPRINT1("Attempted to change ownership of an DCEhDC 0x%x currently being destroyed!!!\n",pdce->hDC);
643 Hit = TRUE;
644 }
645 }
646
647 if (!Hit) IntGdiDeleteDC(pdce->hDC, TRUE);
648
649 if (pdce->hrgnClip && !(pdce->DCXFlags & DCX_KEEPCLIPRGN))
650 {
651 GDIOBJ_FreeObjByHandle(pdce->hrgnClip, GDI_OBJECT_TYPE_REGION|GDI_OBJECT_TYPE_SILENT);
652 pdce->hrgnClip = NULL;
653 }
654
655 RemoveEntryList(&pdce->List);
656
657 if (IsListEmpty(&pdce->List))
658 {
659 DPRINT1("List is Empty! DCE! -> %x\n" , pdce);
660 return NULL;
661 }
662
663 ExFreePoolWithTag(pdce, TAG_PDCE);
664
665 DCECount--;
666 DPRINT("Freed DCE's! %d \n", DCECount);
667
668 return ret;
669 }
670
671 /***********************************************************************
672 * DceFreeWindowDCE
673 *
674 * Remove owned DCE and reset unreleased cache DCEs.
675 */
676 void FASTCALL
677 DceFreeWindowDCE(PWINDOW_OBJECT Window)
678 {
679 PDCE pDCE;
680 PLIST_ENTRY pLE;
681
682 if (DCECount <= 0)
683 {
684 DPRINT1("FreeWindowDCE No Entry! %d\n",DCECount);
685 return;
686 }
687
688 pLE = LEDce.Flink;
689 pDCE = CONTAINING_RECORD(pLE, DCE, List);
690 do
691 {
692 if (!pDCE)
693 {
694 DPRINT1("FreeWindowDCE No DCE Pointer!\n");
695 break;
696 }
697 if (IsListEmpty(&pDCE->List))
698 {
699 DPRINT1("FreeWindowDCE List is Empty!!!!\n");
700 break;
701 }
702 if ( pDCE->hwndCurrent == Window->hSelf &&
703 !(pDCE->DCXFlags & DCX_DCEEMPTY) )
704 {
705 if (!(pDCE->DCXFlags & DCX_CACHE)) /* owned or Class DCE*/
706 {
707 if (Window->Wnd->pcls->style & CS_CLASSDC) /* Test Class first */
708 {
709 if (pDCE->DCXFlags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN)) /* Class DCE*/
710 DceDeleteClipRgn(pDCE);
711 // Update and reset Vis Rgn and clear the dirty bit.
712 // Should release VisRgn than reset it to default.
713 DceUpdateVisRgn(pDCE, Window, pDCE->DCXFlags);
714 pDCE->DCXFlags = DCX_DCEEMPTY|DCX_CACHE;
715 pDCE->hwndCurrent = 0;
716
717 DPRINT("POWNED DCE going Cheap!! DCX_CACHE!! hDC-> %x \n", pDCE->hDC);
718 if (!IntGdiSetDCOwnerEx( pDCE->hDC, GDI_OBJ_HMGR_NONE, FALSE))
719 {
720 DPRINT1("Fail Owner Switch hDC-> %x \n", pDCE->hDC);
721 break;
722 }
723 /* Do not change owner so thread can clean up! */
724 }
725 else if (Window->Wnd->pcls->style & CS_OWNDC) /* owned DCE*/
726 {
727 pDCE = DceFreeDCE(pDCE, FALSE);
728 if (!pDCE) break;
729 continue;
730 }
731 else
732 {
733 DPRINT1("Not POWNED or CLASSDC hwndCurrent -> %x \n", pDCE->hwndCurrent);
734 ASSERT(FALSE);
735 }
736 }
737 else
738 {
739 if (pDCE->DCXFlags & DCX_DCEBUSY) /* shared cache DCE */
740 {
741 /* FIXME: AFAICS we are doing the right thing here so
742 * this should be a DPRINT. But this is best left as an ERR
743 * because the 'application error' is likely to come from
744 * another part of Wine (i.e. it's our fault after all).
745 * We should change this to DPRINT when ReactOS is more stable
746 * (for 1.0?).
747 */
748 DPRINT1("[%p] GetDC() without ReleaseDC()!\n", Window->hSelf);
749 DceReleaseDC(pDCE, FALSE);
750 }
751 pDCE->DCXFlags |= DCX_DCEEMPTY;
752 pDCE->hwndCurrent = 0;
753 }
754 }
755 pLE = pDCE->List.Flink;
756 pDCE = CONTAINING_RECORD(pLE, DCE, List);
757 }
758 while (pLE != &LEDce);
759 }
760
761 void FASTCALL
762 DceFreeClassDCE(HDC hDC)
763 {
764 PDCE pDCE;
765 PLIST_ENTRY pLE;
766 pLE = LEDce.Flink;
767 pDCE = CONTAINING_RECORD(pLE, DCE, List);
768
769 do
770 {
771 if(!pDCE) break;
772 if (pDCE->hDC == hDC)
773 {
774 pDCE = DceFreeDCE(pDCE, TRUE); // Might have gone cheap!
775 if (!pDCE) break;
776 continue;
777 }
778 pLE = pDCE->List.Flink;
779 pDCE = CONTAINING_RECORD(pLE, DCE, List);
780 }
781 while (pLE != &LEDce);
782 }
783
784 void FASTCALL
785 DceFreeThreadDCE(PTHREADINFO pti)
786 {
787 PDCE pDCE;
788 PLIST_ENTRY pLE;
789 pLE = LEDce.Flink;
790 pDCE = CONTAINING_RECORD(pLE, DCE, List);
791
792 do
793 {
794 if(!pDCE) break;
795 if (pDCE->ptiOwner == pti)
796 {
797 if (pDCE->DCXFlags & DCX_CACHE)
798 {
799 pDCE = DceFreeDCE(pDCE, TRUE);
800 if (!pDCE) break;
801 continue;
802 }
803 }
804 pLE = pDCE->List.Flink;
805 pDCE = CONTAINING_RECORD(pLE, DCE, List);
806 }
807 while (pLE != &LEDce);
808 }
809
810 VOID FASTCALL
811 DceEmptyCache(VOID)
812 {
813 PDCE pDCE;
814 PLIST_ENTRY pLE;
815 pLE = LEDce.Flink;
816 pDCE = CONTAINING_RECORD(pLE, DCE, List);
817
818 do
819 {
820 if(!pDCE) break;
821 pDCE = DceFreeDCE(pDCE, TRUE);
822 if(!pDCE) break;
823 }
824 while (pLE != &LEDce);
825 }
826
827 VOID FASTCALL
828 DceResetActiveDCEs(PWINDOW_OBJECT Window)
829 {
830 DCE *pDCE;
831 PDC dc;
832 PWINDOW_OBJECT CurrentWindow;
833 INT DeltaX;
834 INT DeltaY;
835 PLIST_ENTRY pLE;
836
837 if (NULL == Window)
838 {
839 return;
840 }
841 pLE = LEDce.Flink;
842 pDCE = CONTAINING_RECORD(pLE, DCE, List);
843 if(!pDCE) return; // Another null test!
844 do
845 {
846 if(!pDCE) break;
847 if(pLE == &LEDce) break;
848 if (0 == (pDCE->DCXFlags & (DCX_DCEEMPTY|DCX_INDESTROY)))
849 {
850 if (Window->hSelf == pDCE->hwndCurrent)
851 {
852 CurrentWindow = Window;
853 }
854 else
855 {
856 CurrentWindow = UserGetWindowObject(pDCE->hwndCurrent);
857 if (NULL == CurrentWindow)
858 {
859 pLE = pDCE->List.Flink;
860 pDCE = CONTAINING_RECORD(pLE, DCE, List);
861 continue;
862 }
863 }
864
865 if (!GDIOBJ_ValidateHandle(pDCE->hDC, GDI_OBJECT_TYPE_DC) ||
866 (dc = DC_LockDc(pDCE->hDC)) == NULL)
867 {
868 pLE = pDCE->List.Flink;
869 pDCE = CONTAINING_RECORD(pLE, DCE, List);
870 continue;
871 }
872 if (Window == CurrentWindow || IntIsChildWindow(Window, CurrentWindow))
873 {
874 if (pDCE->DCXFlags & DCX_WINDOW)
875 {
876 DeltaX = CurrentWindow->Wnd->rcWindow.left - dc->ptlDCOrig.x;
877 DeltaY = CurrentWindow->Wnd->rcWindow.top - dc->ptlDCOrig.y;
878 dc->ptlDCOrig.x = CurrentWindow->Wnd->rcWindow.left;
879 dc->ptlDCOrig.y = CurrentWindow->Wnd->rcWindow.top;
880 }
881 else
882 {
883 DeltaX = CurrentWindow->Wnd->rcClient.left - dc->ptlDCOrig.x;
884 DeltaY = CurrentWindow->Wnd->rcClient.top - dc->ptlDCOrig.y;
885 dc->ptlDCOrig.x = CurrentWindow->Wnd->rcClient.left;
886 dc->ptlDCOrig.y = CurrentWindow->Wnd->rcClient.top;
887 }
888 if (NULL != dc->rosdc.hClipRgn)
889 {
890 NtGdiOffsetRgn(dc->rosdc.hClipRgn, DeltaX, DeltaY);
891 CLIPPING_UpdateGCRegion(dc);
892 }
893 if (NULL != pDCE->hrgnClip)
894 {
895 NtGdiOffsetRgn(pDCE->hrgnClip, DeltaX, DeltaY);
896 }
897 }
898 DC_UnlockDc(dc);
899
900 DceUpdateVisRgn(pDCE, CurrentWindow, pDCE->DCXFlags);
901
902 if (Window->hSelf != pDCE->hwndCurrent)
903 {
904 // IntEngWindowChanged(CurrentWindow, WOC_RGN_CLIENT);
905 // UserDerefObject(CurrentWindow);
906 }
907 }
908 pLE = pDCE->List.Flink;
909 pDCE = CONTAINING_RECORD(pLE, DCE, List);
910 }
911 while (pLE != &LEDce);
912 }
913
914 HWND FASTCALL
915 IntWindowFromDC(HDC hDc)
916 {
917 DCE *Dce;
918 PLIST_ENTRY pLE;
919 HWND Ret = NULL;
920
921 pLE = LEDce.Flink;
922 Dce = CONTAINING_RECORD(pLE, DCE, List);
923 do
924 {
925 if (Dce->hDC == hDc)
926 {
927 if (Dce->DCXFlags & DCX_INDESTROY)
928 Ret = NULL;
929 else
930 Ret = Dce->hwndCurrent;
931 break;
932 }
933 pLE = Dce->List.Flink;
934 Dce = CONTAINING_RECORD(pLE, DCE, List);
935 }
936 while (pLE != &LEDce);
937 return Ret;
938 }
939
940 INT FASTCALL
941 UserReleaseDC(PWINDOW_OBJECT Window, HDC hDc, BOOL EndPaint)
942 {
943 PDCE dce;
944 PLIST_ENTRY pLE;
945 INT nRet = 0;
946 BOOL Hit = FALSE;
947
948 DPRINT("%p %p\n", Window, hDc);
949 pLE = LEDce.Flink;
950 dce = CONTAINING_RECORD(pLE, DCE, List);
951 do
952 {
953 if(!dce) break;
954 if (dce->hDC == hDc)
955 {
956 Hit = TRUE;
957 break;
958 }
959 pLE = dce->List.Flink;
960 dce = CONTAINING_RECORD(pLE, DCE, List);
961 }
962 while (pLE != &LEDce );
963
964 if ( Hit && (dce->DCXFlags & DCX_DCEBUSY))
965 {
966 nRet = DceReleaseDC(dce, EndPaint);
967 }
968
969 return nRet;
970 }
971
972 HDC FASTCALL
973 UserGetWindowDC(PWINDOW_OBJECT Wnd)
974 {
975 return UserGetDCEx(Wnd, 0, DCX_USESTYLE | DCX_WINDOW);
976 }
977
978 HWND FASTCALL
979 UserGethWnd( HDC hdc, PWNDOBJ *pwndo)
980 {
981 PWNDGDI pWndgdi;
982 PWINDOW_OBJECT Wnd;
983 HWND hWnd;
984
985 hWnd = IntWindowFromDC(hdc);
986
987 if (hWnd && !(Wnd = UserGetWindowObject(hWnd)))
988 {
989 pWndgdi = (WNDGDI *)IntGetProp(Wnd, AtomWndObj);
990
991 if ( pWndgdi && pWndgdi->Hwnd == hWnd )
992 {
993 if (pwndo) *pwndo = (PWNDOBJ)pWndgdi;
994 }
995 }
996 return hWnd;
997 }
998
999 HDC APIENTRY
1000 NtUserGetDCEx(HWND hWnd OPTIONAL, HANDLE ClipRegion, ULONG Flags)
1001 {
1002 PWINDOW_OBJECT Wnd=NULL;
1003 DECLARE_RETURN(HDC);
1004
1005 DPRINT("Enter NtUserGetDCEx\n");
1006 UserEnterExclusive();
1007
1008 if (hWnd && !(Wnd = UserGetWindowObject(hWnd)))
1009 {
1010 RETURN(NULL);
1011 }
1012 RETURN( UserGetDCEx(Wnd, ClipRegion, Flags));
1013
1014 CLEANUP:
1015 DPRINT("Leave NtUserGetDCEx, ret=%i\n",_ret_);
1016 UserLeave();
1017 END_CLEANUP;
1018 }
1019
1020 /*
1021 * NtUserGetWindowDC
1022 *
1023 * The NtUserGetWindowDC function retrieves the device context (DC) for the
1024 * entire window, including title bar, menus, and scroll bars. A window device
1025 * context permits painting anywhere in a window, because the origin of the
1026 * device context is the upper-left corner of the window instead of the client
1027 * area.
1028 *
1029 * Status
1030 * @implemented
1031 */
1032 HDC APIENTRY
1033 NtUserGetWindowDC(HWND hWnd)
1034 {
1035 return NtUserGetDCEx(hWnd, 0, DCX_USESTYLE | DCX_WINDOW);
1036 }
1037
1038 HDC APIENTRY
1039 NtUserGetDC(HWND hWnd)
1040 {
1041 DPRINT("NtUGetDC -> %x:%x\n", hWnd, !hWnd ? DCX_CACHE | DCX_WINDOW : DCX_USESTYLE );
1042
1043 return NtUserGetDCEx(hWnd, NULL, NULL == hWnd ? DCX_CACHE | DCX_WINDOW : DCX_USESTYLE);
1044 }
1045
1046 /*!
1047 * Select logical palette into device context.
1048 * \param hDC handle to the device context
1049 * \param hpal handle to the palette
1050 * \param ForceBackground If this value is FALSE the logical palette will be copied to the device palette only when the applicatioon
1051 * is in the foreground. If this value is TRUE then map the colors in the logical palette to the device
1052 * palette colors in the best way.
1053 * \return old palette
1054 *
1055 * \todo implement ForceBackground == TRUE
1056 */
1057 HPALETTE
1058 APIENTRY
1059 NtUserSelectPalette(HDC hDC,
1060 HPALETTE hpal,
1061 BOOL ForceBackground)
1062 {
1063 HPALETTE oldPal;
1064 UserEnterExclusive();
1065 // Implement window checks
1066 oldPal = GdiSelectPalette( hDC, hpal, ForceBackground);
1067 UserLeave();
1068 return oldPal;
1069 }
1070
1071
1072 /* EOF */