2f30a7569aaf077c4302f4ec2d0ea86185b8e7f8
[reactos.git] / reactos / subsystems / win32 / win32k / eng / mouse.c
1 /*
2 * PROJECT: ReactOS win32 subsystem
3 * PURPOSE: Mouse pointer functions
4 * FILE: subsystems/win32k/eng/mouse.c
5 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
6 * Timo Kreuzer (timo.kreuzer@reactos.org)
7 * REVISION HISTORY:
8 * 06-06-2001 CSH Created
9 */
10 /* INCLUDES ******************************************************************/
11
12 #include <win32k.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17 /* FUNCTIONS *****************************************************************/
18
19 BOOL
20 APIENTRY
21 EngSetPointerTag(
22 IN HDEV hdev,
23 IN SURFOBJ *psoMask,
24 IN SURFOBJ *psoColor,
25 IN 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 INT NTAPI
39 MouseSafetyOnDrawStart(
40 PPDEVOBJ ppdev,
41 LONG HazardX1,
42 LONG HazardY1,
43 LONG HazardX2,
44 LONG HazardY2)
45 {
46 LONG tmp;
47 GDIPOINTER *pgp;
48
49 ASSERT(ppdev != NULL);
50 ASSERT(ppdev->pSurface != NULL);
51
52 pgp = &ppdev->Pointer;
53
54 if (pgp->Exclude.right == -1)
55 {
56 return FALSE;
57 }
58
59 ppdev->SafetyRemoveCount++;
60
61 if (ppdev->SafetyRemoveLevel != 0)
62 {
63 return FALSE;
64 }
65
66 if (HazardX1 > HazardX2)
67 {
68 tmp = HazardX2;
69 HazardX2 = HazardX1;
70 HazardX1 = tmp;
71 }
72 if (HazardY1 > HazardY2)
73 {
74 tmp = HazardY2;
75 HazardY2 = HazardY1;
76 HazardY1 = tmp;
77 }
78
79 if (pgp->Exclude.right >= HazardX1
80 && pgp->Exclude.left <= HazardX2
81 && pgp->Exclude.bottom >= HazardY1
82 && pgp->Exclude.top <= HazardY2)
83 {
84 ppdev->SafetyRemoveLevel = ppdev->SafetyRemoveCount;
85 ppdev->pfnMovePointer(&ppdev->pSurface->SurfObj, -1, -1, NULL);
86 }
87
88 return(TRUE);
89 }
90
91 /*
92 * FUNCTION: Notify the mouse driver that drawing has finished on a surface.
93 */
94 INT NTAPI
95 MouseSafetyOnDrawEnd(
96 PPDEVOBJ ppdev)
97 {
98 GDIPOINTER *pgp;
99
100 ASSERT(ppdev != NULL);
101 ASSERT(ppdev->pSurface != NULL);
102
103 pgp = &ppdev->Pointer;
104
105 if (pgp->Exclude.right == -1)
106 {
107 return FALSE;
108 }
109
110 if (--ppdev->SafetyRemoveCount >= ppdev->SafetyRemoveLevel)
111 {
112 return FALSE;
113 }
114
115 ppdev->pfnMovePointer(&ppdev->pSurface->SurfObj,
116 gpsi->ptCursor.x,
117 gpsi->ptCursor.y,
118 &pgp->Exclude);
119
120 ppdev->SafetyRemoveLevel = 0;
121
122 return(TRUE);
123 }
124
125 /* SOFTWARE MOUSE POINTER IMPLEMENTATION **************************************/
126
127 VOID
128 NTAPI
129 IntHideMousePointer(
130 PDEVOBJ *ppdev,
131 SURFOBJ *psoDest)
132 {
133 GDIPOINTER *pgp;
134 POINTL pt;
135 RECTL rclDest;
136 POINTL ptlSave;
137
138 ASSERT(ppdev);
139 ASSERT(psoDest);
140
141 pgp = &ppdev->Pointer;
142
143 if (!pgp->Enabled)
144 {
145 return;
146 }
147
148 pgp->Enabled = FALSE;
149
150 if (!pgp->psurfSave)
151 {
152 DPRINT1("No SaveSurface!\n");
153 return;
154 }
155
156 /* Calculate cursor coordinates */
157 pt.x = ppdev->ptlPointer.x - pgp->HotSpot.x;
158 pt.y = ppdev->ptlPointer.y - pgp->HotSpot.y;
159
160 rclDest.left = max(pt.x, 0);
161 rclDest.top = max(pt.y, 0);
162 rclDest.right = min(pt.x + pgp->Size.cx, psoDest->sizlBitmap.cx);
163 rclDest.bottom = min(pt.y + pgp->Size.cy, psoDest->sizlBitmap.cy);
164
165 ptlSave.x = rclDest.left - pt.x;
166 ptlSave.y = rclDest.top - pt.y;
167
168 IntEngBitBlt(psoDest,
169 &pgp->psurfSave->SurfObj,
170 NULL,
171 NULL,
172 NULL,
173 &rclDest,
174 &ptlSave,
175 &ptlSave,
176 NULL,
177 NULL,
178 ROP4_FROM_INDEX(R3_OPINDEX_SRCCOPY));
179 }
180
181 VOID
182 NTAPI
183 IntShowMousePointer(PDEVOBJ *ppdev, SURFOBJ *psoDest)
184 {
185 GDIPOINTER *pgp;
186 POINTL pt;
187 RECTL rclSurf, rclPointer;
188
189 ASSERT(ppdev);
190 ASSERT(psoDest);
191
192 pgp = &ppdev->Pointer;
193
194 if (pgp->Enabled)
195 {
196 return;
197 }
198
199 pgp->Enabled = TRUE;
200
201 /* Check if we have any mouse pointer */
202 if (!pgp->psurfSave) return;
203
204 /* Calculate pointer coordinates */
205 pt.x = ppdev->ptlPointer.x - pgp->HotSpot.x;
206 pt.y = ppdev->ptlPointer.y - pgp->HotSpot.y;
207
208 /* Calculate the rect on the surface */
209 rclSurf.left = max(pt.x, 0);
210 rclSurf.top = max(pt.y, 0);
211 rclSurf.right = min(pt.x + pgp->Size.cx, psoDest->sizlBitmap.cx);
212 rclSurf.bottom = min(pt.y + pgp->Size.cy, psoDest->sizlBitmap.cy);
213
214 /* Calculate the rect in the pointer bitmap */
215 rclPointer.left = rclSurf.left - pt.x;
216 rclPointer.top = rclSurf.top - pt.y;
217 rclPointer.right = min(pgp->Size.cx, psoDest->sizlBitmap.cx - pt.x);
218 rclPointer.bottom = min(pgp->Size.cy, psoDest->sizlBitmap.cy - pt.y);
219
220 /* Copy the pixels under the cursor to temporary surface. */
221 IntEngBitBlt(&pgp->psurfSave->SurfObj,
222 psoDest,
223 NULL,
224 NULL,
225 NULL,
226 &rclPointer,
227 (POINTL*)&rclSurf,
228 NULL,
229 NULL,
230 NULL,
231 ROP4_FROM_INDEX(R3_OPINDEX_SRCCOPY));
232
233 /* Blt the pointer on the screen. */
234 if (pgp->psurfColor)
235 {
236 IntEngBitBlt(psoDest,
237 &pgp->psurfMask->SurfObj,
238 NULL,
239 NULL,
240 NULL,
241 &rclSurf,
242 (POINTL*)&rclPointer,
243 NULL,
244 NULL,
245 NULL,
246 ROP4_FROM_INDEX(R3_OPINDEX_SRCAND));
247
248 IntEngBitBlt(psoDest,
249 &pgp->psurfColor->SurfObj,
250 NULL,
251 NULL,
252 NULL,
253 &rclSurf,
254 (POINTL*)&rclPointer,
255 NULL,
256 NULL,
257 NULL,
258 ROP4_FROM_INDEX(R3_OPINDEX_SRCINVERT));
259 }
260 else
261 {
262 IntEngBitBlt(psoDest,
263 &pgp->psurfMask->SurfObj,
264 NULL,
265 NULL,
266 NULL,
267 &rclSurf,
268 (POINTL*)&rclPointer,
269 NULL,
270 NULL,
271 NULL,
272 ROP4_FROM_INDEX(R3_OPINDEX_SRCAND));
273
274 rclPointer.top += pgp->Size.cy;
275
276 IntEngBitBlt(psoDest,
277 &pgp->psurfMask->SurfObj,
278 NULL,
279 NULL,
280 NULL,
281 &rclSurf,
282 (POINTL*)&rclPointer,
283 NULL,
284 NULL,
285 NULL,
286 ROP4_FROM_INDEX(R3_OPINDEX_SRCINVERT));
287 }
288 }
289
290 /*
291 * @implemented
292 */
293 ULONG APIENTRY
294 EngSetPointerShape(
295 IN SURFOBJ *pso,
296 IN SURFOBJ *psoMask,
297 IN SURFOBJ *psoColor,
298 IN XLATEOBJ *pxlo,
299 IN LONG xHot,
300 IN LONG yHot,
301 IN LONG x,
302 IN LONG y,
303 IN RECTL *prcl,
304 IN FLONG fl)
305 {
306 PDEVOBJ *ppdev;
307 GDIPOINTER *pgp;
308 LONG lDelta = 0;
309 HBITMAP hbmSave = NULL, hbmColor = NULL, hbmMask = NULL;
310 PSURFACE psurfSave = NULL, psurfColor = NULL, psurfMask = NULL;
311 RECTL rectl;
312 SIZEL sizel = {0, 0};
313
314 ASSERT(pso);
315
316 ppdev = GDIDEV(pso);
317 pgp = &ppdev->Pointer;
318
319 /* Do we have any bitmap at all? */
320 if (psoColor || psoMask)
321 {
322 /* Get the size of the new pointer */
323 if (psoColor)
324 {
325 sizel.cx = psoColor->sizlBitmap.cx;
326 sizel.cy = psoColor->sizlBitmap.cy;
327 }
328 else// if (psoMask)
329 {
330 sizel.cx = psoMask->sizlBitmap.cx;
331 sizel.cy = psoMask->sizlBitmap.cy / 2;
332 }
333
334 rectl.left = 0;
335 rectl.top = 0;
336 rectl.right = sizel.cx;
337 rectl.bottom = sizel.cy;
338
339 /* Calculate lDelta for our surfaces. */
340 lDelta = WIDTH_BYTES_ALIGN32(sizel.cx,
341 BitsPerFormat(pso->iBitmapFormat));
342
343 /* Create a bitmap for saving the pixels under the cursor. */
344 hbmSave = EngCreateBitmap(sizel,
345 lDelta,
346 pso->iBitmapFormat,
347 BMF_TOPDOWN | BMF_NOZEROINIT,
348 NULL);
349 psurfSave = SURFACE_ShareLockSurface(hbmSave);
350 if (!psurfSave) goto failure;
351 }
352
353 if (psoColor)
354 {
355 /* Color bitmap must have the same format as the dest surface */
356 if (psoColor->iBitmapFormat != pso->iBitmapFormat) goto failure;
357
358 /* Create a bitmap to copy the color bitmap to */
359 hbmColor = EngCreateBitmap(psoColor->sizlBitmap,
360 lDelta,
361 pso->iBitmapFormat,
362 BMF_TOPDOWN | BMF_NOZEROINIT,
363 NULL);
364 psurfColor = SURFACE_ShareLockSurface(hbmColor);
365 if (!psurfColor) goto failure;
366
367 /* Now copy the given bitmap */
368 rectl.bottom = psoColor->sizlBitmap.cy;
369 IntEngCopyBits(&psurfColor->SurfObj,
370 psoColor,
371 NULL,
372 pxlo,
373 &rectl,
374 (POINTL*)&rectl);
375 }
376
377 /* Create a mask surface */
378 if (psoMask)
379 {
380 EXLATEOBJ exlo;
381 PPALETTE ppal;
382
383 /* Create a bitmap for the mask */
384 hbmMask = EngCreateBitmap(psoMask->sizlBitmap,
385 lDelta,
386 pso->iBitmapFormat,
387 BMF_TOPDOWN | BMF_NOZEROINIT,
388 NULL);
389 psurfMask = SURFACE_ShareLockSurface(hbmMask);
390 if (!psurfMask) goto failure;
391
392 /* Initialize an EXLATEOBJ */
393 ppal = PALETTE_ShareLockPalette(ppdev->devinfo.hpalDefault);
394 EXLATEOBJ_vInitialize(&exlo,
395 &gpalMono,
396 ppal,
397 0,
398 RGB(0xff,0xff,0xff),
399 RGB(0,0,0));
400
401 /* Copy the mask bitmap */
402 rectl.bottom = psoMask->sizlBitmap.cy;
403 IntEngCopyBits(&psurfMask->SurfObj,
404 psoMask,
405 NULL,
406 &exlo.xlo,
407 &rectl,
408 (POINTL*)&rectl);
409
410 /* Cleanup */
411 EXLATEOBJ_vCleanup(&exlo);
412 if (ppal) PALETTE_ShareUnlockPalette(ppal);
413 }
414
415 /* Hide mouse pointer */
416 IntHideMousePointer(ppdev, pso);
417
418 /* Free old color bitmap */
419 if (pgp->psurfColor)
420 {
421 EngDeleteSurface(pgp->psurfColor->BaseObject.hHmgr);
422 SURFACE_ShareUnlockSurface(pgp->psurfColor);
423 pgp->psurfColor = NULL;
424 }
425
426 /* Free old mask bitmap */
427 if (pgp->psurfMask)
428 {
429 EngDeleteSurface(pgp->psurfMask->BaseObject.hHmgr);
430 SURFACE_ShareUnlockSurface(pgp->psurfMask);
431 pgp->psurfMask = NULL;
432 }
433
434 /* Free old save bitmap */
435 if (pgp->psurfSave)
436 {
437 EngDeleteSurface(pgp->psurfSave->BaseObject.hHmgr);
438 SURFACE_ShareUnlockSurface(pgp->psurfSave);
439 pgp->psurfSave = NULL;
440 }
441
442 /* See if we are being asked to hide the pointer. */
443 if (psoMask == NULL && psoColor == NULL)
444 {
445 /* We're done */
446 return SPS_ACCEPT_NOEXCLUDE;
447 }
448
449 /* Now set the new cursor */
450 pgp->psurfColor = psurfColor;
451 pgp->psurfMask = psurfMask;
452 pgp->psurfSave = psurfSave;
453 pgp->HotSpot.x = xHot;
454 pgp->HotSpot.y = yHot;
455 pgp->Size = sizel;
456
457 if (x != -1)
458 {
459 ppdev->ptlPointer.x = x;
460 ppdev->ptlPointer.y = y;
461
462 IntShowMousePointer(ppdev, pso);
463
464 if (prcl != NULL)
465 {
466 prcl->left = x - pgp->HotSpot.x;
467 prcl->top = y - pgp->HotSpot.x;
468 prcl->right = prcl->left + pgp->Size.cx;
469 prcl->bottom = prcl->top + pgp->Size.cy;
470 }
471 }
472 else if (prcl != NULL)
473 {
474 prcl->left = prcl->top = prcl->right = prcl->bottom = -1;
475 }
476
477 return SPS_ACCEPT_NOEXCLUDE;
478
479 failure:
480 /* Cleanup surfaces */
481 if (hbmMask) EngDeleteSurface(hbmMask);
482 if (psurfMask) SURFACE_ShareUnlockSurface(psurfMask);
483 if (hbmColor) EngDeleteSurface(hbmColor);
484 if (psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
485 if (hbmSave) EngDeleteSurface(hbmSave);
486 if (psurfSave) SURFACE_ShareUnlockSurface(psurfSave);
487
488 return SPS_ERROR;
489 }
490
491 /*
492 * @implemented
493 */
494
495 VOID APIENTRY
496 EngMovePointer(
497 IN SURFOBJ *pso,
498 IN LONG x,
499 IN LONG y,
500 IN RECTL *prcl)
501 {
502 PDEVOBJ *ppdev;
503 GDIPOINTER *pgp;
504
505 ASSERT(pso);
506
507 ppdev = GDIDEV(pso);
508 ASSERT(ppdev);
509
510 pgp = &ppdev->Pointer;
511
512 IntHideMousePointer(ppdev, pso);
513
514 ppdev->ptlPointer.x = x;
515 ppdev->ptlPointer.y = y;
516
517 if (x != -1)
518 {
519 IntShowMousePointer(ppdev, pso);
520 if (prcl != NULL)
521 {
522 prcl->left = x - pgp->HotSpot.x;
523 prcl->top = y - pgp->HotSpot.y;
524 prcl->right = prcl->left + pgp->Size.cx;
525 prcl->bottom = prcl->top + pgp->Size.cy;
526 }
527 }
528 else if (prcl != NULL)
529 {
530 prcl->left = prcl->top = prcl->right = prcl->bottom = -1;
531 }
532 }
533
534 ULONG APIENTRY
535 IntEngSetPointerShape(
536 IN SURFOBJ *pso,
537 IN SURFOBJ *psoMask,
538 IN SURFOBJ *psoColor,
539 IN XLATEOBJ *pxlo,
540 IN LONG xHot,
541 IN LONG yHot,
542 IN LONG x,
543 IN LONG y,
544 IN RECTL *prcl,
545 IN FLONG fl)
546 {
547 ULONG ulResult = SPS_DECLINE;
548 PFN_DrvSetPointerShape pfnSetPointerShape;
549 PPDEVOBJ ppdev = GDIDEV(pso);
550
551 pfnSetPointerShape = GDIDEVFUNCS(pso).SetPointerShape;
552
553 if (pfnSetPointerShape)
554 {
555 ulResult = pfnSetPointerShape(pso,
556 psoMask,
557 psoColor,
558 pxlo,
559 xHot,
560 yHot,
561 x,
562 y,
563 prcl,
564 fl);
565 }
566
567 /* Check if the driver accepted it */
568 if (ulResult == SPS_ACCEPT_NOEXCLUDE)
569 {
570 /* Set MovePointer to the driver function */
571 ppdev->pfnMovePointer = GDIDEVFUNCS(pso).MovePointer;
572 }
573 else
574 {
575 /* Set software pointer */
576 ulResult = EngSetPointerShape(pso,
577 psoMask,
578 psoColor,
579 pxlo,
580 xHot,
581 yHot,
582 x,
583 y,
584 prcl,
585 fl);
586 /* Set MovePointer to the eng function */
587 ppdev->pfnMovePointer = EngMovePointer;
588 }
589
590 return ulResult;
591 }
592
593 ULONG
594 NTAPI
595 GreSetPointerShape(
596 HDC hdc,
597 HBITMAP hbmMask,
598 HBITMAP hbmColor,
599 LONG xHot,
600 LONG yHot,
601 LONG x,
602 LONG y)
603 {
604 PDC pdc;
605 PSURFACE psurf, psurfMask, psurfColor;
606 EXLATEOBJ exlo;
607 FLONG fl = 0;
608 ULONG ulResult = 0;
609
610 pdc = DC_LockDc(hdc);
611 if (!pdc)
612 {
613 DPRINT1("Failed to lock the DC.\n");
614 return 0;
615 }
616
617 ASSERT(pdc->dctype == DCTYPE_DIRECT);
618 EngAcquireSemaphore(pdc->ppdev->hsemDevLock);
619 /* We're not sure DC surface is the good one */
620 psurf = pdc->ppdev->pSurface;
621 if (!psurf)
622 {
623 DPRINT1("DC has no surface.\n");
624 EngReleaseSemaphore(pdc->ppdev->hsemDevLock);
625 DC_UnlockDc(pdc);
626 return 0;
627 }
628
629 /* Lock the mask bitmap */
630 if (hbmMask)
631 psurfMask = SURFACE_ShareLockSurface(hbmMask);
632 else
633 psurfMask = NULL;
634
635 /* Check for color bitmap */
636 if (hbmColor)
637 {
638 /* We have one, lock it */
639 psurfColor = SURFACE_ShareLockSurface(hbmColor);
640
641 if (psurfColor)
642 {
643 /* Create an XLATEOBJ, no mono support */
644 EXLATEOBJ_vInitialize(&exlo, psurfColor->ppal, psurf->ppal, 0, 0, 0);
645 }
646 }
647 else
648 psurfColor = NULL;
649
650 /* Call the driver or eng function */
651 ulResult = IntEngSetPointerShape(&psurf->SurfObj,
652 psurfMask ? &psurfMask->SurfObj : NULL,
653 psurfColor ? &psurfColor->SurfObj : NULL,
654 psurfColor ? &exlo.xlo : NULL,
655 xHot,
656 yHot,
657 x,
658 y,
659 &pdc->ppdev->Pointer.Exclude,
660 fl | SPS_CHANGE);
661
662 /* Cleanup */
663 if (psurfColor)
664 {
665 EXLATEOBJ_vCleanup(&exlo);
666 SURFACE_ShareUnlockSurface(psurfColor);
667 }
668
669 if (psurfMask)
670 SURFACE_ShareUnlockSurface(psurfMask);
671
672 EngReleaseSemaphore(pdc->ppdev->hsemDevLock);
673
674 /* Unlock the DC */
675 DC_UnlockDc(pdc);
676
677 /* Return result */
678 return ulResult;
679 }
680
681 VOID
682 NTAPI
683 GreMovePointer(
684 HDC hdc,
685 LONG x,
686 LONG y)
687 {
688 PDC pdc;
689 PRECTL prcl;
690
691 /* Lock the DC */
692 pdc = DC_LockDc(hdc);
693 if (!pdc)
694 {
695 DPRINT1("Failed to lock the DC.\n");
696 return;
697 }
698 ASSERT(pdc->dctype == DCTYPE_DIRECT);
699
700 /* Acquire PDEV lock */
701 EngAcquireSemaphore(pdc->ppdev->hsemDevLock);
702
703 /* Check if we need to move it */
704 if(pdc->ppdev->SafetyRemoveLevel == 0)
705 {
706 /* Store the cursor exclude position in the PDEV */
707 prcl = &pdc->ppdev->Pointer.Exclude;
708
709 /* Call Eng/Drv function */
710 pdc->ppdev->pfnMovePointer(&pdc->ppdev->pSurface->SurfObj, x, y, prcl);
711 }
712
713 /* Release PDEV lock */
714 EngReleaseSemaphore(pdc->ppdev->hsemDevLock);
715
716 /* Unlock the DC */
717 DC_UnlockDc(pdc);
718 }
719
720
721 /* EOF */