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