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