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