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