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