The real, definitive, Visual C++ support branch. Accept no substitutes
[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: 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 if (!Dce) return NULL;
471
472 Dce->hwndCurrent = (Window ? Window->hSelf : NULL);
473 }
474 else // If we are here, we are POWNED or having CLASS.
475 {
476 KeEnterCriticalRegion();
477 Dce = FirstDce;
478 do
479 { // Check for Window handle than HDC match for CLASS.
480 if ((Dce->hwndCurrent == Window->hSelf) || (Dce->hDC == hDC)) break;
481 Dce = (PDCE)Dce->List.Flink;
482 } while (Dce != FirstDce);
483 KeLeaveCriticalRegion();
484
485 DPRINT("DCX:Flags -> %x:%x\n",Dce->DCXFlags & DCX_CACHE, Flags & DCX_CACHE);
486
487 if (Dce->hwndCurrent == Window->hSelf)
488 {
489 DPRINT("Owned DCE!\n");
490 UpdateVisRgn = FALSE; /* updated automatically, via DCHook() */
491 }
492 else
493 {
494 DPRINT("Owned/Class DCE\n");
495 /* we should free dce->clip_rgn here, but Windows apparently doesn't */
496 Dce->DCXFlags &= ~(DCX_EXCLUDERGN | DCX_INTERSECTRGN);
497 Dce->hClipRgn = NULL;
498 }
499
500 #if 1 /* FIXME */
501 UpdateVisRgn = TRUE;
502 #endif
503 }
504
505 // First time use hax, need to use DceAllocDCE during window display init.
506 if (NULL == Dce)
507 {
508 return(NULL);
509 }
510
511 if (!GDIOBJ_ValidateHandle(Dce->hDC, GDI_OBJECT_TYPE_DC))
512 {
513 DPRINT1("FIXME: Got DCE with invalid hDC! 0x%x\n", Dce->hDC);
514 Dce->hDC = DceCreateDisplayDC();
515 /* FIXME: Handle error */
516 }
517
518 if (!(Flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN)) && ClipRegion)
519 {
520 if (!(Flags & DCX_KEEPCLIPRGN))
521 NtGdiDeleteObject(ClipRegion);
522 ClipRegion = NULL;
523 }
524
525 #if 0
526 if (NULL != Dce->hClipRgn)
527 {
528 DceDeleteClipRgn(Dce);
529 }
530 #endif
531
532 Dce->DCXFlags = Flags | DCX_DCEBUSY;
533
534 if (0 != (Flags & DCX_INTERSECTUPDATE) && NULL == ClipRegion)
535 {
536 Flags |= DCX_INTERSECTRGN | DCX_KEEPCLIPRGN;
537 Dce->DCXFlags |= DCX_INTERSECTRGN | DCX_KEEPCLIPRGN;
538 ClipRegion = Window->UpdateRegion;
539 }
540
541 if (ClipRegion == (HRGN) 1)
542 {
543 if (!(Flags & DCX_WINDOW))
544 {
545 Dce->hClipRgn = UnsafeIntCreateRectRgnIndirect(&Window->Wnd->ClientRect);
546 }
547 else
548 {
549 Dce->hClipRgn = UnsafeIntCreateRectRgnIndirect(&Window->Wnd->WindowRect);
550 }
551 Dce->DCXFlags &= ~DCX_KEEPCLIPRGN;
552 }
553 else if (ClipRegion != NULL)
554 {
555 Dce->hClipRgn = ClipRegion;
556 }
557
558 DceSetDrawable(Window, Dce->hDC, Flags, UpdateClipOrigin);
559
560 // if (UpdateVisRgn)
561 {
562 DceUpdateVisRgn(Dce, Window, Flags);
563 }
564
565 if (Dce->DCXFlags & DCX_CACHE)
566 {
567 DPRINT("ENTER!!!!!! DCX_CACHE!!!!!! hDC-> %x\n", Dce->hDC);
568 // Need to set ownership so Sync dcattr will work.
569 IntGdiSetDCOwnerEx( Dce->hDC, GDI_OBJ_HMGR_POWNED, FALSE);
570 Dce->pProcess = PsGetCurrentProcess(); // Set the temp owning process
571 }
572 return(Dce->hDC);
573 }
574
575 /***********************************************************************
576 * DceFreeDCE
577 */
578 PDCE FASTCALL
579 DceFreeDCE(PDCE pdce, BOOLEAN Force)
580 {
581 DCE *ret;
582 BOOL Hit = FALSE;
583
584 if (NULL == pdce) return NULL;
585
586 ret = (PDCE) pdce->List.Flink;
587
588 #if 0 /* FIXME */
589 SetDCHook(pdce->hDC, NULL, 0L);
590 #endif
591
592 if (Force && !GDIOBJ_OwnedByCurrentProcess(pdce->hDC))
593 {
594 DPRINT("Change ownership for DCE! -> %x\n" , pdce);
595 // Note: Windows sets W32PF_OWNDCCLEANUP and moves on.
596 if (!IsObjectDead((HGDIOBJ) pdce->hDC))
597 {
598 DC_SetOwnership( pdce->hDC, PsGetCurrentProcess());
599 }
600 else
601 {
602 DPRINT1("Attempted to change ownership of an DCEhDC 0x%x currently being destroyed!!!\n",pdce->hDC);
603 Hit = TRUE;
604 }
605 }
606
607 if (!Hit) IntGdiDeleteDC(pdce->hDC, TRUE);
608
609 if (pdce->hClipRgn && ! (pdce->DCXFlags & DCX_KEEPCLIPRGN))
610 {
611 NtGdiDeleteObject(pdce->hClipRgn);
612 }
613
614 RemoveEntryList(&pdce->List);
615
616 if (IsListEmpty(&pdce->List))
617 {
618 DPRINT1("List is Empty! DCE! -> %x\n" , pdce);
619 FirstDce = NULL;
620 ret = NULL;
621 }
622
623 ExFreePoolWithTag(pdce, TAG_PDCE);
624
625 return ret;
626 }
627
628
629 /***********************************************************************
630 * DceFreeWindowDCE
631 *
632 * Remove owned DCE and reset unreleased cache DCEs.
633 */
634 void FASTCALL
635 DceFreeWindowDCE(PWINDOW_OBJECT Window)
636 {
637 PDCE pDCE;
638
639 pDCE = FirstDce;
640 KeEnterCriticalRegion();
641 do
642 {
643 if (!pDCE) break;
644 if (pDCE->hwndCurrent == Window->hSelf)
645 {
646 if (!(pDCE->DCXFlags & DCX_CACHE)) /* owned or Class DCE*/
647 {
648 if (Window->Wnd->Class->Style & CS_CLASSDC ||
649 Window->Wnd->Style & CS_CLASSDC) /* Test Class first */
650 {
651 if (pDCE->DCXFlags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN)) /* Class DCE*/
652 DceDeleteClipRgn(pDCE);
653 // Update and reset Vis Rgn and clear the dirty bit.
654 // Should release VisRgn than reset it to default.
655 DceUpdateVisRgn(pDCE, Window, pDCE->DCXFlags);
656 pDCE->DCXFlags = DCX_DCEEMPTY;
657 pDCE->hwndCurrent = 0;
658 }
659 else if (Window->Wnd->Class->Style & CS_OWNDC ||
660 Window->Wnd->Style & CS_OWNDC) /* owned DCE*/
661 {
662 pDCE = DceFreeDCE(pDCE, FALSE);
663 if (!pDCE) break;
664 Window->Dce = NULL;
665 continue;
666 }
667 else
668 {
669 ASSERT(FALSE);
670 }
671 }
672 else
673 {
674 if (pDCE->DCXFlags & DCX_DCEBUSY) /* shared cache DCE */
675 {
676 /* FIXME: AFAICS we are doing the right thing here so
677 * this should be a DPRINT. But this is best left as an ERR
678 * because the 'application error' is likely to come from
679 * another part of Wine (i.e. it's our fault after all).
680 * We should change this to DPRINT when ReactOS is more stable
681 * (for 1.0?).
682 */
683 DPRINT1("[%p] GetDC() without ReleaseDC()!\n", Window->hSelf);
684 DceReleaseDC(pDCE, FALSE);
685 }
686 pDCE->DCXFlags |= DCX_DCEEMPTY;
687 pDCE->hwndCurrent = 0;
688 }
689 }
690 pDCE = (PDCE) pDCE->List.Flink;
691 } while (pDCE != FirstDce);
692 KeLeaveCriticalRegion();
693 }
694
695 void FASTCALL
696 DceFreeClassDCE(HDC hDC)
697 {
698 PDCE pDCE = FirstDce;
699 KeEnterCriticalRegion();
700 do
701 {
702 if(!pDCE) break;
703 if (pDCE->hDC == hDC)
704 {
705 pDCE = DceFreeDCE(pDCE, FALSE);
706 if(!pDCE) break;
707 continue;
708 }
709 pDCE = (PDCE)pDCE->List.Flink;
710 } while (pDCE != FirstDce);
711 KeLeaveCriticalRegion();
712 }
713
714 VOID FASTCALL
715 DceEmptyCache()
716 {
717 PDCE pDCE = FirstDce;
718 KeEnterCriticalRegion();
719 do
720 {
721 if(!pDCE) break;
722 pDCE = DceFreeDCE(pDCE, TRUE);
723 if(!pDCE) break;
724 } while (pDCE != FirstDce);
725 KeLeaveCriticalRegion();
726 FirstDce = NULL;
727 }
728
729 VOID FASTCALL
730 DceResetActiveDCEs(PWINDOW_OBJECT Window)
731 {
732 DCE *pDCE;
733 PDC dc;
734 PWINDOW_OBJECT CurrentWindow;
735 INT DeltaX;
736 INT DeltaY;
737
738 if (NULL == Window)
739 {
740 return;
741 }
742 pDCE = FirstDce;
743 if(!pDCE) return; // Another null test!
744 do
745 {
746 if(!pDCE) break;
747 if (0 == (pDCE->DCXFlags & DCX_DCEEMPTY))
748 {
749 if (Window->hSelf == pDCE->hwndCurrent)
750 {
751 CurrentWindow = Window;
752 }
753 else
754 {
755 CurrentWindow = UserGetWindowObject(pDCE->hwndCurrent);
756 if (NULL == CurrentWindow)
757 {
758 pDCE = (PDCE) pDCE->List.Flink;
759 continue;
760 }
761 }
762
763 if (!GDIOBJ_ValidateHandle(pDCE->hDC, GDI_OBJECT_TYPE_DC) ||
764 (dc = DC_LockDc(pDCE->hDC)) == NULL)
765 {
766 pDCE = (PDCE) pDCE->List.Flink;
767 continue;
768 }
769 if (Window == CurrentWindow || IntIsChildWindow(Window, CurrentWindow))
770 {
771 if (pDCE->DCXFlags & DCX_WINDOW)
772 {
773 DeltaX = CurrentWindow->Wnd->WindowRect.left - dc->ptlDCOrig.x;
774 DeltaY = CurrentWindow->Wnd->WindowRect.top - dc->ptlDCOrig.y;
775 dc->ptlDCOrig.x = CurrentWindow->Wnd->WindowRect.left;
776 dc->ptlDCOrig.y = CurrentWindow->Wnd->WindowRect.top;
777 }
778 else
779 {
780 DeltaX = CurrentWindow->Wnd->ClientRect.left - dc->ptlDCOrig.x;
781 DeltaY = CurrentWindow->Wnd->ClientRect.top - dc->ptlDCOrig.y;
782 dc->ptlDCOrig.x = CurrentWindow->Wnd->ClientRect.left;
783 dc->ptlDCOrig.y = CurrentWindow->Wnd->ClientRect.top;
784 }
785 if (NULL != dc->w.hClipRgn)
786 {
787 int FASTCALL CLIPPING_UpdateGCRegion(DC* Dc);
788 NtGdiOffsetRgn(dc->w.hClipRgn, DeltaX, DeltaY);
789 CLIPPING_UpdateGCRegion(dc);
790 }
791 if (NULL != pDCE->hClipRgn)
792 {
793 NtGdiOffsetRgn(pDCE->hClipRgn, DeltaX, DeltaY);
794 }
795 }
796 DC_UnlockDc(dc);
797
798 DceUpdateVisRgn(pDCE, CurrentWindow, pDCE->DCXFlags);
799
800 if (Window->hSelf != pDCE->hwndCurrent)
801 {
802 // IntEngWindowChanged(CurrentWindow, WOC_RGN_CLIENT);
803 // UserDerefObject(CurrentWindow);
804 }
805 }
806 pDCE =(PDCE) pDCE->List.Flink;
807 } while (pDCE != FirstDce);
808 }
809
810 HWND FASTCALL
811 IntWindowFromDC(HDC hDc)
812 {
813 DCE *Dce;
814 HWND Ret = NULL;
815 KeEnterCriticalRegion();
816 Dce = FirstDce;
817 do
818 {
819 if(Dce->hDC == hDc)
820 {
821 Ret = Dce->hwndCurrent;
822 break;
823 }
824 Dce = (PDCE)Dce->List.Flink;
825 } while (Dce != FirstDce);
826 KeLeaveCriticalRegion();
827 return Ret;
828 }
829
830 INT FASTCALL
831 UserReleaseDC(PWINDOW_OBJECT Window, HDC hDc, BOOL EndPaint)
832 {
833 PDCE dce;
834 INT nRet = 0;
835 BOOL Hit = FALSE;
836
837 DPRINT("%p %p\n", Window, hDc);
838 dce = FirstDce;
839 KeEnterCriticalRegion();
840 do
841 {
842 if(!dce) break;
843 if (dce->hDC == hDc)
844 {
845 Hit = TRUE;
846 break;
847 }
848
849 dce = (PDCE) dce->List.Flink;
850 }
851 while (dce != FirstDce );
852 KeLeaveCriticalRegion();
853
854 if ( Hit && (dce->DCXFlags & DCX_DCEBUSY))
855 {
856 nRet = DceReleaseDC(dce, EndPaint);
857 }
858
859 return nRet;
860 }
861
862 HDC FASTCALL
863 UserGetWindowDC(PWINDOW_OBJECT Wnd)
864 {
865 return UserGetDCEx(Wnd, 0, DCX_USESTYLE | DCX_WINDOW);
866 }
867
868 HDC STDCALL
869 NtUserGetDCEx(HWND hWnd OPTIONAL, HANDLE ClipRegion, ULONG Flags)
870 {
871 PWINDOW_OBJECT Wnd=NULL;
872 DECLARE_RETURN(HDC);
873
874 DPRINT("Enter NtUserGetDCEx\n");
875 UserEnterExclusive();
876
877 if (hWnd && !(Wnd = UserGetWindowObject(hWnd)))
878 {
879 RETURN(NULL);
880 }
881 RETURN( UserGetDCEx(Wnd, ClipRegion, Flags));
882
883 CLEANUP:
884 DPRINT("Leave NtUserGetDCEx, ret=%i\n",_ret_);
885 UserLeave();
886 END_CLEANUP;
887 }
888
889 /*
890 * NtUserGetWindowDC
891 *
892 * The NtUserGetWindowDC function retrieves the device context (DC) for the
893 * entire window, including title bar, menus, and scroll bars. A window device
894 * context permits painting anywhere in a window, because the origin of the
895 * device context is the upper-left corner of the window instead of the client
896 * area.
897 *
898 * Status
899 * @implemented
900 */
901 HDC STDCALL
902 NtUserGetWindowDC(HWND hWnd)
903 {
904 return NtUserGetDCEx(hWnd, 0, DCX_USESTYLE | DCX_WINDOW);
905 }
906
907 HDC STDCALL
908 NtUserGetDC(HWND hWnd)
909 {
910 DPRINT("NtUGetDC -> %x:%x\n", hWnd, !hWnd ? DCX_CACHE | DCX_WINDOW : DCX_USESTYLE );
911
912 return NtUserGetDCEx(hWnd, NULL, NULL == hWnd ? DCX_CACHE | DCX_WINDOW : DCX_USESTYLE);
913 }
914
915 /*!
916 * Select logical palette into device context.
917 * \param hDC handle to the device context
918 * \param hpal handle to the palette
919 * \param ForceBackground If this value is FALSE the logical palette will be copied to the device palette only when the applicatioon
920 * is in the foreground. If this value is TRUE then map the colors in the logical palette to the device
921 * palette colors in the best way.
922 * \return old palette
923 *
924 * \todo implement ForceBackground == TRUE
925 */
926 HPALETTE
927 STDCALL
928 NtUserSelectPalette(HDC hDC,
929 HPALETTE hpal,
930 BOOL ForceBackground)
931 {
932 HPALETTE oldPal;
933 UserEnterExclusive();
934 // Implement window checks
935 oldPal = GdiSelectPalette( hDC, hpal, ForceBackground);
936 UserLeave();
937 return oldPal;
938 }
939
940
941 /* EOF */