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