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