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