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