rename NtGdiSetHookFlags into IntGdiSetHookFlags
[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 HDC 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 == defaultDCstate) // Ultra HAX! Dedicated to GvG!
131 { // This is a cheesy way to do this.
132 // But, due to the right way of creating gdi handles there is no choice.
133 defaultDCstate = IntGdiGetDCState(pDce->hDC);
134 DC_SetOwnership( defaultDCstate, NULL);
135 }
136
137 pDce->hwndCurrent = (Window ? Window->hSelf : NULL);
138 pDce->hClipRgn = NULL;
139 pDce->pProcess = NULL;
140
141 pDce->next = FirstDce;
142 FirstDce = pDce;
143
144 if (Type == DCE_WINDOW_DC) //Window DCE have ownership.
145 {
146 DC_SetOwnership(pDce->hDC, PsGetCurrentProcess());
147 pDce->pProcess = PsGetCurrentProcess();
148 }
149 else
150 {
151 DC_SetOwnership(pDce->hDC, NULL); // This hDC is inaccessible!
152 }
153
154 if (Type != DCE_CACHE_DC)
155 {
156 pDce->DCXFlags = DCX_DCEBUSY;
157
158 if (Window)
159 {
160 if (Window->Style & WS_CLIPCHILDREN)
161 {
162 pDce->DCXFlags |= DCX_CLIPCHILDREN;
163 }
164 if (Window->Style & WS_CLIPSIBLINGS)
165 {
166 pDce->DCXFlags |= DCX_CLIPSIBLINGS;
167 }
168 }
169 }
170 else
171 {
172 pDce->DCXFlags = DCX_CACHE | DCX_DCEEMPTY;
173 }
174
175 return(pDce);
176 }
177
178 VOID static STDCALL
179 DceSetDrawable(PWINDOW_OBJECT Window OPTIONAL, HDC hDC, ULONG Flags,
180 BOOL SetClipOrigin)
181 {
182 DC *dc = DC_LockDc(hDC);
183 if(!dc)
184 return;
185
186 if (Window == NULL)
187 {
188 dc->w.DCOrgX = 0;
189 dc->w.DCOrgY = 0;
190 }
191 else
192 {
193 if (Flags & DCX_WINDOW)
194 {
195 dc->w.DCOrgX = Window->WindowRect.left;
196 dc->w.DCOrgY = Window->WindowRect.top;
197 }
198 else
199 {
200 dc->w.DCOrgX = Window->ClientRect.left;
201 dc->w.DCOrgY = Window->ClientRect.top;
202 }
203 }
204 DC_UnlockDc(dc);
205 }
206
207
208 static VOID FASTCALL
209 DceDeleteClipRgn(DCE* Dce)
210 {
211 Dce->DCXFlags &= ~(DCX_EXCLUDERGN | DCX_INTERSECTRGN);
212
213 if (Dce->DCXFlags & DCX_KEEPCLIPRGN )
214 {
215 Dce->DCXFlags &= ~DCX_KEEPCLIPRGN;
216 }
217 else if (Dce->hClipRgn != NULL)
218 {
219 NtGdiDeleteObject(Dce->hClipRgn);
220 }
221
222 Dce->hClipRgn = NULL;
223
224 /* make it dirty so that the vis rgn gets recomputed next time */
225 Dce->DCXFlags |= DCX_DCEDIRTY;
226 }
227
228 static INT FASTCALL
229 DceReleaseDC(DCE* dce, BOOL EndPaint)
230 {
231 if (DCX_DCEBUSY != (dce->DCXFlags & (DCX_DCEEMPTY | DCX_DCEBUSY)))
232 {
233 return 0;
234 }
235
236 /* restore previous visible region */
237
238 if ((dce->DCXFlags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN)) &&
239 ((dce->DCXFlags & DCX_CACHE) || EndPaint))
240 {
241 DceDeleteClipRgn(dce);
242 }
243
244 if (dce->DCXFlags & DCX_CACHE)
245 {
246 /* make the DC clean so that SetDCState doesn't try to update the vis rgn */
247 IntGdiSetHookFlags(dce->hDC, DCHF_VALIDATEVISRGN);
248
249 if( dce->pProcess ) // Attempt to fix Dc_Attr problem.
250 DC_SetOwnership( defaultDCstate, dce->pProcess);
251 else
252 DC_SetOwnership( defaultDCstate, PsGetCurrentProcess());
253
254 NtGdiSetDCState(dce->hDC, defaultDCstate);
255 DC_SetOwnership( defaultDCstate, NULL); // Return default dc state to inaccessible mode.
256
257 dce->DCXFlags &= ~DCX_DCEBUSY;
258 if (dce->DCXFlags & DCX_DCEDIRTY)
259 {
260 /* don't keep around invalidated entries
261 * because SetDCState() disables hVisRgn updates
262 * by removing dirty bit. */
263 dce->hwndCurrent = 0;
264 dce->DCXFlags &= DCX_CACHE;
265 dce->DCXFlags |= DCX_DCEEMPTY;
266 }
267 }
268 return 1;
269 }
270
271 static VOID FASTCALL
272 DceUpdateVisRgn(DCE *Dce, PWINDOW_OBJECT Window, ULONG Flags)
273 {
274 HANDLE hRgnVisible = NULL;
275 ULONG DcxFlags;
276 PWINDOW_OBJECT DesktopWindow;
277
278 if (Flags & DCX_PARENTCLIP)
279 {
280 PWINDOW_OBJECT Parent;
281
282 Parent = Window->Parent;
283 if(!Parent)
284 {
285 hRgnVisible = NULL;
286 goto noparent;
287 }
288
289 if (Parent->Style & WS_CLIPSIBLINGS)
290 {
291 DcxFlags = DCX_CLIPSIBLINGS |
292 (Flags & ~(DCX_CLIPCHILDREN | DCX_WINDOW));
293 }
294 else
295 {
296 DcxFlags = Flags & ~(DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | DCX_WINDOW);
297 }
298 hRgnVisible = DceGetVisRgn(Parent, DcxFlags, Window->hSelf, Flags);
299 }
300 else if (Window == NULL)
301 {
302 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
303 if (NULL != DesktopWindow)
304 {
305 hRgnVisible = UnsafeIntCreateRectRgnIndirect(&DesktopWindow->WindowRect);
306 }
307 else
308 {
309 hRgnVisible = NULL;
310 }
311 }
312 else
313 {
314 hRgnVisible = DceGetVisRgn(Window, Flags, 0, 0);
315 }
316
317 noparent:
318 if (Flags & DCX_INTERSECTRGN)
319 {
320 if(Dce->hClipRgn != NULL)
321 {
322 NtGdiCombineRgn(hRgnVisible, hRgnVisible, Dce->hClipRgn, RGN_AND);
323 }
324 else
325 {
326 if(hRgnVisible != NULL)
327 {
328 NtGdiDeleteObject(hRgnVisible);
329 }
330 hRgnVisible = NtGdiCreateRectRgn(0, 0, 0, 0);
331 }
332 }
333
334 if (Flags & DCX_EXCLUDERGN && Dce->hClipRgn != NULL)
335 {
336 NtGdiCombineRgn(hRgnVisible, hRgnVisible, Dce->hClipRgn, RGN_DIFF);
337 }
338
339 Dce->DCXFlags &= ~DCX_DCEDIRTY;
340 IntGdiSelectVisRgn(Dce->hDC, hRgnVisible);
341
342 if (Window != NULL)
343 {
344 IntEngWindowChanged(Window, WOC_RGN_CLIENT);
345 }
346
347 if (hRgnVisible != NULL)
348 {
349 NtGdiDeleteObject(hRgnVisible);
350 }
351 }
352
353 HDC FASTCALL
354 UserGetDCEx(PWINDOW_OBJECT Window OPTIONAL, HANDLE ClipRegion, ULONG Flags)
355 {
356 PWINDOW_OBJECT Parent;
357 ULONG DcxFlags;
358 DCE* Dce;
359 BOOL UpdateVisRgn = TRUE;
360 BOOL UpdateClipOrigin = FALSE;
361
362 if (NULL == Window)
363 {
364 Flags &= ~DCX_USESTYLE;
365 }
366
367 if (NULL == Window || NULL == Window->Dce)
368 {
369 Flags |= DCX_CACHE;
370 }
371
372 if (Flags & DCX_USESTYLE)
373 {
374 Flags &= ~(DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS | DCX_PARENTCLIP);
375
376 if (Window->Style & WS_CLIPSIBLINGS)
377 {
378 Flags |= DCX_CLIPSIBLINGS;
379 }
380
381 if (!(Flags & DCX_WINDOW))
382 {
383 if (Window->Class->Style & CS_PARENTDC)
384 {
385 Flags |= DCX_PARENTCLIP;
386 }
387
388 if (Window->Style & WS_CLIPCHILDREN &&
389 !(Window->Style & WS_MINIMIZE))
390 {
391 Flags |= DCX_CLIPCHILDREN;
392 }
393 }
394 else
395 {
396 Flags |= DCX_CACHE;
397 }
398 }
399
400 if (Flags & DCX_NOCLIPCHILDREN)
401 {
402 Flags |= DCX_CACHE;
403 Flags |= ~(DCX_PARENTCLIP | DCX_CLIPCHILDREN);
404 }
405
406 if (Flags & DCX_WINDOW)
407 {
408 Flags = (Flags & ~DCX_CLIPCHILDREN) | DCX_CACHE;
409 }
410
411 Parent = (Window ? Window->Parent : NULL);
412
413 if (NULL == Window || !(Window->Style & WS_CHILD) || NULL == Parent)
414 {
415 Flags &= ~DCX_PARENTCLIP;
416 }
417 else if (Flags & DCX_PARENTCLIP)
418 {
419 Flags |= DCX_CACHE;
420 if ((Window->Style & WS_VISIBLE) &&
421 (Parent->Style & WS_VISIBLE))
422 {
423 Flags &= ~DCX_CLIPCHILDREN;
424 if (Parent->Style & WS_CLIPSIBLINGS)
425 {
426 Flags |= DCX_CLIPSIBLINGS;
427 }
428 }
429 }
430
431 DcxFlags = Flags & DCX_CACHECOMPAREMASK;
432
433 if (Flags & DCX_CACHE)
434 {
435 DCE* DceEmpty = NULL;
436 DCE* DceUnused = NULL;
437
438 for (Dce = FirstDce; Dce != NULL; Dce = Dce->next)
439 {
440 if ((Dce->DCXFlags & (DCX_CACHE | DCX_DCEBUSY)) == DCX_CACHE)
441 {
442 DceUnused = Dce;
443 if (Dce->DCXFlags & DCX_DCEEMPTY)
444 {
445 DceEmpty = Dce;
446 }
447 else if (Dce->hwndCurrent == (Window ? Window->hSelf : NULL) &&
448 ((Dce->DCXFlags & DCX_CACHECOMPAREMASK) == DcxFlags))
449 {
450 #if 0 /* FIXME */
451 UpdateVisRgn = FALSE;
452 #endif
453
454 UpdateClipOrigin = TRUE;
455 break;
456 }
457 }
458 }
459
460
461 if (Dce == NULL)
462 {
463 Dce = (DceEmpty == NULL) ? DceUnused : DceEmpty;
464 }
465
466 if (Dce == NULL)
467 {
468 Dce = DceAllocDCE(NULL, DCE_CACHE_DC);
469 }
470 }
471 else
472 {
473 Dce = Window->Dce;
474 if (NULL != Dce && Dce->hwndCurrent == (Window ? Window->hSelf : NULL))
475 {
476 UpdateVisRgn = FALSE; /* updated automatically, via DCHook() */
477 }
478 #if 1 /* FIXME */
479 UpdateVisRgn = TRUE;
480 #endif
481
482 }
483
484 if (NULL == Dce)
485 {
486 return(NULL);
487 }
488
489 Dce->hwndCurrent = (Window ? Window->hSelf : NULL);
490 Dce->DCXFlags = Flags | DCX_DCEBUSY;
491
492 if (0 == (Flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN)) && NULL != ClipRegion)
493 {
494 if (Flags & DCX_KEEPCLIPRGN)
495 NtGdiDeleteObject(ClipRegion);
496 ClipRegion = NULL;
497 }
498
499 #if 0
500 if (NULL != Dce->hClipRgn)
501 {
502 DceDeleteClipRgn(Dce);
503 Dce->hClipRgn = NULL;
504 }
505 #endif
506
507 if (0 != (Flags & DCX_INTERSECTUPDATE) && NULL == ClipRegion)
508 {
509 Flags |= DCX_INTERSECTRGN | DCX_KEEPCLIPRGN;
510 Dce->DCXFlags |= DCX_INTERSECTRGN | DCX_KEEPCLIPRGN;
511 ClipRegion = Window->UpdateRegion;
512 }
513
514 if (ClipRegion == (HRGN) 1)
515 {
516 if (!(Flags & DCX_WINDOW))
517 {
518 Dce->hClipRgn = UnsafeIntCreateRectRgnIndirect(&Window->ClientRect);
519 }
520 else
521 {
522 Dce->hClipRgn = UnsafeIntCreateRectRgnIndirect(&Window->WindowRect);
523 }
524 }
525 else if (ClipRegion != NULL)
526 {
527 Dce->hClipRgn = ClipRegion;
528 }
529
530 DceSetDrawable(Window, Dce->hDC, Flags, UpdateClipOrigin);
531
532 // if (UpdateVisRgn)
533 {
534 DceUpdateVisRgn(Dce, Window, Flags);
535 }
536
537 return(Dce->hDC);
538 }
539
540
541
542 HDC STDCALL
543 NtUserGetDCEx(HWND hWnd OPTIONAL, HANDLE ClipRegion, ULONG Flags)
544 {
545 PWINDOW_OBJECT Wnd=NULL;
546 DECLARE_RETURN(HDC);
547
548 DPRINT("Enter NtUserGetDCEx\n");
549 UserEnterExclusive();
550
551 if (hWnd && !(Wnd = UserGetWindowObject(hWnd)))
552 {
553 RETURN(NULL);
554 }
555
556 RETURN( UserGetDCEx(Wnd, ClipRegion, Flags));
557
558 CLEANUP:
559 DPRINT("Leave NtUserGetDCEx, ret=%i\n",_ret_);
560 UserLeave();
561 END_CLEANUP;
562 }
563
564
565 BOOL FASTCALL
566 DCE_Cleanup(PDCE pDce)
567 {
568 PDCE PrevInList;
569
570 if (pDce == FirstDce)
571 {
572 FirstDce = pDce->next;
573 PrevInList = pDce;
574 }
575 else
576 {
577 for (PrevInList = FirstDce; NULL != PrevInList; PrevInList = PrevInList->next)
578 {
579 if (pDce == PrevInList->next)
580 {
581 PrevInList->next = pDce->next;
582 break;
583 }
584 }
585 assert(NULL != PrevInList);
586 }
587
588 return NULL != PrevInList;
589 }
590
591 HWND FASTCALL
592 IntWindowFromDC(HDC hDc)
593 {
594 DCE *Dce;
595
596 for (Dce = FirstDce; Dce != NULL; Dce = Dce->next)
597 {
598 if(Dce->hDC == hDc)
599 {
600 return Dce->hwndCurrent;
601 }
602 }
603
604 return 0;
605 }
606
607
608 INT FASTCALL
609 UserReleaseDC(PWINDOW_OBJECT Window, HDC hDc, BOOL EndPaint)
610 {
611 DCE *dce;
612 INT nRet = 0;
613
614 dce = FirstDce;
615
616 DPRINT("%p %p\n", Window, hDc);
617
618 while (dce && (dce->hDC != hDc))
619 {
620 dce = dce->next;
621 }
622
623 if (dce && (dce->DCXFlags & DCX_DCEBUSY))
624 {
625 nRet = DceReleaseDC(dce, EndPaint);
626 }
627
628 return nRet;
629 }
630
631
632 // Win 3.1 throw back, hWnd should be ignored and not used.
633 // Replace with NtUserCallOneParam ((DWORD) hDC, ONEPARAM_ROUTINE_RELEASEDC);
634 INT STDCALL
635 NtUserReleaseDC(HWND hWnd, HDC hDc)
636 {
637 DECLARE_RETURN(INT);
638
639 DPRINT("Enter NtUserReleaseDC\n");
640 UserEnterExclusive();
641
642 RETURN(UserReleaseDC(NULL, hDc, FALSE));
643
644 CLEANUP:
645 DPRINT("Leave NtUserReleaseDC, ret=%i\n",_ret_);
646 UserLeave();
647 END_CLEANUP;
648 }
649
650 /***********************************************************************
651 * DceFreeDCE
652 */
653 PDCE FASTCALL
654 DceFreeDCE(PDCE pdce, BOOLEAN Force)
655 {
656 DCE *ret;
657
658 if (NULL == pdce)
659 {
660 return NULL;
661 }
662
663 ret = pdce->next;
664
665 #if 0 /* FIXME */
666
667 SetDCHook(pdce->hDC, NULL, 0L);
668 #endif
669
670 if(Force && !GDIOBJ_OwnedByCurrentProcess(GdiHandleTable, pdce->hDC))
671 {
672 DC_SetOwnership( pdce->hDC, PsGetCurrentProcess());
673 }
674
675 NtGdiDeleteObjectApp(pdce->hDC);
676 if (pdce->hClipRgn && ! (pdce->DCXFlags & DCX_KEEPCLIPRGN))
677 {
678 NtGdiDeleteObject(pdce->hClipRgn);
679 }
680
681 DCE_Cleanup(pdce);
682 ExFreePoolWithTag(pdce, TAG_PDCE);
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 while (pDCE)
698 {
699 if (pDCE->hwndCurrent == Window->hSelf)
700 {
701 if (pDCE == Window->Dce) /* owned or Class DCE*/
702 {
703 if (Window->Class->Style & CS_OWNDC) /* owned DCE*/
704 {
705 pDCE = DceFreeDCE(pDCE, FALSE);
706 Window->Dce = NULL;
707 continue;
708 }
709 else if (pDCE->DCXFlags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN)) /* Class DCE*/
710 {
711 DceDeleteClipRgn(pDCE);
712 pDCE->hwndCurrent = 0;
713 }
714 }
715 else
716 {
717 if (pDCE->DCXFlags & DCX_DCEBUSY) /* shared cache DCE */
718 {
719 /* FIXME: AFAICS we are doing the right thing here so
720 * this should be a DPRINT. But this is best left as an ERR
721 * because the 'application error' is likely to come from
722 * another part of Wine (i.e. it's our fault after all).
723 * We should change this to DPRINT when ReactOS is more stable
724 * (for 1.0?).
725 */
726 DPRINT1("[%p] GetDC() without ReleaseDC()!\n", Window->hSelf);
727 DceReleaseDC(pDCE, FALSE);
728 }
729
730 pDCE->DCXFlags &= DCX_CACHE;
731 pDCE->DCXFlags |= DCX_DCEEMPTY;
732 pDCE->hwndCurrent = 0;
733 }
734 }
735 pDCE = pDCE->next;
736 }
737 }
738
739 VOID FASTCALL
740 DceEmptyCache()
741 {
742 while (FirstDce != NULL)
743 {
744 FirstDce = DceFreeDCE(FirstDce, TRUE);
745 }
746 }
747
748 VOID FASTCALL
749 DceResetActiveDCEs(PWINDOW_OBJECT Window)
750 {
751 DCE *pDCE;
752 PDC dc;
753 PWINDOW_OBJECT CurrentWindow;
754 INT DeltaX;
755 INT DeltaY;
756
757 if (NULL == Window)
758 {
759 return;
760 }
761
762 pDCE = FirstDce;
763 while (pDCE)
764 {
765 if (0 == (pDCE->DCXFlags & DCX_DCEEMPTY))
766 {
767 if (Window->hSelf == pDCE->hwndCurrent)
768 {
769 CurrentWindow = Window;
770 }
771 else
772 {
773 CurrentWindow = UserGetWindowObject(pDCE->hwndCurrent);
774 if (NULL == CurrentWindow)
775 {
776 pDCE = pDCE->next;
777 continue;
778 }
779 }
780
781 dc = DC_LockDc(pDCE->hDC);
782 if (dc == NULL)
783 {
784 // if (Window->hSelf != pDCE->hwndCurrent)
785 // {
786 // UserDerefObject(CurrentWindow);
787 // }
788 pDCE = pDCE->next;
789 continue;
790 }
791 if (Window == CurrentWindow || IntIsChildWindow(Window, CurrentWindow))
792 {
793 if (pDCE->DCXFlags & DCX_WINDOW)
794 {
795 DeltaX = CurrentWindow->WindowRect.left - dc->w.DCOrgX;
796 DeltaY = CurrentWindow->WindowRect.top - dc->w.DCOrgY;
797 dc->w.DCOrgX = CurrentWindow->WindowRect.left;
798 dc->w.DCOrgY = CurrentWindow->WindowRect.top;
799 }
800 else
801 {
802 DeltaX = CurrentWindow->ClientRect.left - dc->w.DCOrgX;
803 DeltaY = CurrentWindow->ClientRect.top - dc->w.DCOrgY;
804 dc->w.DCOrgX = CurrentWindow->ClientRect.left;
805 dc->w.DCOrgY = CurrentWindow->ClientRect.top;
806 }
807 if (NULL != dc->w.hClipRgn)
808 {
809 int FASTCALL CLIPPING_UpdateGCRegion(DC* Dc);
810 NtGdiOffsetRgn(dc->w.hClipRgn, DeltaX, DeltaY);
811 CLIPPING_UpdateGCRegion(dc);
812 }
813 if (NULL != pDCE->hClipRgn)
814 {
815 NtGdiOffsetRgn(pDCE->hClipRgn, DeltaX, DeltaY);
816 }
817 }
818 DC_UnlockDc(dc);
819
820 DceUpdateVisRgn(pDCE, CurrentWindow, pDCE->DCXFlags);
821
822 if (Window->hSelf != pDCE->hwndCurrent)
823 {
824 // IntEngWindowChanged(CurrentWindow, WOC_RGN_CLIENT);
825 // UserDerefObject(CurrentWindow);
826 }
827 }
828
829 pDCE = pDCE->next;
830 }
831
832 }
833
834
835 #define COPY_DEVMODE_VALUE_TO_CALLER(dst, src, member) \
836 Status = MmCopyToCaller(&(dst)->member, &(src)->member, sizeof ((src)->member)); \
837 if (!NT_SUCCESS(Status)) \
838 { \
839 SetLastNtError(Status); \
840 ExFreePool(src); \
841 return FALSE; \
842 }
843
844 BOOL
845 STDCALL
846 NtUserEnumDisplaySettings(
847 PUNICODE_STRING lpszDeviceName,
848 DWORD iModeNum,
849 LPDEVMODEW lpDevMode, /* FIXME is this correct? */
850 DWORD dwFlags )
851 {
852 NTSTATUS Status;
853 LPDEVMODEW pSafeDevMode;
854 PUNICODE_STRING pSafeDeviceName = NULL;
855 UNICODE_STRING SafeDeviceName;
856 USHORT Size = 0, ExtraSize = 0;
857
858 /* Copy the devmode */
859 Status = MmCopyFromCaller(&Size, &lpDevMode->dmSize, sizeof (Size));
860 if (!NT_SUCCESS(Status))
861 {
862 SetLastNtError(Status);
863 return FALSE;
864 }
865 Status = MmCopyFromCaller(&ExtraSize, &lpDevMode->dmDriverExtra, sizeof (ExtraSize));
866 if (!NT_SUCCESS(Status))
867 {
868 SetLastNtError(Status);
869 return FALSE;
870 }
871 pSafeDevMode = ExAllocatePool(PagedPool, Size + ExtraSize);
872 if (pSafeDevMode == NULL)
873 {
874 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
875 return FALSE;
876 }
877 pSafeDevMode->dmSize = Size;
878 pSafeDevMode->dmDriverExtra = ExtraSize;
879
880 /* Copy the device name */
881 if (lpszDeviceName != NULL)
882 {
883 Status = IntSafeCopyUnicodeString(&SafeDeviceName, lpszDeviceName);
884 if (!NT_SUCCESS(Status))
885 {
886 ExFreePool(pSafeDevMode);
887 SetLastNtError(Status);
888 return FALSE;
889 }
890 pSafeDeviceName = &SafeDeviceName;
891 }
892
893 /* Call internal function */
894 if (!IntEnumDisplaySettings(pSafeDeviceName, iModeNum, pSafeDevMode, dwFlags))
895 {
896 if (pSafeDeviceName != NULL)
897 RtlFreeUnicodeString(pSafeDeviceName);
898 ExFreePool(pSafeDevMode);
899 return FALSE;
900 }
901 if (pSafeDeviceName != NULL)
902 RtlFreeUnicodeString(pSafeDeviceName);
903
904 /* Copy some information back */
905 COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode, pSafeDevMode, dmPelsWidth);
906 COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode, pSafeDevMode, dmPelsHeight);
907 COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode, pSafeDevMode, dmBitsPerPel);
908 COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode, pSafeDevMode, dmDisplayFrequency);
909 COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode, pSafeDevMode, dmDisplayFlags);
910
911 /* output private/extra driver data */
912 if (ExtraSize > 0)
913 {
914 Status = MmCopyToCaller((PCHAR)lpDevMode + Size, (PCHAR)pSafeDevMode + Size, ExtraSize);
915 if (!NT_SUCCESS(Status))
916 {
917 SetLastNtError(Status);
918 ExFreePool(pSafeDevMode);
919 return FALSE;
920 }
921 }
922
923 ExFreePool(pSafeDevMode);
924 return TRUE;
925 }
926
927 #undef COPY_DEVMODE_VALUE_TO_CALLER
928
929
930 LONG
931 STDCALL
932 NtUserChangeDisplaySettings(
933 PUNICODE_STRING lpszDeviceName,
934 LPDEVMODEW lpDevMode,
935 HWND hwnd,
936 DWORD dwflags,
937 LPVOID lParam)
938 {
939 NTSTATUS Status;
940 DEVMODEW DevMode;
941 PUNICODE_STRING pSafeDeviceName = NULL;
942 UNICODE_STRING SafeDeviceName;
943 LONG Ret;
944
945 /* Check arguments */
946 #ifdef CDS_VIDEOPARAMETERS
947
948 if (dwflags != CDS_VIDEOPARAMETERS && lParam != NULL)
949 #else
950
951 if (lParam != NULL)
952 #endif
953
954 {
955 SetLastWin32Error(ERROR_INVALID_PARAMETER);
956 return DISP_CHANGE_BADPARAM;
957 }
958 if (hwnd != NULL)
959 {
960 SetLastWin32Error(ERROR_INVALID_PARAMETER);
961 return DISP_CHANGE_BADPARAM;
962 }
963
964 /* Copy devmode */
965 Status = MmCopyFromCaller(&DevMode.dmSize, &lpDevMode->dmSize, sizeof (DevMode.dmSize));
966 if (!NT_SUCCESS(Status))
967 {
968 SetLastNtError(Status);
969 return DISP_CHANGE_BADPARAM;
970 }
971 DevMode.dmSize = min(sizeof (DevMode), DevMode.dmSize);
972 Status = MmCopyFromCaller(&DevMode, lpDevMode, DevMode.dmSize);
973 if (!NT_SUCCESS(Status))
974 {
975 SetLastNtError(Status);
976 return DISP_CHANGE_BADPARAM;
977 }
978 if (DevMode.dmDriverExtra > 0)
979 {
980 DbgPrint("(%s:%i) WIN32K: %s lpDevMode->dmDriverExtra is IGNORED!\n", __FILE__, __LINE__, __FUNCTION__);
981 DevMode.dmDriverExtra = 0;
982 }
983
984 /* Copy the device name */
985 if (lpszDeviceName != NULL)
986 {
987 Status = IntSafeCopyUnicodeString(&SafeDeviceName, lpszDeviceName);
988 if (!NT_SUCCESS(Status))
989 {
990 SetLastNtError(Status);
991 return DISP_CHANGE_BADPARAM;
992 }
993 pSafeDeviceName = &SafeDeviceName;
994 }
995
996 /* Call internal function */
997 Ret = IntChangeDisplaySettings(pSafeDeviceName, &DevMode, dwflags, lParam);
998
999 if (pSafeDeviceName != NULL)
1000 RtlFreeUnicodeString(pSafeDeviceName);
1001
1002 return Ret;
1003 }
1004
1005
1006 /* EOF */