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