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