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