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