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