- First try bug fix for #2698.
[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 /* make the DC clean so that SetDCState doesn't try to update the vis rgn */
252 IntGdiSetHookFlags(dce->hDC, DCHF_VALIDATEVISRGN);
253
254 PDC dc = DC_LockDc ( dce->hDC );
255 IntGdiCopyFromSaveState(dc, defaultDCstate, dce->hDC ); // Was SetDCState.
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 KeEnterCriticalRegion();
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 KeLeaveCriticalRegion();
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 KeEnterCriticalRegion();
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 KeLeaveCriticalRegion();
588 return NULL != PrevInList;
589 }
590
591 HWND FASTCALL
592 IntWindowFromDC(HDC hDc)
593 {
594 DCE *Dce;
595 KeEnterCriticalRegion();
596 for (Dce = FirstDce; Dce != NULL; Dce = Dce->next)
597 {
598 if(Dce->hDC == hDc)
599 {
600 KeLeaveCriticalRegion();
601 return Dce->hwndCurrent;
602 }
603 }
604 KeLeaveCriticalRegion();
605 return 0;
606 }
607
608
609 INT FASTCALL
610 UserReleaseDC(PWINDOW_OBJECT Window, HDC hDc, BOOL EndPaint)
611 {
612 DCE *dce;
613 INT nRet = 0;
614
615 dce = FirstDce;
616
617 DPRINT("%p %p\n", Window, hDc);
618 KeEnterCriticalRegion();
619 while (dce && (dce->hDC != hDc))
620 {
621 dce = dce->next;
622 }
623 KeLeaveCriticalRegion();
624 if (dce && (dce->DCXFlags & DCX_DCEBUSY))
625 {
626 nRet = DceReleaseDC(dce, EndPaint);
627 }
628
629 return nRet;
630 }
631
632
633 /***********************************************************************
634 * DceFreeDCE
635 */
636 PDCE FASTCALL
637 DceFreeDCE(PDCE pdce, BOOLEAN Force)
638 {
639 DCE *ret;
640
641 if (NULL == pdce)
642 {
643 return NULL;
644 }
645
646 ret = pdce->next;
647
648 #if 0 /* FIXME */
649
650 SetDCHook(pdce->hDC, NULL, 0L);
651 #endif
652
653 if(Force && !GDIOBJ_OwnedByCurrentProcess(GdiHandleTable, pdce->hDC))
654 {
655 DC_SetOwnership( pdce->hDC, PsGetCurrentProcess());
656 }
657
658 NtGdiDeleteObjectApp(pdce->hDC);
659 if (pdce->hClipRgn && ! (pdce->DCXFlags & DCX_KEEPCLIPRGN))
660 {
661 NtGdiDeleteObject(pdce->hClipRgn);
662 }
663
664 DCE_Cleanup(pdce);
665 ExFreePoolWithTag(pdce, TAG_PDCE);
666 return ret;
667 }
668
669 /***********************************************************************
670 * DceFreeWindowDCE
671 *
672 * Remove owned DCE and reset unreleased cache DCEs.
673 */
674 void FASTCALL
675 DceFreeWindowDCE(PWINDOW_OBJECT Window)
676 {
677 DCE *pDCE;
678
679 pDCE = FirstDce;
680 KeEnterCriticalRegion();
681 while (pDCE)
682 {
683 if (pDCE->hwndCurrent == Window->hSelf)
684 {
685 if (pDCE == Window->Dce) /* owned or Class DCE*/
686 {
687 if (Window->Class->Style & CS_OWNDC) /* owned DCE*/
688 {
689 pDCE = DceFreeDCE(pDCE, FALSE);
690 Window->Dce = NULL;
691 continue;
692 }
693 else if (pDCE->DCXFlags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN)) /* Class DCE*/
694 {
695 DceDeleteClipRgn(pDCE);
696 pDCE->hwndCurrent = 0;
697 }
698 }
699 else
700 {
701 if (pDCE->DCXFlags & DCX_DCEBUSY) /* shared cache DCE */
702 {
703 /* FIXME: AFAICS we are doing the right thing here so
704 * this should be a DPRINT. But this is best left as an ERR
705 * because the 'application error' is likely to come from
706 * another part of Wine (i.e. it's our fault after all).
707 * We should change this to DPRINT when ReactOS is more stable
708 * (for 1.0?).
709 */
710 DPRINT1("[%p] GetDC() without ReleaseDC()!\n", Window->hSelf);
711 DceReleaseDC(pDCE, FALSE);
712 }
713
714 pDCE->DCXFlags &= DCX_CACHE;
715 pDCE->DCXFlags |= DCX_DCEEMPTY;
716 pDCE->hwndCurrent = 0;
717 }
718 }
719 pDCE = pDCE->next;
720 }
721 KeLeaveCriticalRegion();
722 }
723
724 VOID FASTCALL
725 DceEmptyCache()
726 {
727 KeEnterCriticalRegion();
728 while (FirstDce != NULL)
729 {
730 FirstDce = DceFreeDCE(FirstDce, TRUE);
731 }
732 KeLeaveCriticalRegion();
733 }
734
735 VOID FASTCALL
736 DceResetActiveDCEs(PWINDOW_OBJECT Window)
737 {
738 DCE *pDCE;
739 PDC dc;
740 PWINDOW_OBJECT CurrentWindow;
741 INT DeltaX;
742 INT DeltaY;
743
744 if (NULL == Window)
745 {
746 return;
747 }
748 pDCE = FirstDce;
749 while (pDCE)
750 {
751 if (0 == (pDCE->DCXFlags & DCX_DCEEMPTY))
752 {
753 if (Window->hSelf == pDCE->hwndCurrent)
754 {
755 CurrentWindow = Window;
756 }
757 else
758 {
759 CurrentWindow = UserGetWindowObject(pDCE->hwndCurrent);
760 if (NULL == CurrentWindow)
761 {
762 pDCE = pDCE->next;
763 continue;
764 }
765 }
766
767 dc = DC_LockDc(pDCE->hDC);
768 if (dc == NULL)
769 {
770 // if (Window->hSelf != pDCE->hwndCurrent)
771 // {
772 // UserDerefObject(CurrentWindow);
773 // }
774 pDCE = pDCE->next;
775 continue;
776 }
777 if (Window == CurrentWindow || IntIsChildWindow(Window, CurrentWindow))
778 {
779 if (pDCE->DCXFlags & DCX_WINDOW)
780 {
781 DeltaX = CurrentWindow->WindowRect.left - dc->w.DCOrgX;
782 DeltaY = CurrentWindow->WindowRect.top - dc->w.DCOrgY;
783 dc->w.DCOrgX = CurrentWindow->WindowRect.left;
784 dc->w.DCOrgY = CurrentWindow->WindowRect.top;
785 }
786 else
787 {
788 DeltaX = CurrentWindow->ClientRect.left - dc->w.DCOrgX;
789 DeltaY = CurrentWindow->ClientRect.top - dc->w.DCOrgY;
790 dc->w.DCOrgX = CurrentWindow->ClientRect.left;
791 dc->w.DCOrgY = CurrentWindow->ClientRect.top;
792 }
793 if (NULL != dc->w.hClipRgn)
794 {
795 int FASTCALL CLIPPING_UpdateGCRegion(DC* Dc);
796 NtGdiOffsetRgn(dc->w.hClipRgn, DeltaX, DeltaY);
797 CLIPPING_UpdateGCRegion(dc);
798 }
799 if (NULL != pDCE->hClipRgn)
800 {
801 NtGdiOffsetRgn(pDCE->hClipRgn, DeltaX, DeltaY);
802 }
803 }
804 DC_UnlockDc(dc);
805
806 DceUpdateVisRgn(pDCE, CurrentWindow, pDCE->DCXFlags);
807
808 if (Window->hSelf != pDCE->hwndCurrent)
809 {
810 // IntEngWindowChanged(CurrentWindow, WOC_RGN_CLIENT);
811 // UserDerefObject(CurrentWindow);
812 }
813 }
814 pDCE = pDCE->next;
815 }
816 }
817
818
819 #define COPY_DEVMODE_VALUE_TO_CALLER(dst, src, member) \
820 Status = MmCopyToCaller(&(dst)->member, &(src)->member, sizeof ((src)->member)); \
821 if (!NT_SUCCESS(Status)) \
822 { \
823 SetLastNtError(Status); \
824 ExFreePool(src); \
825 return FALSE; \
826 }
827
828 BOOL
829 STDCALL
830 NtUserEnumDisplaySettings(
831 PUNICODE_STRING lpszDeviceName,
832 DWORD iModeNum,
833 LPDEVMODEW lpDevMode, /* FIXME is this correct? */
834 DWORD dwFlags )
835 {
836 NTSTATUS Status;
837 LPDEVMODEW pSafeDevMode;
838 PUNICODE_STRING pSafeDeviceName = NULL;
839 UNICODE_STRING SafeDeviceName;
840 USHORT Size = 0, ExtraSize = 0;
841
842 /* Copy the devmode */
843 Status = MmCopyFromCaller(&Size, &lpDevMode->dmSize, sizeof (Size));
844 if (!NT_SUCCESS(Status))
845 {
846 SetLastNtError(Status);
847 return FALSE;
848 }
849 Status = MmCopyFromCaller(&ExtraSize, &lpDevMode->dmDriverExtra, sizeof (ExtraSize));
850 if (!NT_SUCCESS(Status))
851 {
852 SetLastNtError(Status);
853 return FALSE;
854 }
855 pSafeDevMode = ExAllocatePool(PagedPool, Size + ExtraSize);
856 if (pSafeDevMode == NULL)
857 {
858 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
859 return FALSE;
860 }
861 pSafeDevMode->dmSize = Size;
862 pSafeDevMode->dmDriverExtra = ExtraSize;
863
864 /* Copy the device name */
865 if (lpszDeviceName != NULL)
866 {
867 Status = IntSafeCopyUnicodeString(&SafeDeviceName, lpszDeviceName);
868 if (!NT_SUCCESS(Status))
869 {
870 ExFreePool(pSafeDevMode);
871 SetLastNtError(Status);
872 return FALSE;
873 }
874 pSafeDeviceName = &SafeDeviceName;
875 }
876
877 /* Call internal function */
878 if (!IntEnumDisplaySettings(pSafeDeviceName, iModeNum, pSafeDevMode, dwFlags))
879 {
880 if (pSafeDeviceName != NULL)
881 RtlFreeUnicodeString(pSafeDeviceName);
882 ExFreePool(pSafeDevMode);
883 return FALSE;
884 }
885 if (pSafeDeviceName != NULL)
886 RtlFreeUnicodeString(pSafeDeviceName);
887
888 /* Copy some information back */
889 COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode, pSafeDevMode, dmPelsWidth);
890 COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode, pSafeDevMode, dmPelsHeight);
891 COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode, pSafeDevMode, dmBitsPerPel);
892 COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode, pSafeDevMode, dmDisplayFrequency);
893 COPY_DEVMODE_VALUE_TO_CALLER(lpDevMode, pSafeDevMode, dmDisplayFlags);
894
895 /* output private/extra driver data */
896 if (ExtraSize > 0)
897 {
898 Status = MmCopyToCaller((PCHAR)lpDevMode + Size, (PCHAR)pSafeDevMode + Size, ExtraSize);
899 if (!NT_SUCCESS(Status))
900 {
901 SetLastNtError(Status);
902 ExFreePool(pSafeDevMode);
903 return FALSE;
904 }
905 }
906
907 ExFreePool(pSafeDevMode);
908 return TRUE;
909 }
910
911 #undef COPY_DEVMODE_VALUE_TO_CALLER
912
913
914 LONG
915 STDCALL
916 NtUserChangeDisplaySettings(
917 PUNICODE_STRING lpszDeviceName,
918 LPDEVMODEW lpDevMode,
919 HWND hwnd,
920 DWORD dwflags,
921 LPVOID lParam)
922 {
923 NTSTATUS Status;
924 DEVMODEW DevMode;
925 PUNICODE_STRING pSafeDeviceName = NULL;
926 UNICODE_STRING SafeDeviceName;
927 LONG Ret;
928
929 /* Check arguments */
930 #ifdef CDS_VIDEOPARAMETERS
931
932 if (dwflags != CDS_VIDEOPARAMETERS && lParam != NULL)
933 #else
934
935 if (lParam != NULL)
936 #endif
937
938 {
939 SetLastWin32Error(ERROR_INVALID_PARAMETER);
940 return DISP_CHANGE_BADPARAM;
941 }
942 if (hwnd != NULL)
943 {
944 SetLastWin32Error(ERROR_INVALID_PARAMETER);
945 return DISP_CHANGE_BADPARAM;
946 }
947
948 /* Copy devmode */
949 Status = MmCopyFromCaller(&DevMode.dmSize, &lpDevMode->dmSize, sizeof (DevMode.dmSize));
950 if (!NT_SUCCESS(Status))
951 {
952 SetLastNtError(Status);
953 return DISP_CHANGE_BADPARAM;
954 }
955 DevMode.dmSize = min(sizeof (DevMode), DevMode.dmSize);
956 Status = MmCopyFromCaller(&DevMode, lpDevMode, DevMode.dmSize);
957 if (!NT_SUCCESS(Status))
958 {
959 SetLastNtError(Status);
960 return DISP_CHANGE_BADPARAM;
961 }
962 if (DevMode.dmDriverExtra > 0)
963 {
964 DbgPrint("(%s:%i) WIN32K: %s lpDevMode->dmDriverExtra is IGNORED!\n", __FILE__, __LINE__, __FUNCTION__);
965 DevMode.dmDriverExtra = 0;
966 }
967
968 /* Copy the device name */
969 if (lpszDeviceName != NULL)
970 {
971 Status = IntSafeCopyUnicodeString(&SafeDeviceName, lpszDeviceName);
972 if (!NT_SUCCESS(Status))
973 {
974 SetLastNtError(Status);
975 return DISP_CHANGE_BADPARAM;
976 }
977 pSafeDeviceName = &SafeDeviceName;
978 }
979
980 /* Call internal function */
981 Ret = IntChangeDisplaySettings(pSafeDeviceName, &DevMode, dwflags, lParam);
982
983 if (pSafeDeviceName != NULL)
984 RtlFreeUnicodeString(pSafeDeviceName);
985
986 return Ret;
987 }
988
989 /*!
990 * Select logical palette into device context.
991 * \param hDC handle to the device context
992 * \param hpal handle to the palette
993 * \param ForceBackground If this value is FALSE the logical palette will be copied to the device palette only when the applicatioon
994 * is in the foreground. If this value is TRUE then map the colors in the logical palette to the device
995 * palette colors in the best way.
996 * \return old palette
997 *
998 * \todo implement ForceBackground == TRUE
999 */
1000 HPALETTE STDCALL NtUserSelectPalette(HDC hDC,
1001 HPALETTE hpal,
1002 BOOL ForceBackground)
1003 {
1004 PDC dc;
1005 HPALETTE oldPal = NULL;
1006 PPALGDI PalGDI;
1007
1008 // FIXME: mark the palette as a [fore\back]ground pal
1009 dc = DC_LockDc(hDC);
1010 if (NULL != dc)
1011 {
1012 /* Check if this is a valid palette handle */
1013 PalGDI = PALETTE_LockPalette(hpal);
1014 if (NULL != PalGDI)
1015 {
1016 /* Is this a valid palette for this depth? */
1017 if ((dc->w.bitsPerPixel <= 8 && PAL_INDEXED == PalGDI->Mode)
1018 || (8 < dc->w.bitsPerPixel && PAL_INDEXED != PalGDI->Mode))
1019 {
1020 PALETTE_UnlockPalette(PalGDI);
1021 oldPal = dc->w.hPalette;
1022 dc->w.hPalette = hpal;
1023 }
1024 else if (8 < dc->w.bitsPerPixel && PAL_INDEXED == PalGDI->Mode)
1025 {
1026 PALETTE_UnlockPalette(PalGDI);
1027 oldPal = dc->PalIndexed;
1028 dc->PalIndexed = hpal;
1029 }
1030 else
1031 {
1032 PALETTE_UnlockPalette(PalGDI);
1033 oldPal = NULL;
1034 }
1035 }
1036 else
1037 {
1038 oldPal = NULL;
1039 }
1040 DC_UnlockDc(dc);
1041 }
1042
1043 return oldPal;
1044 }
1045
1046
1047 /* EOF */