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