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