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