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