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