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