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