xref: /reactos/win32ss/gdi/eng/mouse.c (revision c2c66aff)
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 
622     pfnSetPointerShape = GDIDEVFUNCS(pso).SetPointerShape;
623 
624     if (pfnSetPointerShape)
625     {
626         /* Drivers expect to get an XLATEOBJ */
627         if (pxlo == NULL)
628             pxlo = &gexloTrivial.xlo;
629 
630         /* Call the driver */
631         ulResult = pfnSetPointerShape(pso,
632                                       psoMask,
633                                       psoColor,
634                                       pxlo,
635                                       xHot,
636                                       yHot,
637                                       x,
638                                       y,
639                                       prcl,
640                                       fl);
641     }
642 
643     /* Check if the driver accepted it */
644     if (ulResult == SPS_ACCEPT_NOEXCLUDE)
645     {
646         /* Set MovePointer to the driver function */
647         ppdev->pfnMovePointer = GDIDEVFUNCS(pso).MovePointer;
648     }
649     else
650     {
651         /* Set software pointer */
652         ulResult = EngSetPointerShape(pso,
653                                       psoMask,
654                                       psoColor,
655                                       pxlo,
656                                       xHot,
657                                       yHot,
658                                       x,
659                                       y,
660                                       prcl,
661                                       fl);
662         /* Set MovePointer to the eng function */
663         ppdev->pfnMovePointer = EngMovePointer;
664     }
665 
666     return ulResult;
667 }
668 
669 ULONG
670 NTAPI
671 GreSetPointerShape(
672     _In_ HDC hdc,
673     _In_opt_ HBITMAP hbmMask,
674     _In_opt_ HBITMAP hbmColor,
675     _In_ LONG xHot,
676     _In_ LONG yHot,
677     _In_ LONG x,
678     _In_ LONG y,
679     _In_ FLONG fl)
680 {
681     PDC pdc;
682     PSURFACE psurf, psurfMask, psurfColor;
683     EXLATEOBJ exlo;
684     ULONG ulResult = 0;
685 
686     pdc = DC_LockDc(hdc);
687     if (!pdc)
688     {
689         DPRINT1("Failed to lock the DC.\n");
690         return 0;
691     }
692 
693     ASSERT(pdc->dctype == DCTYPE_DIRECT);
694     EngAcquireSemaphore(pdc->ppdev->hsemDevLock);
695     /* We're not sure DC surface is the good one */
696     psurf = pdc->ppdev->pSurface;
697     if (!psurf)
698     {
699         DPRINT1("DC has no surface.\n");
700         EngReleaseSemaphore(pdc->ppdev->hsemDevLock);
701         DC_UnlockDc(pdc);
702         return 0;
703     }
704 
705     /* Lock the mask bitmap */
706     if (hbmMask)
707     {
708         psurfMask = SURFACE_ShareLockSurface(hbmMask);
709     }
710     else
711     {
712         //ASSERT(fl & SPS_ALPHA);
713         psurfMask = NULL;
714     }
715 
716     /* Check for color bitmap */
717     if (hbmColor)
718     {
719         /* We have one, lock it */
720         psurfColor = SURFACE_ShareLockSurface(hbmColor);
721 
722         if (psurfColor)
723         {
724             /* Create an XLATEOBJ, no mono support */
725             EXLATEOBJ_vInitialize(&exlo, psurfColor->ppal, psurf->ppal, 0, 0, 0);
726         }
727     }
728     else
729         psurfColor = NULL;
730 
731     /* We must have a valid surface in case of alpha bitmap */
732     ASSERT(((fl & SPS_ALPHA) && psurfColor) || !(fl & SPS_ALPHA));
733 
734     /* Call the driver or eng function */
735     ulResult = IntEngSetPointerShape(&psurf->SurfObj,
736                                      psurfMask ? &psurfMask->SurfObj : NULL,
737                                      psurfColor ? &psurfColor->SurfObj : NULL,
738                                      psurfColor ? &exlo.xlo : NULL,
739                                      xHot,
740                                      yHot,
741                                      x,
742                                      y,
743                                      &pdc->ppdev->Pointer.Exclude,
744                                      fl | SPS_CHANGE);
745 
746     /* Cleanup */
747     if (psurfColor)
748     {
749         EXLATEOBJ_vCleanup(&exlo);
750         SURFACE_ShareUnlockSurface(psurfColor);
751     }
752 
753     if (psurfMask)
754         SURFACE_ShareUnlockSurface(psurfMask);
755 
756     EngReleaseSemaphore(pdc->ppdev->hsemDevLock);
757 
758     /* Unlock the DC */
759     DC_UnlockDc(pdc);
760 
761     /* Return result */
762     return ulResult;
763 }
764 
765 VOID
766 NTAPI
767 GreMovePointer(
768     _In_ HDC hdc,
769     _In_ LONG x,
770     _In_ LONG y)
771 {
772     PDC pdc;
773     PRECTL prcl;
774 
775     /* Lock the DC */
776     pdc = DC_LockDc(hdc);
777     if (!pdc)
778     {
779         DPRINT1("Failed to lock the DC.\n");
780         return;
781     }
782     ASSERT(pdc->dctype == DCTYPE_DIRECT);
783 
784     /* Acquire PDEV lock */
785     EngAcquireSemaphore(pdc->ppdev->hsemDevLock);
786 
787     /* Check if we need to move it */
788     if(pdc->ppdev->SafetyRemoveLevel == 0)
789     {
790         /* Store the cursor exclude position in the PDEV */
791         prcl = &pdc->ppdev->Pointer.Exclude;
792 
793         /* Call Eng/Drv function */
794         pdc->ppdev->pfnMovePointer(&pdc->ppdev->pSurface->SurfObj, x, y, prcl);
795     }
796 
797     /* Release PDEV lock */
798     EngReleaseSemaphore(pdc->ppdev->hsemDevLock);
799 
800     /* Unlock the DC */
801     DC_UnlockDc(pdc);
802 }
803 
804 
805 /* EOF */
806