No need to stop APC when looping.
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / windc.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Window classes
24 * FILE: subsys/win32k/ntuser/class.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * REVISION HISTORY:
27 * 06-06-2001 CSH Created
28 */
29
30 /* INCLUDES ******************************************************************/
31
32 #include <w32k.h>
33
34 #define NDEBUG
35 #include <debug.h>
36
37 /* GLOBALS *******************************************************************/
38
39 /* NOTE - I think we should store this per window station (including gdi objects) */
40
41 static PDCE FirstDce = NULL;
42 static PDC defaultDCstate = NULL;
43 //static INT DCECount = 0;
44
45 #define DCX_CACHECOMPAREMASK (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | \
46 DCX_CACHE | DCX_WINDOW | DCX_PARENTCLIP)
47
48 /* FUNCTIONS *****************************************************************/
49
50 HDC FASTCALL
51 DceCreateDisplayDC(VOID)
52 {
53 HDC hDC;
54 UNICODE_STRING DriverName;
55 RtlInitUnicodeString(&DriverName, L"DISPLAY");
56 hDC = IntGdiCreateDC(&DriverName, NULL, NULL, NULL, FALSE);
57 return hDC;
58 }
59
60 VOID FASTCALL
61 DceInit(VOID)
62 {
63
64 }
65
66 static
67 HRGN FASTCALL
68 DceGetVisRgn(PWINDOW_OBJECT Window, ULONG Flags, HWND hWndChild, ULONG CFlags)
69 {
70 HRGN VisRgn;
71
72 VisRgn = VIS_ComputeVisibleRegion(Window,
73 0 == (Flags & DCX_WINDOW),
74 0 != (Flags & DCX_CLIPCHILDREN),
75 0 != (Flags & DCX_CLIPSIBLINGS));
76
77 if (VisRgn == NULL)
78 VisRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
79
80 return VisRgn;
81 }
82
83 /*
84 * NtUserGetWindowDC
85 *
86 * The NtUserGetWindowDC function retrieves the device context (DC) for the
87 * entire window, including title bar, menus, and scroll bars. A window device
88 * context permits painting anywhere in a window, because the origin of the
89 * device context is the upper-left corner of the window instead of the client
90 * area.
91 *
92 * Status
93 * @implemented
94 */
95
96 DWORD STDCALL
97 NtUserGetWindowDC(HWND hWnd)
98 {
99 return (DWORD)NtUserGetDCEx(hWnd, 0, DCX_USESTYLE | DCX_WINDOW);
100 }
101
102 DWORD FASTCALL
103 UserGetWindowDC(PWINDOW_OBJECT Wnd)
104 {
105 return (DWORD)UserGetDCEx(Wnd, 0, DCX_USESTYLE | DCX_WINDOW);
106 }
107
108 HDC STDCALL
109 NtUserGetDC(HWND hWnd)
110 {
111 return NtUserGetDCEx(hWnd, NULL, NULL == hWnd ? DCX_CACHE | DCX_WINDOW : DCX_USESTYLE);
112 }
113
114 PDCE FASTCALL
115 DceAllocDCE(PWINDOW_OBJECT Window OPTIONAL, DCE_TYPE Type)
116 {
117 PDCE pDce;
118
119 pDce = ExAllocatePoolWithTag(PagedPool, sizeof(DCE), TAG_PDCE);
120 if(!pDce)
121 return NULL;
122
123 pDce->hDC = DceCreateDisplayDC();
124 if(!pDce->hDC)
125 {
126 ExFreePoolWithTag(pDce, TAG_PDCE);
127 return NULL;
128 }
129 //
130 // If NULL, first time through! Build the default window dc!
131 //
132 if (NULL == defaultDCstate) // Ultra HAX! Dedicated to GvG!
133 { // This is a cheesy way to do this.
134 PDC dc = DC_LockDc ( pDce->hDC );
135 defaultDCstate = ExAllocatePoolWithTag(PagedPool, sizeof(DC), TAG_DC);
136 RtlZeroMemory(defaultDCstate, sizeof(DC));
137 IntGdiCopyToSaveState(dc, defaultDCstate);
138 DC_UnlockDc( dc );
139 }
140
141 pDce->hwndCurrent = (Window ? Window->hSelf : NULL);
142 pDce->hClipRgn = NULL;
143 pDce->pProcess = NULL;
144
145 KeEnterCriticalRegion();
146 pDce->next = FirstDce;
147 FirstDce = pDce;
148 KeLeaveCriticalRegion();
149
150 if (Type == DCE_WINDOW_DC) //Window DCE have ownership.
151 { // Process should already own it.
152 pDce->pProcess = PsGetCurrentProcess();
153 }
154 else
155 {
156 DC_SetOwnership(pDce->hDC, NULL); // This hDC is inaccessible!
157 }
158
159 if (Type != DCE_CACHE_DC)
160 {
161 pDce->DCXFlags = DCX_DCEBUSY;
162
163 if (Window)
164 {
165 if (Window->Style & WS_CLIPCHILDREN)
166 {
167 pDce->DCXFlags |= DCX_CLIPCHILDREN;
168 }
169 if (Window->Style & WS_CLIPSIBLINGS)
170 {
171 pDce->DCXFlags |= DCX_CLIPSIBLINGS;
172 }
173 }
174 }
175 else
176 {
177 pDce->DCXFlags = DCX_CACHE | DCX_DCEEMPTY;
178 }
179
180 return(pDce);
181 }
182
183 VOID static STDCALL
184 DceSetDrawable(PWINDOW_OBJECT Window OPTIONAL, HDC hDC, ULONG Flags,
185 BOOL SetClipOrigin)
186 {
187 DC *dc = DC_LockDc(hDC);
188 if(!dc)
189 return;
190
191 if (Window == NULL)
192 {
193 dc->w.DCOrgX = 0;
194 dc->w.DCOrgY = 0;
195 }
196 else
197 {
198 if (Flags & DCX_WINDOW)
199 {
200 dc->w.DCOrgX = Window->WindowRect.left;
201 dc->w.DCOrgY = Window->WindowRect.top;
202 }
203 else
204 {
205 dc->w.DCOrgX = Window->ClientRect.left;
206 dc->w.DCOrgY = Window->ClientRect.top;
207 }
208 }
209 DC_UnlockDc(dc);
210 }
211
212
213 static VOID FASTCALL
214 DceDeleteClipRgn(DCE* Dce)
215 {
216 Dce->DCXFlags &= ~(DCX_EXCLUDERGN | DCX_INTERSECTRGN);
217
218 if (Dce->DCXFlags & DCX_KEEPCLIPRGN )
219 {
220 Dce->DCXFlags &= ~DCX_KEEPCLIPRGN;
221 }
222 else if (Dce->hClipRgn != NULL)
223 {
224 NtGdiDeleteObject(Dce->hClipRgn);
225 }
226
227 Dce->hClipRgn = NULL;
228
229 /* make it dirty so that the vis rgn gets recomputed next time */
230 Dce->DCXFlags |= DCX_DCEDIRTY;
231 }
232
233 static INT FASTCALL
234 DceReleaseDC(DCE* dce, BOOL EndPaint)
235 {
236 if (DCX_DCEBUSY != (dce->DCXFlags & (DCX_DCEEMPTY | DCX_DCEBUSY)))
237 {
238 return 0;
239 }
240
241 /* restore previous visible region */
242
243 if ((dce->DCXFlags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN)) &&
244 ((dce->DCXFlags & DCX_CACHE) || EndPaint))
245 {
246 DceDeleteClipRgn(dce);
247 }
248
249 if (dce->DCXFlags & DCX_CACHE)
250 {
251 if (!(dce->DCXFlags & DCX_NORESETATTRS))
252 {
253 /* make the DC clean so that SetDCState doesn't try to update the vis rgn */
254 IntGdiSetHookFlags(dce->hDC, DCHF_VALIDATEVISRGN);
255
256 PDC dc = DC_LockDc ( dce->hDC );
257 IntGdiCopyFromSaveState(dc, defaultDCstate, dce->hDC ); // Was SetDCState.
258
259 dce->DCXFlags &= ~DCX_DCEBUSY;
260 if (dce->DCXFlags & DCX_DCEDIRTY)
261 {
262 /* don't keep around invalidated entries
263 * because SetDCState() disables hVisRgn updates
264 * by removing dirty bit. */
265 dce->hwndCurrent = 0;
266 dce->DCXFlags &= DCX_CACHE;
267 dce->DCXFlags |= DCX_DCEEMPTY;
268 }
269 }
270 }
271 return 1;
272 }
273
274 static VOID FASTCALL
275 DceUpdateVisRgn(DCE *Dce, PWINDOW_OBJECT Window, ULONG Flags)
276 {
277 HANDLE hRgnVisible = NULL;
278 ULONG DcxFlags;
279 PWINDOW_OBJECT DesktopWindow;
280
281 if (Flags & DCX_PARENTCLIP)
282 {
283 PWINDOW_OBJECT Parent;
284
285 Parent = Window->Parent;
286 if(!Parent)
287 {
288 hRgnVisible = NULL;
289 goto noparent;
290 }
291
292 if (Parent->Style & WS_CLIPSIBLINGS)
293 {
294 DcxFlags = DCX_CLIPSIBLINGS |
295 (Flags & ~(DCX_CLIPCHILDREN | DCX_WINDOW));
296 }
297 else
298 {
299 DcxFlags = Flags & ~(DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | DCX_WINDOW);
300 }
301 hRgnVisible = DceGetVisRgn(Parent, DcxFlags, Window->hSelf, Flags);
302 }
303 else if (Window == NULL)
304 {
305 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
306 if (NULL != DesktopWindow)
307 {
308 hRgnVisible = UnsafeIntCreateRectRgnIndirect(&DesktopWindow->WindowRect);
309 }
310 else
311 {
312 hRgnVisible = NULL;
313 }
314 }
315 else
316 {
317 hRgnVisible = DceGetVisRgn(Window, Flags, 0, 0);
318 }
319
320 noparent:
321 if (Flags & DCX_INTERSECTRGN)
322 {
323 if(Dce->hClipRgn != NULL)
324 {
325 NtGdiCombineRgn(hRgnVisible, hRgnVisible, Dce->hClipRgn, RGN_AND);
326 }
327 else
328 {
329 if(hRgnVisible != NULL)
330 {
331 NtGdiDeleteObject(hRgnVisible);
332 }
333 hRgnVisible = NtGdiCreateRectRgn(0, 0, 0, 0);
334 }
335 }
336
337 if (Flags & DCX_EXCLUDERGN && Dce->hClipRgn != NULL)
338 {
339 NtGdiCombineRgn(hRgnVisible, hRgnVisible, Dce->hClipRgn, RGN_DIFF);
340 }
341
342 Dce->DCXFlags &= ~DCX_DCEDIRTY;
343 IntGdiSelectVisRgn(Dce->hDC, hRgnVisible);
344
345 if (Window != NULL)
346 {
347 IntEngWindowChanged(Window, WOC_RGN_CLIENT);
348 }
349
350 if (hRgnVisible != NULL)
351 {
352 NtGdiDeleteObject(hRgnVisible);
353 }
354 }
355
356 HDC FASTCALL
357 UserGetDCEx(PWINDOW_OBJECT Window OPTIONAL, HANDLE ClipRegion, ULONG Flags)
358 {
359 PWINDOW_OBJECT Parent;
360 ULONG DcxFlags;
361 DCE* Dce;
362 BOOL UpdateVisRgn = TRUE;
363 BOOL UpdateClipOrigin = FALSE;
364
365 if (NULL == Window)
366 {
367 Flags &= ~DCX_USESTYLE;
368 }
369
370 if (NULL == Window || NULL == Window->Dce)
371 {
372 Flags |= DCX_CACHE;
373 }
374
375 if (Flags & DCX_USESTYLE)
376 {
377 Flags &= ~(DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS | DCX_PARENTCLIP);
378
379 if (Window->Style & WS_CLIPSIBLINGS)
380 {
381 Flags |= DCX_CLIPSIBLINGS;
382 }
383
384 if (!(Flags & DCX_WINDOW))
385 {
386 if (Window->Class->Style & CS_PARENTDC)
387 {
388 Flags |= DCX_PARENTCLIP;
389 }
390
391 if (Window->Style & WS_CLIPCHILDREN &&
392 !(Window->Style & WS_MINIMIZE))
393 {
394 Flags |= DCX_CLIPCHILDREN;
395 }
396 }
397 else
398 {
399 Flags |= DCX_CACHE;
400 }
401 }
402
403 if (Flags & DCX_NOCLIPCHILDREN)
404 {
405 Flags |= DCX_CACHE;
406 Flags &= ~(DCX_PARENTCLIP | DCX_CLIPCHILDREN);
407 }
408
409 if (Flags & DCX_WINDOW)
410 {
411 Flags = (Flags & ~DCX_CLIPCHILDREN) | DCX_CACHE;
412 }
413
414 Parent = (Window ? Window->Parent : NULL);
415
416 if (NULL == Window || !(Window->Style & WS_CHILD) || NULL == Parent)
417 {
418 Flags &= ~DCX_PARENTCLIP;
419 }
420 else if (Flags & DCX_PARENTCLIP)
421 {
422 Flags |= DCX_CACHE;
423 if ((Window->Style & WS_VISIBLE) &&
424 (Parent->Style & WS_VISIBLE))
425 {
426 Flags &= ~DCX_CLIPCHILDREN;
427 if (Parent->Style & WS_CLIPSIBLINGS)
428 {
429 Flags |= DCX_CLIPSIBLINGS;
430 }
431 }
432 }
433
434 DcxFlags = Flags & DCX_CACHECOMPAREMASK;
435
436 if (Flags & DCX_CACHE)
437 {
438 DCE* DceEmpty = NULL;
439 DCE* DceUnused = NULL;
440 KeEnterCriticalRegion();
441 for (Dce = FirstDce; Dce != NULL; Dce = Dce->next)
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
457 UpdateClipOrigin = TRUE;
458 break;
459 }
460 }
461 }
462 KeLeaveCriticalRegion();
463
464 if (Dce == NULL)
465 {
466 Dce = (DceEmpty == NULL) ? DceUnused : DceEmpty;
467 }
468
469 if (Dce == NULL)
470 {
471 Dce = DceAllocDCE(NULL, DCE_CACHE_DC);
472 }
473 }
474 else
475 {
476 Dce = Window->Dce;
477 if (NULL != Dce && Dce->hwndCurrent == (Window ? Window->hSelf : NULL))
478 {
479 UpdateVisRgn = FALSE; /* updated automatically, via DCHook() */
480 }
481 else
482 {
483 /* we should free dce->clip_rgn here, but Windows apparently doesn't */
484 Dce->DCXFlags &= ~(DCX_EXCLUDERGN | DCX_INTERSECTRGN);
485 Dce->hClipRgn = NULL;
486 }
487 #if 1 /* FIXME */
488 UpdateVisRgn = TRUE;
489 #endif
490
491 }
492
493 if (NULL == Dce)
494 {
495 return(NULL);
496 }
497
498 Dce->hwndCurrent = (Window ? Window->hSelf : NULL);
499 Dce->DCXFlags = Flags | DCX_DCEBUSY;
500
501 if (0 == (Flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN)) && NULL != ClipRegion)
502 {
503 if (Flags & DCX_KEEPCLIPRGN)
504 NtGdiDeleteObject(ClipRegion);
505 ClipRegion = NULL;
506 }
507
508 #if 0
509 if (NULL != Dce->hClipRgn)
510 {
511 DceDeleteClipRgn(Dce);
512 Dce->hClipRgn = NULL;
513 }
514 #endif
515
516 if (0 != (Flags & DCX_INTERSECTUPDATE) && NULL == ClipRegion)
517 {
518 Flags |= DCX_INTERSECTRGN | DCX_KEEPCLIPRGN;
519 Dce->DCXFlags |= DCX_INTERSECTRGN | DCX_KEEPCLIPRGN;
520 ClipRegion = Window->UpdateRegion;
521 }
522
523 if (ClipRegion == (HRGN) 1)
524 {
525 if (!(Flags & DCX_WINDOW))
526 {
527 Dce->hClipRgn = UnsafeIntCreateRectRgnIndirect(&Window->ClientRect);
528 }
529 else
530 {
531 Dce->hClipRgn = UnsafeIntCreateRectRgnIndirect(&Window->WindowRect);
532 }
533 }
534 else if (ClipRegion != NULL)
535 {
536 Dce->hClipRgn = ClipRegion;
537 }
538
539 DceSetDrawable(Window, Dce->hDC, Flags, UpdateClipOrigin);
540
541 // if (UpdateVisRgn)
542 {
543 DceUpdateVisRgn(Dce, Window, Flags);
544 }
545
546 return(Dce->hDC);
547 }
548
549
550
551 HDC STDCALL
552 NtUserGetDCEx(HWND hWnd OPTIONAL, HANDLE ClipRegion, ULONG Flags)
553 {
554 PWINDOW_OBJECT Wnd=NULL;
555 DECLARE_RETURN(HDC);
556
557 DPRINT("Enter NtUserGetDCEx\n");
558 UserEnterExclusive();
559
560 if (hWnd && !(Wnd = UserGetWindowObject(hWnd)))
561 {
562 RETURN(NULL);
563 }
564
565 RETURN( UserGetDCEx(Wnd, ClipRegion, Flags));
566
567 CLEANUP:
568 DPRINT("Leave NtUserGetDCEx, ret=%i\n",_ret_);
569 UserLeave();
570 END_CLEANUP;
571 }
572
573
574 BOOL FASTCALL
575 DCE_Cleanup(PDCE pDce)
576 {
577 PDCE PrevInList;
578 KeEnterCriticalRegion();
579 if (pDce == FirstDce)
580 {
581 FirstDce = pDce->next;
582 PrevInList = pDce;
583 }
584 else
585 {
586 for (PrevInList = FirstDce; NULL != PrevInList; PrevInList = PrevInList->next)
587 {
588 if (pDce == PrevInList->next)
589 {
590 PrevInList->next = pDce->next;
591 break;
592 }
593 }
594 assert(NULL != PrevInList);
595 }
596 KeLeaveCriticalRegion();
597 return NULL != PrevInList;
598 }
599
600 HWND FASTCALL
601 IntWindowFromDC(HDC hDc)
602 {
603 DCE *Dce;
604 HWND Ret = NULL;
605 KeEnterCriticalRegion();
606 for (Dce = FirstDce; Dce != NULL; Dce = Dce->next)
607 {
608 if(Dce->hDC == hDc)
609 {
610 Ret = Dce->hwndCurrent;
611 break;
612 }
613 }
614 KeLeaveCriticalRegion();
615 return Ret;
616 }
617
618
619 INT FASTCALL
620 UserReleaseDC(PWINDOW_OBJECT Window, HDC hDc, BOOL EndPaint)
621 {
622 DCE *dce;
623 INT nRet = 0;
624
625 dce = FirstDce;
626
627 DPRINT("%p %p\n", Window, hDc);
628 KeEnterCriticalRegion();
629 while (dce && (dce->hDC != hDc))
630 {
631 dce = dce->next;
632 }
633 KeLeaveCriticalRegion();
634 if (dce && (dce->DCXFlags & DCX_DCEBUSY))
635 {
636 nRet = DceReleaseDC(dce, EndPaint);
637 }
638
639 return nRet;
640 }
641
642
643 /***********************************************************************
644 * DceFreeDCE
645 */
646 PDCE FASTCALL
647 DceFreeDCE(PDCE pdce, BOOLEAN Force)
648 {
649 DCE *ret;
650
651 if (NULL == pdce)
652 {
653 return NULL;
654 }
655
656 ret = pdce->next;
657
658 #if 0 /* FIXME */
659
660 SetDCHook(pdce->hDC, NULL, 0L);
661 #endif
662
663 if(Force && !GDIOBJ_OwnedByCurrentProcess(GdiHandleTable, pdce->hDC))
664 {
665 DPRINT1("Change ownership for DCE!\n");
666 DC_SetOwnership( pdce->hDC, PsGetCurrentProcess());
667 }
668
669 NtGdiDeleteObjectApp(pdce->hDC);
670 if (pdce->hClipRgn && ! (pdce->DCXFlags & DCX_KEEPCLIPRGN))
671 {
672 NtGdiDeleteObject(pdce->hClipRgn);
673 }
674
675 DCE_Cleanup(pdce);
676 ExFreePoolWithTag(pdce, TAG_PDCE);
677
678 if (FirstDce == NULL)
679 {
680 ExFreePoolWithTag(defaultDCstate, TAG_DC);
681 defaultDCstate = NULL;
682 }
683 return ret;
684 }
685
686 /***********************************************************************
687 * DceFreeWindowDCE
688 *
689 * Remove owned DCE and reset unreleased cache DCEs.
690 */
691 void FASTCALL
692 DceFreeWindowDCE(PWINDOW_OBJECT Window)
693 {
694 DCE *pDCE;
695
696 pDCE = FirstDce;
697 KeEnterCriticalRegion();
698 while (pDCE)
699 {
700 if (pDCE->hwndCurrent == Window->hSelf)
701 {
702 if (pDCE == Window->Dce) /* owned or Class DCE*/
703 {
704 if (Window->Class->Style & CS_OWNDC) /* owned DCE*/
705 {
706 pDCE = DceFreeDCE(pDCE, FALSE);
707 Window->Dce = NULL;
708 continue;
709 }
710 else if (pDCE->DCXFlags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN)) /* Class DCE*/
711 {
712 DceDeleteClipRgn(pDCE);
713 pDCE->hwndCurrent = 0;
714 }
715 }
716 else
717 {
718 if (pDCE->DCXFlags & DCX_DCEBUSY) /* shared cache DCE */
719 {
720 /* FIXME: AFAICS we are doing the right thing here so
721 * this should be a DPRINT. But this is best left as an ERR
722 * because the 'application error' is likely to come from
723 * another part of Wine (i.e. it's our fault after all).
724 * We should change this to DPRINT when ReactOS is more stable
725 * (for 1.0?).
726 */
727 DPRINT1("[%p] GetDC() without ReleaseDC()!\n", Window->hSelf);
728 DceReleaseDC(pDCE, FALSE);
729 }
730
731 pDCE->DCXFlags &= DCX_CACHE;
732 pDCE->DCXFlags |= DCX_DCEEMPTY;
733 pDCE->hwndCurrent = 0;
734 }
735 }
736 pDCE = pDCE->next;
737 }
738 KeLeaveCriticalRegion();
739 }
740
741 VOID FASTCALL
742 DceEmptyCache()
743 {
744 while (FirstDce != NULL)
745 {
746 FirstDce = DceFreeDCE(FirstDce, TRUE);
747 }
748 }
749
750 VOID FASTCALL
751 DceResetActiveDCEs(PWINDOW_OBJECT Window)
752 {
753 DCE *pDCE;
754 PDC dc;
755 PWINDOW_OBJECT CurrentWindow;
756 INT DeltaX;
757 INT DeltaY;
758
759 if (NULL == Window)
760 {
761 return;
762 }
763 pDCE = FirstDce;
764 while (pDCE)
765 {
766 if (0 == (pDCE->DCXFlags & DCX_DCEEMPTY))
767 {
768 if (Window->hSelf == pDCE->hwndCurrent)
769 {
770 CurrentWindow = Window;
771 }
772 else
773 {
774 CurrentWindow = UserGetWindowObject(pDCE->hwndCurrent);
775 if (NULL == CurrentWindow)
776 {
777 pDCE = pDCE->next;
778 continue;
779 }
780 }
781
782 dc = DC_LockDc(pDCE->hDC);
783 if (dc == NULL)
784 {
785 // if (Window->hSelf != pDCE->hwndCurrent)
786 // {
787 // UserDerefObject(CurrentWindow);
788 // }
789 pDCE = pDCE->next;
790 continue;
791 }
792 if (Window == CurrentWindow || IntIsChildWindow(Window, CurrentWindow))
793 {
794 if (pDCE->DCXFlags & DCX_WINDOW)
795 {
796 DeltaX = CurrentWindow->WindowRect.left - dc->w.DCOrgX;
797 DeltaY = CurrentWindow->WindowRect.top - dc->w.DCOrgY;
798 dc->w.DCOrgX = CurrentWindow->WindowRect.left;
799 dc->w.DCOrgY = CurrentWindow->WindowRect.top;
800 }
801 else
802 {
803 DeltaX = CurrentWindow->ClientRect.left - dc->w.DCOrgX;
804 DeltaY = CurrentWindow->ClientRect.top - dc->w.DCOrgY;
805 dc->w.DCOrgX = CurrentWindow->ClientRect.left;
806 dc->w.DCOrgY = CurrentWindow->ClientRect.top;
807 }
808 if (NULL != dc->w.hClipRgn)
809 {
810 int FASTCALL CLIPPING_UpdateGCRegion(DC* Dc);
811 NtGdiOffsetRgn(dc->w.hClipRgn, DeltaX, DeltaY);
812 CLIPPING_UpdateGCRegion(dc);
813 }
814 if (NULL != pDCE->hClipRgn)
815 {
816 NtGdiOffsetRgn(pDCE->hClipRgn, DeltaX, DeltaY);
817 }
818 }
819 DC_UnlockDc(dc);
820
821 DceUpdateVisRgn(pDCE, CurrentWindow, pDCE->DCXFlags);
822
823 if (Window->hSelf != pDCE->hwndCurrent)
824 {
825 // IntEngWindowChanged(CurrentWindow, WOC_RGN_CLIENT);
826 // UserDerefObject(CurrentWindow);
827 }
828 }
829 pDCE = pDCE->next;
830 }
831 }
832
833
834 #define COPY_DEVMODE_VALUE_TO_CALLER(dst, src, member) \
835 Status = MmCopyToCaller(&(dst)->member, &(src)->member, sizeof ((src)->member)); \
836 if (!NT_SUCCESS(Status)) \
837 { \
838 SetLastNtError(Status); \
839 ExFreePool(src); \
840 return FALSE; \
841 }
842
843 BOOL
844 STDCALL
845 NtUserEnumDisplaySettings(
846 PUNICODE_STRING lpszDeviceName,
847 DWORD iModeNum,
848 LPDEVMODEW lpDevMode, /* FIXME is this correct? */
849 DWORD dwFlags )
850 {
851 NTSTATUS Status;
852 LPDEVMODEW pSafeDevMode;
853 PUNICODE_STRING pSafeDeviceName = NULL;
854 UNICODE_STRING SafeDeviceName;
855 USHORT Size = 0, ExtraSize = 0;
856
857 /* Copy the devmode */
858 Status = MmCopyFromCaller(&Size, &lpDevMode->dmSize, sizeof (Size));
859 if (!NT_SUCCESS(Status))
860 {
861 SetLastNtError(Status);
862 return FALSE;
863 }
864 Status = MmCopyFromCaller(&ExtraSize, &lpDevMode->dmDriverExtra, sizeof (ExtraSize));
865 if (!NT_SUCCESS(Status))
866 {
867 SetLastNtError(Status);
868 return FALSE;
869 }
870 pSafeDevMode = ExAllocatePool(PagedPool, Size + ExtraSize);
871 if (pSafeDevMode == NULL)
872 {
873 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
874 return FALSE;
875 }
876 pSafeDevMode->dmSize = Size;
877 pSafeDevMode->dmDriverExtra = ExtraSize;
878
879 /* Copy the device name */
880 if (lpszDeviceName != NULL)
881 {
882 Status = IntSafeCopyUnicodeString(&SafeDeviceName, lpszDeviceName);
883 if (!NT_SUCCESS(Status))
884 {
885 ExFreePool(pSafeDevMode);
886 SetLastNtError(Status);
887 return FALSE;
888 }
889 pSafeDeviceName = &SafeDeviceName;
890 }
891
892 /* Call internal function */
893 if (!IntEnumDisplaySettings(pSafeDeviceName, iModeNum, pSafeDevMode, dwFlags))
894 {
895 if (pSafeDeviceName != NULL)
896 RtlFreeUnicodeString(pSafeDeviceName);
897 ExFreePool(pSafeDevMode);
898 return FALSE;
899 }
900 if (pSafeDeviceName != NULL)
901 RtlFreeUnicodeString(pSafeDeviceName);
902
903 /* Copy some information back */
904 COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode, pSafeDevMode, dmPelsWidth);
905 COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode, pSafeDevMode, dmPelsHeight);
906 COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode, pSafeDevMode, dmBitsPerPel);
907 COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode, pSafeDevMode, dmDisplayFrequency);
908 COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode, pSafeDevMode, dmDisplayFlags);
909
910 /* output private/extra driver data */
911 if (ExtraSize > 0)
912 {
913 Status = MmCopyToCaller((PCHAR)lpDevMode + Size, (PCHAR)pSafeDevMode + Size, ExtraSize);
914 if (!NT_SUCCESS(Status))
915 {
916 SetLastNtError(Status);
917 ExFreePool(pSafeDevMode);
918 return FALSE;
919 }
920 }
921
922 ExFreePool(pSafeDevMode);
923 return TRUE;
924 }
925
926 #undef COPY_DEVMODE_VALUE_TO_CALLER
927
928
929 LONG
930 STDCALL
931 NtUserChangeDisplaySettings(
932 PUNICODE_STRING lpszDeviceName,
933 LPDEVMODEW lpDevMode,
934 HWND hwnd,
935 DWORD dwflags,
936 LPVOID lParam)
937 {
938 NTSTATUS Status;
939 DEVMODEW DevMode;
940 PUNICODE_STRING pSafeDeviceName = NULL;
941 UNICODE_STRING SafeDeviceName;
942 LONG Ret;
943
944 /* Check arguments */
945 #ifdef CDS_VIDEOPARAMETERS
946
947 if (dwflags != CDS_VIDEOPARAMETERS && lParam != NULL)
948 #else
949
950 if (lParam != NULL)
951 #endif
952
953 {
954 SetLastWin32Error(ERROR_INVALID_PARAMETER);
955 return DISP_CHANGE_BADPARAM;
956 }
957 if (hwnd != NULL)
958 {
959 SetLastWin32Error(ERROR_INVALID_PARAMETER);
960 return DISP_CHANGE_BADPARAM;
961 }
962
963 /* Copy devmode */
964 Status = MmCopyFromCaller(&DevMode.dmSize, &lpDevMode->dmSize, sizeof (DevMode.dmSize));
965 if (!NT_SUCCESS(Status))
966 {
967 SetLastNtError(Status);
968 return DISP_CHANGE_BADPARAM;
969 }
970 DevMode.dmSize = min(sizeof (DevMode), DevMode.dmSize);
971 Status = MmCopyFromCaller(&DevMode, lpDevMode, DevMode.dmSize);
972 if (!NT_SUCCESS(Status))
973 {
974 SetLastNtError(Status);
975 return DISP_CHANGE_BADPARAM;
976 }
977 if (DevMode.dmDriverExtra > 0)
978 {
979 DbgPrint("(%s:%i) WIN32K: %s lpDevMode->dmDriverExtra is IGNORED!\n", __FILE__, __LINE__, __FUNCTION__);
980 DevMode.dmDriverExtra = 0;
981 }
982
983 /* Copy the device name */
984 if (lpszDeviceName != NULL)
985 {
986 Status = IntSafeCopyUnicodeString(&SafeDeviceName, lpszDeviceName);
987 if (!NT_SUCCESS(Status))
988 {
989 SetLastNtError(Status);
990 return DISP_CHANGE_BADPARAM;
991 }
992 pSafeDeviceName = &SafeDeviceName;
993 }
994
995 /* Call internal function */
996 Ret = IntChangeDisplaySettings(pSafeDeviceName, &DevMode, dwflags, lParam);
997
998 if (pSafeDeviceName != NULL)
999 RtlFreeUnicodeString(pSafeDeviceName);
1000
1001 return Ret;
1002 }
1003
1004 /*!
1005 * Select logical palette into device context.
1006 * \param hDC handle to the device context
1007 * \param hpal handle to the palette
1008 * \param ForceBackground If this value is FALSE the logical palette will be copied to the device palette only when the applicatioon
1009 * is in the foreground. If this value is TRUE then map the colors in the logical palette to the device
1010 * palette colors in the best way.
1011 * \return old palette
1012 *
1013 * \todo implement ForceBackground == TRUE
1014 */
1015 HPALETTE STDCALL NtUserSelectPalette(HDC hDC,
1016 HPALETTE hpal,
1017 BOOL ForceBackground)
1018 {
1019 PDC dc;
1020 HPALETTE oldPal = NULL;
1021 PPALGDI PalGDI;
1022
1023 // FIXME: mark the palette as a [fore\back]ground pal
1024 dc = DC_LockDc(hDC);
1025 if (NULL != dc)
1026 {
1027 /* Check if this is a valid palette handle */
1028 PalGDI = PALETTE_LockPalette(hpal);
1029 if (NULL != PalGDI)
1030 {
1031 /* Is this a valid palette for this depth? */
1032 if ((dc->w.bitsPerPixel <= 8 && PAL_INDEXED == PalGDI->Mode)
1033 || (8 < dc->w.bitsPerPixel && PAL_INDEXED != PalGDI->Mode))
1034 {
1035 PALETTE_UnlockPalette(PalGDI);
1036 oldPal = dc->w.hPalette;
1037 dc->w.hPalette = hpal;
1038 }
1039 else if (8 < dc->w.bitsPerPixel && PAL_INDEXED == PalGDI->Mode)
1040 {
1041 PALETTE_UnlockPalette(PalGDI);
1042 oldPal = dc->PalIndexed;
1043 dc->PalIndexed = hpal;
1044 }
1045 else
1046 {
1047 PALETTE_UnlockPalette(PalGDI);
1048 oldPal = NULL;
1049 }
1050 }
1051 else
1052 {
1053 oldPal = NULL;
1054 }
1055 DC_UnlockDc(dc);
1056 }
1057
1058 return oldPal;
1059 }
1060
1061
1062 /* EOF */