xref: /reactos/win32ss/gdi/eng/mouse.c (revision 0b366ea1)
1 /*
2  * COPYRIGHT:        See COPYING in the top level directory
3  * PROJECT:          ReactOS win32 subsystem
4  * PURPOSE:          Mouse pointer functions
5  * FILE:             win32ss/gdi/eng/mouse.c
6  * PROGRAMER:        Casper S. Hornstrup (chorns@users.sourceforge.net)
7  *                   Timo Kreuzer (timo.kreuzer@reactos.org)
8  */
9 /* INCLUDES ******************************************************************/
10 
11 #include <win32k.h>
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* FUNCTIONS *****************************************************************/
17 
18 __drv_preferredFunction("(see documentation)", "Obsolete, always returns false. ")
19 BOOL
20 APIENTRY
21 EngSetPointerTag(
22     _In_ HDEV hdev,
23     _In_opt_ SURFOBJ *psoMask,
24     _In_opt_ SURFOBJ *psoColor,
25     _Reserved_ XLATEOBJ *pxlo,
26     _In_ FLONG fl)
27 {
28     // This function is obsolete for Windows 2000 and later.
29     // This function is still supported, but always returns FALSE.
30     // www.osr.com/ddk/graphics/gdifncs_4yav.htm
31     return FALSE;
32 }
33 
34 /*
35  * FUNCTION: Notify the mouse driver that drawing is about to begin in
36  * a rectangle on a particular surface.
37  */
38 _Requires_lock_held_(*ppdev->hsemDevLock)
39 BOOL
40 NTAPI
41 MouseSafetyOnDrawStart(
42     _Inout_ PPDEVOBJ ppdev,
43     _In_ LONG HazardX1,
44     _In_ LONG HazardY1,
45     _In_ LONG HazardX2,
46     _In_ LONG HazardY2)
47 {
48     LONG tmp;
49     GDIPOINTER *pgp;
50 
51     ASSERT(ppdev != NULL);
52     ASSERT(ppdev->pSurface != NULL);
53 
54     pgp = &ppdev->Pointer;
55 
56     if (pgp->Exclude.right == -1)
57     {
58         return FALSE;
59     }
60 
61     ppdev->SafetyRemoveCount++;
62 
63     if (ppdev->SafetyRemoveLevel != 0)
64     {
65         return FALSE;
66     }
67 
68     if (HazardX1 > HazardX2)
69     {
70         tmp = HazardX2;
71         HazardX2 = HazardX1;
72         HazardX1 = tmp;
73     }
74     if (HazardY1 > HazardY2)
75     {
76         tmp = HazardY2;
77         HazardY2 = HazardY1;
78         HazardY1 = tmp;
79     }
80 
81     if (pgp->Exclude.right >= HazardX1
82         && pgp->Exclude.left <= HazardX2
83         && pgp->Exclude.bottom >= HazardY1
84         && pgp->Exclude.top <= HazardY2)
85     {
86         ppdev->SafetyRemoveLevel = ppdev->SafetyRemoveCount;
87         if (ppdev->flFlags & PDEV_HARDWARE_POINTER)
88             ppdev->pfnMovePointer(&ppdev->pSurface->SurfObj, -1, -1, NULL);
89         else if (ppdev->flFlags & PDEV_SOFTWARE_POINTER)
90             EngMovePointer(&ppdev->pSurface->SurfObj, -1, -1, NULL);
91     }
92 
93     return TRUE;
94 }
95 
96 /*
97  * FUNCTION: Notify the mouse driver that drawing has finished on a surface.
98  */
99 _Requires_lock_held_(*ppdev->hsemDevLock)
100 BOOL
101 NTAPI
102 MouseSafetyOnDrawEnd(
103     _Inout_ PPDEVOBJ ppdev)
104 {
105     GDIPOINTER *pgp;
106 
107     ASSERT(ppdev != NULL);
108     ASSERT(ppdev->pSurface != NULL);
109 
110     pgp = &ppdev->Pointer;
111 
112     if (pgp->Exclude.right == -1)
113     {
114         return FALSE;
115     }
116 
117     if (--ppdev->SafetyRemoveCount >= ppdev->SafetyRemoveLevel)
118     {
119         return FALSE;
120     }
121 
122     if (ppdev->flFlags & PDEV_HARDWARE_POINTER)
123         ppdev->pfnMovePointer(&ppdev->pSurface->SurfObj,
124                               gpsi->ptCursor.x,
125                               gpsi->ptCursor.y,
126                               &pgp->Exclude);
127     else if (ppdev->flFlags & PDEV_SOFTWARE_POINTER)
128         EngMovePointer(&ppdev->pSurface->SurfObj,
129                        gpsi->ptCursor.x,
130                        gpsi->ptCursor.y,
131                        &pgp->Exclude);
132 
133     ppdev->SafetyRemoveLevel = 0;
134 
135     return TRUE;
136 }
137 
138 /* SOFTWARE MOUSE POINTER IMPLEMENTATION **************************************/
139 
140 VOID
141 NTAPI
142 IntHideMousePointer(
143     _Inout_ PDEVOBJ *ppdev,
144     _Inout_ SURFOBJ *psoDest)
145 {
146     GDIPOINTER *pgp;
147     POINTL pt;
148     RECTL rclDest;
149     POINTL ptlSave;
150 
151     ASSERT(ppdev);
152     ASSERT(psoDest);
153 
154     pgp = &ppdev->Pointer;
155 
156     if (!pgp->Enabled)
157     {
158         return;
159     }
160 
161     pgp->Enabled = FALSE;
162 
163     if (!pgp->psurfSave)
164     {
165         DPRINT("No SaveSurface!\n");
166         return;
167     }
168 
169     /* Calculate cursor coordinates */
170     pt.x = ppdev->ptlPointer.x - pgp->HotSpot.x;
171     pt.y = ppdev->ptlPointer.y - pgp->HotSpot.y;
172 
173     rclDest.left = max(pt.x, 0);
174     rclDest.top = max(pt.y, 0);
175     rclDest.right = min(pt.x + pgp->Size.cx, psoDest->sizlBitmap.cx);
176     rclDest.bottom = min(pt.y + pgp->Size.cy, psoDest->sizlBitmap.cy);
177 
178     ptlSave.x = rclDest.left - pt.x;
179     ptlSave.y = rclDest.top - pt.y;
180 
181     IntEngBitBlt(psoDest,
182                  &pgp->psurfSave->SurfObj,
183                  NULL,
184                  NULL,
185                  NULL,
186                  &rclDest,
187                  &ptlSave,
188                  &ptlSave,
189                  NULL,
190                  NULL,
191                  ROP4_FROM_INDEX(R3_OPINDEX_SRCCOPY));
192 }
193 
194 VOID
195 NTAPI
196 IntShowMousePointer(
197     _Inout_ PDEVOBJ *ppdev,
198     _Inout_ SURFOBJ *psoDest)
199 {
200     GDIPOINTER *pgp;
201     POINTL pt;
202     RECTL rclSurf, rclPointer;
203 
204     ASSERT(ppdev);
205     ASSERT(psoDest);
206 
207     pgp = &ppdev->Pointer;
208 
209     if (pgp->Enabled)
210     {
211         return;
212     }
213 
214     pgp->Enabled = TRUE;
215 
216     /* Check if we have any mouse pointer */
217     if (!pgp->psurfSave) return;
218 
219     /* Calculate pointer coordinates */
220     pt.x = ppdev->ptlPointer.x - pgp->HotSpot.x;
221     pt.y = ppdev->ptlPointer.y - pgp->HotSpot.y;
222 
223     /* Calculate the rect on the surface */
224     rclSurf.left = max(pt.x, 0);
225     rclSurf.top = max(pt.y, 0);
226     rclSurf.right = min(pt.x + pgp->Size.cx, psoDest->sizlBitmap.cx);
227     rclSurf.bottom = min(pt.y + pgp->Size.cy, psoDest->sizlBitmap.cy);
228 
229     /* Calculate the rect in the pointer bitmap */
230     rclPointer.left = rclSurf.left - pt.x;
231     rclPointer.top = rclSurf.top - pt.y;
232     rclPointer.right = min(pgp->Size.cx, psoDest->sizlBitmap.cx - pt.x);
233     rclPointer.bottom = min(pgp->Size.cy, psoDest->sizlBitmap.cy - pt.y);
234 
235     /* Copy the pixels under the cursor to temporary surface. */
236     IntEngBitBlt(&pgp->psurfSave->SurfObj,
237                  psoDest,
238                  NULL,
239                  NULL,
240                  NULL,
241                  &rclPointer,
242                  (POINTL*)&rclSurf,
243                  NULL,
244                  NULL,
245                  NULL,
246                  ROP4_FROM_INDEX(R3_OPINDEX_SRCCOPY));
247 
248     /* Blt the pointer on the screen. */
249     if (pgp->psurfColor)
250     {
251         if(!(pgp->flags & SPS_ALPHA))
252         {
253             IntEngBitBlt(psoDest,
254                          &pgp->psurfMask->SurfObj,
255                          NULL,
256                          NULL,
257                          NULL,
258                          &rclSurf,
259                          (POINTL*)&rclPointer,
260                          NULL,
261                          NULL,
262                          NULL,
263                          ROP4_SRCAND);
264 
265             IntEngBitBlt(psoDest,
266                          &pgp->psurfColor->SurfObj,
267                          NULL,
268                          NULL,
269                          NULL,
270                          &rclSurf,
271                          (POINTL*)&rclPointer,
272                          NULL,
273                          NULL,
274                          NULL,
275                          ROP4_SRCINVERT);
276          }
277          else
278          {
279             BLENDOBJ blendobj = { {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA } };
280             EXLATEOBJ exlo;
281             EXLATEOBJ_vInitialize(&exlo,
282                 &gpalRGB,
283                 ppdev->ppalSurf,
284                 0, 0, 0);
285             IntEngAlphaBlend(psoDest,
286                              &pgp->psurfColor->SurfObj,
287                              NULL,
288                              &exlo.xlo,
289                              &rclSurf,
290                              &rclPointer,
291                              &blendobj);
292             EXLATEOBJ_vCleanup(&exlo);
293         }
294     }
295     else
296     {
297         IntEngBitBlt(psoDest,
298                      &pgp->psurfMask->SurfObj,
299                      NULL,
300                      NULL,
301                      NULL,
302                      &rclSurf,
303                      (POINTL*)&rclPointer,
304                      NULL,
305                      NULL,
306                      NULL,
307                      ROP4_FROM_INDEX(R3_OPINDEX_SRCAND));
308 
309         rclPointer.top += pgp->Size.cy;
310 
311         IntEngBitBlt(psoDest,
312                      &pgp->psurfMask->SurfObj,
313                      NULL,
314                      NULL,
315                      NULL,
316                      &rclSurf,
317                      (POINTL*)&rclPointer,
318                      NULL,
319                      NULL,
320                      NULL,
321                      ROP4_FROM_INDEX(R3_OPINDEX_SRCINVERT));
322     }
323 }
324 
325 /*
326  * @implemented
327  */
328 ULONG
329 APIENTRY
330 EngSetPointerShape(
331     _In_ SURFOBJ *pso,
332     _In_opt_ SURFOBJ *psoMask,
333     _In_opt_ SURFOBJ *psoColor,
334     _In_opt_ XLATEOBJ *pxlo,
335     _In_ LONG xHot,
336     _In_ LONG yHot,
337     _In_ LONG x,
338     _In_ LONG y,
339     _In_ RECTL *prcl,
340     _In_ FLONG fl)
341 {
342     PDEVOBJ *ppdev;
343     GDIPOINTER *pgp;
344     LONG lDelta = 0;
345     HBITMAP hbmSave = NULL, hbmColor = NULL, hbmMask = NULL;
346     PSURFACE psurfSave = NULL, psurfColor = NULL, psurfMask = NULL;
347     RECTL rectl;
348     SIZEL sizel = {0, 0};
349 
350     ASSERT(pso);
351 
352     ppdev = GDIDEV(pso);
353     pgp = &ppdev->Pointer;
354 
355     /* Handle the case where we have no XLATEOBJ */
356     if (pxlo == NULL)
357         pxlo = &gexloTrivial.xlo;
358 
359     /* Do we have any bitmap at all? */
360     if (psoColor || psoMask)
361     {
362         /* Get the size of the new pointer */
363         if (psoColor)
364         {
365             sizel.cx = psoColor->sizlBitmap.cx;
366             sizel.cy = psoColor->sizlBitmap.cy;
367         }
368         else// if (psoMask)
369         {
370             sizel.cx = psoMask->sizlBitmap.cx;
371             sizel.cy = psoMask->sizlBitmap.cy / 2;
372         }
373 
374         rectl.left = 0;
375         rectl.top = 0;
376         rectl.right = sizel.cx;
377         rectl.bottom = sizel.cy;
378 
379         /* Calculate lDelta for our surfaces. */
380         lDelta = WIDTH_BYTES_ALIGN32(sizel.cx,
381                                      BitsPerFormat(pso->iBitmapFormat));
382 
383         /* Create a bitmap for saving the pixels under the cursor. */
384         hbmSave = EngCreateBitmap(sizel,
385                                   lDelta,
386                                   pso->iBitmapFormat,
387                                   BMF_TOPDOWN | BMF_NOZEROINIT,
388                                   NULL);
389         psurfSave = SURFACE_ShareLockSurface(hbmSave);
390         if (!psurfSave) goto failure;
391     }
392 
393     if (psoColor)
394     {
395         if (fl & SPS_ALPHA)
396         {
397             /* Always store the alpha cursor in RGB. */
398             EXLATEOBJ exloSrcRGB;
399             PEXLATEOBJ pexlo;
400 
401             pexlo = CONTAINING_RECORD(pxlo, EXLATEOBJ, xlo);
402             EXLATEOBJ_vInitialize(&exloSrcRGB, pexlo->ppalSrc, &gpalRGB, 0, 0, 0);
403 
404             hbmColor = EngCreateBitmap(psoColor->sizlBitmap,
405                 WIDTH_BYTES_ALIGN32(sizel.cx, 32),
406                 BMF_32BPP,
407                 BMF_TOPDOWN | BMF_NOZEROINIT,
408                 NULL);
409             psurfColor = SURFACE_ShareLockSurface(hbmColor);
410             if (!psurfColor) goto failure;
411 
412             /* Now copy the given bitmap. */
413             rectl.bottom = psoColor->sizlBitmap.cy;
414             IntEngCopyBits(&psurfColor->SurfObj,
415                            psoColor,
416                            NULL,
417                            &exloSrcRGB.xlo,
418                            &rectl,
419                            (POINTL*)&rectl);
420 
421             EXLATEOBJ_vCleanup(&exloSrcRGB);
422         }
423         else
424         {
425             /* Color bitmap must have the same format as the dest surface */
426             if (psoColor->iBitmapFormat != pso->iBitmapFormat)
427             {
428                 DPRINT1("Screen surface and cursor color bitmap format don't match!.\n");
429                 goto failure;
430             }
431 
432             /* Create a bitmap to copy the color bitmap to */
433             hbmColor = EngCreateBitmap(psoColor->sizlBitmap,
434                                lDelta,
435                                pso->iBitmapFormat,
436                                BMF_TOPDOWN | BMF_NOZEROINIT,
437                                NULL);
438             psurfColor = SURFACE_ShareLockSurface(hbmColor);
439             if (!psurfColor) goto failure;
440 
441             /* Now copy the given bitmap. */
442             rectl.bottom = psoColor->sizlBitmap.cy;
443             IntEngCopyBits(&psurfColor->SurfObj,
444                            psoColor,
445                            NULL,
446                            pxlo,
447                            &rectl,
448                            (POINTL*)&rectl);
449         }
450 
451     }
452 
453     /* Create a mask surface */
454     if (psoMask)
455     {
456         EXLATEOBJ exlo;
457         PPALETTE ppal;
458 
459         lDelta = WIDTH_BYTES_ALIGN32(sizel.cx, BitsPerFormat(pso->iBitmapFormat));
460 
461         /* Create a bitmap for the mask */
462         hbmMask = EngCreateBitmap(psoMask->sizlBitmap,
463                                   lDelta,
464                                   pso->iBitmapFormat,
465                                   BMF_TOPDOWN | BMF_NOZEROINIT,
466                                   NULL);
467         psurfMask = SURFACE_ShareLockSurface(hbmMask);
468         if (!psurfMask) goto failure;
469 
470         /* Initialize an EXLATEOBJ */
471         ppal = PALETTE_ShareLockPalette(ppdev->devinfo.hpalDefault);
472         EXLATEOBJ_vInitialize(&exlo,
473                               gppalMono,
474                               ppal,
475                               0,
476                               RGB(0xff,0xff,0xff),
477                               RGB(0,0,0));
478 
479         /* Copy the mask bitmap */
480         rectl.bottom = psoMask->sizlBitmap.cy;
481         IntEngCopyBits(&psurfMask->SurfObj,
482                        psoMask,
483                        NULL,
484                        &exlo.xlo,
485                        &rectl,
486                        (POINTL*)&rectl);
487 
488         /* Cleanup */
489         EXLATEOBJ_vCleanup(&exlo);
490         if (ppal) PALETTE_ShareUnlockPalette(ppal);
491     }
492 
493     /* Hide mouse pointer */
494     IntHideMousePointer(ppdev, pso);
495 
496     /* Free old color bitmap */
497     if (pgp->psurfColor)
498     {
499         EngDeleteSurface(pgp->psurfColor->BaseObject.hHmgr);
500         SURFACE_ShareUnlockSurface(pgp->psurfColor);
501         pgp->psurfColor = NULL;
502     }
503 
504     /* Free old mask bitmap */
505     if (pgp->psurfMask)
506     {
507         EngDeleteSurface(pgp->psurfMask->BaseObject.hHmgr);
508         SURFACE_ShareUnlockSurface(pgp->psurfMask);
509         pgp->psurfMask = NULL;
510     }
511 
512     /* Free old save bitmap */
513     if (pgp->psurfSave)
514     {
515         EngDeleteSurface(pgp->psurfSave->BaseObject.hHmgr);
516         SURFACE_ShareUnlockSurface(pgp->psurfSave);
517         pgp->psurfSave = NULL;
518     }
519 
520     /* See if we are being asked to hide the pointer. */
521     if (psoMask == NULL && psoColor == NULL)
522     {
523         /* We're done */
524         return SPS_ACCEPT_NOEXCLUDE;
525     }
526 
527     /* Now set the new cursor */
528     pgp->psurfColor = psurfColor;
529     pgp->psurfMask = psurfMask;
530     pgp->psurfSave = psurfSave;
531     pgp->HotSpot.x = xHot;
532     pgp->HotSpot.y = yHot;
533     pgp->Size = sizel;
534     pgp->flags = fl;
535 
536     if (x != -1)
537     {
538         ppdev->ptlPointer.x = x;
539         ppdev->ptlPointer.y = y;
540 
541         IntShowMousePointer(ppdev, pso);
542 
543         if (prcl != NULL)
544         {
545             prcl->left = x - pgp->HotSpot.x;
546             prcl->top = y - pgp->HotSpot.x;
547             prcl->right = prcl->left + pgp->Size.cx;
548             prcl->bottom = prcl->top + pgp->Size.cy;
549         }
550     }
551     else if (prcl != NULL)
552     {
553         prcl->left = prcl->top = prcl->right = prcl->bottom = -1;
554     }
555 
556     return SPS_ACCEPT_NOEXCLUDE;
557 
558 failure:
559     /* Cleanup surfaces */
560     if (hbmMask) EngDeleteSurface((HSURF)hbmMask);
561     if (psurfMask) SURFACE_ShareUnlockSurface(psurfMask);
562     if (hbmColor) EngDeleteSurface((HSURF)hbmColor);
563     if (psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
564     if (hbmSave) EngDeleteSurface((HSURF)hbmSave);
565     if (psurfSave) SURFACE_ShareUnlockSurface(psurfSave);
566 
567     return SPS_ERROR;
568 }
569 
570 /*
571  * @implemented
572  */
573 VOID
574 APIENTRY
575 EngMovePointer(
576     _In_ SURFOBJ *pso,
577     _In_ LONG x,
578     _In_ LONG y,
579     _In_ RECTL *prcl)
580 {
581     PDEVOBJ *ppdev;
582     GDIPOINTER *pgp;
583 
584     ASSERT(pso);
585 
586     ppdev = GDIDEV(pso);
587     ASSERT(ppdev);
588 
589     pgp = &ppdev->Pointer;
590 
591     IntHideMousePointer(ppdev, pso);
592 
593     ppdev->ptlPointer.x = x;
594     ppdev->ptlPointer.y = y;
595 
596     if (x != -1)
597     {
598         IntShowMousePointer(ppdev, pso);
599         if (prcl != NULL)
600         {
601             prcl->left = x - pgp->HotSpot.x;
602             prcl->top = y - pgp->HotSpot.y;
603             prcl->right = prcl->left + pgp->Size.cx;
604             prcl->bottom = prcl->top + pgp->Size.cy;
605         }
606     }
607     else if (prcl != NULL)
608     {
609         prcl->left = prcl->top = prcl->right = prcl->bottom = -1;
610     }
611 }
612 
613 ULONG
614 NTAPI
615 IntEngSetPointerShape(
616     _In_ SURFOBJ *pso,
617     _In_opt_ SURFOBJ *psoMask,
618     _In_opt_ SURFOBJ *psoColor,
619     _In_opt_ XLATEOBJ *pxlo,
620     _In_ LONG xHot,
621     _In_ LONG yHot,
622     _In_ LONG x,
623     _In_ LONG y,
624     _In_ RECTL *prcl,
625     _In_ FLONG fl)
626 {
627     ULONG ulResult = SPS_DECLINE;
628     PFN_DrvSetPointerShape pfnSetPointerShape;
629     PPDEVOBJ ppdev = GDIDEV(pso);
630     BOOL bHardwarePointer = FALSE;
631     BOOL bSoftwarePointer = TRUE;
632 
633     pfnSetPointerShape = GDIDEVFUNCS(pso).SetPointerShape;
634 
635     if (pfnSetPointerShape)
636     {
637         /* Drivers expect to get an XLATEOBJ */
638         if (pxlo == NULL)
639             pxlo = &gexloTrivial.xlo;
640 
641         /* Call the driver */
642         ulResult = pfnSetPointerShape(pso,
643                                       psoMask,
644                                       psoColor,
645                                       pxlo,
646                                       xHot,
647                                       yHot,
648                                       x,
649                                       y,
650                                       prcl,
651                                       fl);
652 
653         /* Check if the driver accepted it */
654         if (ulResult == SPS_ACCEPT_NOEXCLUDE)
655             bHardwarePointer = TRUE;
656 
657         bSoftwarePointer = !bHardwarePointer;
658     }
659 
660     if (bSoftwarePointer)
661     {
662         /* Set software pointer */
663         ulResult = EngSetPointerShape(pso,
664                                       psoMask,
665                                       psoColor,
666                                       pxlo,
667                                       xHot,
668                                       yHot,
669                                       x,
670                                       y,
671                                       prcl,
672                                       fl);
673     }
674 
675     if (!bSoftwarePointer && ppdev->flFlags & PDEV_SOFTWARE_POINTER)
676     {
677         /* Disable software pointer */
678         EngMovePointer(pso, -1, -1, NULL);
679     }
680 
681     if (!bHardwarePointer && ppdev->flFlags & PDEV_HARDWARE_POINTER)
682     {
683         /* Disable hardware pointer */
684         ppdev->pfnMovePointer(pso, -1, -1, NULL);
685     }
686 
687     /* Update flags */
688     if (bSoftwarePointer)
689         ppdev->flFlags |= PDEV_SOFTWARE_POINTER;
690     else
691         ppdev->flFlags &= ~PDEV_SOFTWARE_POINTER;
692 
693     if (bHardwarePointer)
694         ppdev->flFlags |= PDEV_HARDWARE_POINTER;
695     else
696         ppdev->flFlags &= ~PDEV_HARDWARE_POINTER;
697 
698     return ulResult;
699 }
700 
701 ULONG
702 NTAPI
703 GreSetPointerShape(
704     _In_ HDC hdc,
705     _In_opt_ HBITMAP hbmMask,
706     _In_opt_ HBITMAP hbmColor,
707     _In_ LONG xHot,
708     _In_ LONG yHot,
709     _In_ LONG x,
710     _In_ LONG y,
711     _In_ FLONG fl)
712 {
713     PDC pdc;
714     PSURFACE psurf, psurfMask, psurfColor;
715     EXLATEOBJ exlo;
716     ULONG ulResult = 0;
717 
718     pdc = DC_LockDc(hdc);
719     if (!pdc)
720     {
721         DPRINT1("Failed to lock the DC.\n");
722         return 0;
723     }
724 
725     ASSERT(pdc->dctype == DCTYPE_DIRECT);
726     EngAcquireSemaphore(pdc->ppdev->hsemDevLock);
727     /* We're not sure DC surface is the good one */
728     psurf = pdc->ppdev->pSurface;
729     if (!psurf)
730     {
731         DPRINT1("DC has no surface.\n");
732         EngReleaseSemaphore(pdc->ppdev->hsemDevLock);
733         DC_UnlockDc(pdc);
734         return 0;
735     }
736 
737     /* Lock the mask bitmap */
738     if (hbmMask)
739     {
740         psurfMask = SURFACE_ShareLockSurface(hbmMask);
741     }
742     else
743     {
744         //ASSERT(fl & SPS_ALPHA);
745         psurfMask = NULL;
746     }
747 
748     /* Check for color bitmap */
749     if (hbmColor)
750     {
751         /* We have one, lock it */
752         psurfColor = SURFACE_ShareLockSurface(hbmColor);
753 
754         if (psurfColor)
755         {
756             /* Create an XLATEOBJ, no mono support */
757             EXLATEOBJ_vInitialize(&exlo, psurfColor->ppal, psurf->ppal, 0, 0, 0);
758         }
759     }
760     else
761         psurfColor = NULL;
762 
763     /* We must have a valid surface in case of alpha bitmap */
764     ASSERT(((fl & SPS_ALPHA) && psurfColor) || !(fl & SPS_ALPHA));
765 
766     /* Call the driver or eng function */
767     ulResult = IntEngSetPointerShape(&psurf->SurfObj,
768                                      psurfMask ? &psurfMask->SurfObj : NULL,
769                                      psurfColor ? &psurfColor->SurfObj : NULL,
770                                      psurfColor ? &exlo.xlo : NULL,
771                                      xHot,
772                                      yHot,
773                                      x,
774                                      y,
775                                      &pdc->ppdev->Pointer.Exclude,
776                                      fl | SPS_CHANGE);
777 
778     /* Cleanup */
779     if (psurfColor)
780     {
781         EXLATEOBJ_vCleanup(&exlo);
782         SURFACE_ShareUnlockSurface(psurfColor);
783     }
784 
785     if (psurfMask)
786         SURFACE_ShareUnlockSurface(psurfMask);
787 
788     EngReleaseSemaphore(pdc->ppdev->hsemDevLock);
789 
790     /* Unlock the DC */
791     DC_UnlockDc(pdc);
792 
793     /* Return result */
794     return ulResult;
795 }
796 
797 VOID
798 NTAPI
799 GreMovePointer(
800     _In_ HDC hdc,
801     _In_ LONG x,
802     _In_ LONG y)
803 {
804     PDC pdc;
805     PRECTL prcl;
806 
807     /* Lock the DC */
808     pdc = DC_LockDc(hdc);
809     if (!pdc)
810     {
811         DPRINT1("Failed to lock the DC.\n");
812         return;
813     }
814     ASSERT(pdc->dctype == DCTYPE_DIRECT);
815 
816     /* Acquire PDEV lock */
817     EngAcquireSemaphore(pdc->ppdev->hsemDevLock);
818 
819     /* Check if we need to move it */
820     if(pdc->ppdev->SafetyRemoveLevel == 0)
821     {
822         SURFOBJ* pso = &pdc->ppdev->pSurface->SurfObj;
823 
824         /* Store the cursor exclude position in the PDEV */
825         prcl = &pdc->ppdev->Pointer.Exclude;
826 
827         /* Send new position of the hot spot of the pointer (will likely redraw cursor) */
828         if (pdc->ppdev->flFlags & PDEV_HARDWARE_POINTER)
829             pdc->ppdev->pfnMovePointer(pso, x, y, prcl);
830         else if (pdc->ppdev->flFlags & PDEV_SOFTWARE_POINTER)
831             EngMovePointer(pso, x, y, prcl);
832 
833         /* If panning device, and we're not hiding the cursor, notify cursor's current position.
834          * (driver may already have been called if it also supports hardware pointers) */
835         if (pdc->ppdev->devinfo.flGraphicsCaps & GCAPS_PANNING && y >= 0)
836             pdc->ppdev->pfnMovePointer(pso, x, y - pso->sizlBitmap.cy, NULL);
837     }
838 
839     /* Release PDEV lock */
840     EngReleaseSemaphore(pdc->ppdev->hsemDevLock);
841 
842     /* Unlock the DC */
843     DC_UnlockDc(pdc);
844 }
845 
846 
847 /* EOF */
848