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