ec6c3b4d3c9dce26b076d06d73eb73d671391756
[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 <w32k.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 IntEngBitBltEx(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 FALSE);
177 }
178
179 VOID
180 INTERNAL_CALL
181 IntShowMousePointer(PDEVOBJ *ppdev, SURFOBJ *psoDest)
182 {
183 GDIPOINTER *pgp;
184 POINTL pt;
185 RECTL rclSurf, rclPointer;
186
187 ASSERT(ppdev);
188 ASSERT(psoDest);
189
190 pgp = &ppdev->Pointer;
191
192 if (pgp->Enabled)
193 {
194 return;
195 }
196
197 pgp->Enabled = TRUE;
198
199 /* Calculate pointer coordinates */
200 pt.x = ppdev->ptlPointer.x - pgp->HotSpot.x;
201 pt.y = ppdev->ptlPointer.y - pgp->HotSpot.y;
202
203 /* Calculate the rect on the surface */
204 rclSurf.left = max(pt.x, 0);
205 rclSurf.top = max(pt.y, 0);
206 rclSurf.right = min(pt.x + pgp->Size.cx, psoDest->sizlBitmap.cx);
207 rclSurf.bottom = min(pt.y + pgp->Size.cy, psoDest->sizlBitmap.cy);
208
209 /* Calculate the rect in the pointer bitmap */
210 rclPointer.left = rclSurf.left - pt.x;
211 rclPointer.top = rclSurf.top - pt.y;
212 rclPointer.right = min(pgp->Size.cx, psoDest->sizlBitmap.cx - pt.x);
213 rclPointer.bottom = min(pgp->Size.cy, psoDest->sizlBitmap.cy - pt.y);
214
215 /* Copy the pixels under the cursor to temporary surface. */
216 IntEngBitBltEx(&pgp->psurfSave->SurfObj,
217 psoDest,
218 NULL,
219 NULL,
220 NULL,
221 &rclPointer,
222 (POINTL*)&rclSurf,
223 NULL,
224 NULL,
225 NULL,
226 ROP3_TO_ROP4(SRCCOPY),
227 FALSE);
228
229 /* Blt the pointer on the screen. */
230 if (pgp->psurfColor)
231 {
232 IntEngBitBltEx(psoDest,
233 &pgp->psurfMask->SurfObj,
234 NULL,
235 NULL,
236 NULL,
237 &rclSurf,
238 (POINTL*)&rclPointer,
239 NULL,
240 NULL,
241 NULL,
242 ROP3_TO_ROP4(SRCAND),
243 FALSE);
244
245 IntEngBitBltEx(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 FALSE);
257 }
258 else
259 {
260 IntEngBitBltEx(psoDest,
261 &pgp->psurfMask->SurfObj,
262 NULL,
263 NULL,
264 NULL,
265 &rclSurf,
266 (POINTL*)&rclPointer,
267 NULL,
268 NULL,
269 NULL,
270 ROP3_TO_ROP4(SRCAND),
271 FALSE);
272
273 rclPointer.top += pgp->Size.cy;
274
275 IntEngBitBltEx(psoDest,
276 &pgp->psurfMask->SurfObj,
277 NULL,
278 NULL,
279 NULL,
280 &rclSurf,
281 (POINTL*)&rclPointer,
282 NULL,
283 NULL,
284 NULL,
285 ROP3_TO_ROP4(SRCINVERT),
286 FALSE);
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;
309 HBITMAP hbmp;
310 RECTL rcl;
311
312 ASSERT(pso);
313
314 ppdev = GDIDEV(pso);
315 pgp = &ppdev->Pointer;
316
317 if (psoColor)
318 {
319 pgp->Size.cx = psoColor->sizlBitmap.cx;
320 pgp->Size.cy = psoColor->sizlBitmap.cy;
321 if (psoMask)
322 {
323 // CHECKME: Is this really required? if we have a color surface,
324 // we only need the AND part of the mask.
325 /* Check if the sizes match as they should */
326 if (psoMask->sizlBitmap.cx != psoColor->sizlBitmap.cx ||
327 psoMask->sizlBitmap.cy != psoColor->sizlBitmap.cy * 2)
328 {
329 DPRINT("Sizes of mask (%ld,%ld) and color (%ld,%ld) don't match\n",
330 psoMask->sizlBitmap.cx, psoMask->sizlBitmap.cy,
331 psoColor->sizlBitmap.cx, psoColor->sizlBitmap.cy);
332 // return SPS_ERROR;
333 }
334 }
335 }
336 else if (psoMask)
337 {
338 pgp->Size.cx = psoMask->sizlBitmap.cx;
339 pgp->Size.cy = psoMask->sizlBitmap.cy / 2;
340 }
341
342 IntHideMousePointer(ppdev, pso);
343
344 if (pgp->psurfColor)
345 {
346 EngDeleteSurface(pgp->psurfColor->BaseObject.hHmgr);
347 SURFACE_ShareUnlockSurface(pgp->psurfColor);
348 pgp->psurfColor = NULL;
349 }
350
351 if (pgp->psurfMask)
352 {
353 EngDeleteSurface(pgp->psurfMask->BaseObject.hHmgr);
354 SURFACE_ShareUnlockSurface(pgp->psurfMask);
355 pgp->psurfMask = NULL;
356 }
357
358 if (pgp->psurfSave != NULL)
359 {
360 EngDeleteSurface(pgp->psurfSave->BaseObject.hHmgr);
361 SURFACE_ShareUnlockSurface(pgp->psurfSave);
362 pgp->psurfSave = NULL;
363 }
364
365 /* See if we are being asked to hide the pointer. */
366 if (psoMask == NULL && psoColor == NULL)
367 {
368 return SPS_ACCEPT_NOEXCLUDE;
369 }
370
371 pgp->HotSpot.x = xHot;
372 pgp->HotSpot.y = yHot;
373
374 /* Calculate lDelta for our surfaces. */
375 lDelta = DIB_GetDIBWidthBytes(pgp->Size.cx,
376 BitsPerFormat(pso->iBitmapFormat));
377
378 rcl.left = 0;
379 rcl.top = 0;
380 rcl.right = pgp->Size.cx;
381 rcl.bottom = pgp->Size.cy;
382
383 /* Create surface for saving the pixels under the cursor. */
384 hbmp = EngCreateBitmap(pgp->Size,
385 lDelta,
386 pso->iBitmapFormat,
387 BMF_TOPDOWN | BMF_NOZEROINIT,
388 NULL);
389 pgp->psurfSave = SURFACE_ShareLockSurface(hbmp);
390
391 /* Create a mask surface */
392 if (psoMask)
393 {
394 EXLATEOBJ exlo;
395 PPALETTE ppal;
396
397 hbmp = EngCreateBitmap(psoMask->sizlBitmap,
398 lDelta,
399 pso->iBitmapFormat,
400 BMF_TOPDOWN | BMF_NOZEROINIT,
401 NULL);
402 pgp->psurfMask = SURFACE_ShareLockSurface(hbmp);
403
404 if(pgp->psurfMask)
405 {
406 ppal = PALETTE_LockPalette(ppdev->devinfo.hpalDefault);
407 EXLATEOBJ_vInitialize(&exlo,
408 &gpalMono,
409 ppal,
410 0,
411 RGB(0xff,0xff,0xff),
412 RGB(0,0,0));
413
414 rcl.bottom = psoMask->sizlBitmap.cy;
415 IntEngCopyBits(&pgp->psurfMask->SurfObj,
416 psoMask,
417 NULL,
418 &exlo.xlo,
419 &rcl,
420 (POINTL*)&rcl);
421
422 EXLATEOBJ_vCleanup(&exlo);
423 if (ppal)
424 PALETTE_UnlockPalette(ppal);
425 }
426 }
427 else
428 {
429 pgp->psurfMask = NULL;
430 }
431
432 /* Create a color surface */
433 if (psoColor)
434 {
435 hbmp = EngCreateBitmap(psoColor->sizlBitmap,
436 lDelta,
437 pso->iBitmapFormat,
438 BMF_TOPDOWN | BMF_NOZEROINIT,
439 NULL);
440 pgp->psurfColor = SURFACE_ShareLockSurface(hbmp);
441 if (pgp->psurfColor)
442 {
443 rcl.bottom = psoColor->sizlBitmap.cy;
444 IntEngCopyBits(&pgp->psurfColor->SurfObj,
445 psoColor,
446 NULL,
447 pxlo,
448 &rcl,
449 (POINTL*)&rcl);
450 }
451 }
452 else
453 {
454 pgp->psurfColor = NULL;
455 }
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
480 /*
481 * @implemented
482 */
483
484 VOID APIENTRY
485 EngMovePointer(
486 IN SURFOBJ *pso,
487 IN LONG x,
488 IN LONG y,
489 IN RECTL *prcl)
490 {
491 PDEVOBJ *ppdev;
492 GDIPOINTER *pgp;
493
494 ASSERT(pso);
495
496 ppdev = GDIDEV(pso);
497 ASSERT(ppdev);
498
499 pgp = &ppdev->Pointer;
500
501 IntHideMousePointer(ppdev, pso);
502
503 ppdev->ptlPointer.x = x;
504 ppdev->ptlPointer.y = y;
505
506 if (x != -1)
507 {
508 IntShowMousePointer(ppdev, pso);
509 if (prcl != NULL)
510 {
511 prcl->left = x - pgp->HotSpot.x;
512 prcl->top = y - pgp->HotSpot.y;
513 prcl->right = prcl->left + pgp->Size.cx;
514 prcl->bottom = prcl->top + pgp->Size.cy;
515 }
516 }
517 else if (prcl != NULL)
518 {
519 prcl->left = prcl->top = prcl->right = prcl->bottom = -1;
520 }
521 }
522
523 VOID APIENTRY
524 IntEngMovePointer(
525 IN SURFOBJ *pso,
526 IN LONG x,
527 IN LONG y,
528 IN RECTL *prcl)
529 {
530 PPDEVOBJ ppdev = (PPDEVOBJ)pso->hdev;
531 if(ppdev->SafetyRemoveLevel)
532 return ;
533
534 EngAcquireSemaphore(ppdev->hsemDevLock);
535 ppdev->pfnMovePointer(pso, x, y, prcl);
536 EngReleaseSemaphore(ppdev->hsemDevLock);
537 }
538
539 ULONG APIENTRY
540 IntEngSetPointerShape(
541 IN SURFOBJ *pso,
542 IN SURFOBJ *psoMask,
543 IN SURFOBJ *psoColor,
544 IN XLATEOBJ *pxlo,
545 IN LONG xHot,
546 IN LONG yHot,
547 IN LONG x,
548 IN LONG y,
549 IN RECTL *prcl,
550 IN FLONG fl)
551 {
552 ULONG ulResult = SPS_DECLINE;
553 PFN_DrvSetPointerShape pfnSetPointerShape;
554 PPDEVOBJ ppdev = GDIDEV(pso);
555
556 pfnSetPointerShape = GDIDEVFUNCS(pso).SetPointerShape;
557
558 EngAcquireSemaphore(ppdev->hsemDevLock);
559 if (pfnSetPointerShape)
560 {
561 ulResult = pfnSetPointerShape(pso,
562 psoMask,
563 psoColor,
564 pxlo,
565 xHot,
566 yHot,
567 x,
568 y,
569 prcl,
570 fl);
571 }
572
573 /* Check if the driver accepted it */
574 if (ulResult == SPS_ACCEPT_NOEXCLUDE)
575 {
576 /* Set MovePointer to the driver function */
577 ppdev->pfnMovePointer = GDIDEVFUNCS(pso).MovePointer;
578 }
579 else
580 {
581 /* Set software pointer */
582 ulResult = EngSetPointerShape(pso,
583 psoMask,
584 psoColor,
585 pxlo,
586 xHot,
587 yHot,
588 x,
589 y,
590 prcl,
591 fl);
592 /* Set MovePointer to the eng function */
593 ppdev->pfnMovePointer = EngMovePointer;
594 }
595
596 EngReleaseSemaphore(ppdev->hsemDevLock);
597
598 return ulResult;
599 }
600
601 ULONG
602 NTAPI
603 GreSetPointerShape(
604 HDC hdc,
605 HBITMAP hbmMask,
606 HBITMAP hbmColor,
607 LONG xHot,
608 LONG yHot,
609 LONG x,
610 LONG y)
611 {
612 PDC pdc;
613 PSURFACE psurf, psurfMask, psurfColor;
614 EXLATEOBJ exlo;
615 FLONG fl = 0;
616 ULONG ulResult = 0;
617
618 pdc = DC_LockDc(hdc);
619 if (!pdc)
620 {
621 DPRINT1("Failed to lock the DC.\n");
622 return 0;
623 }
624
625 ASSERT(pdc->dctype == DCTYPE_DIRECT);
626 /* We're not sure DC surface is the good one */
627 psurf = pdc->ppdev->pSurface;
628 if (!psurf)
629 {
630 DPRINT1("DC has no surface.\n");
631 DC_UnlockDc(pdc);
632 return 0;
633 }
634
635 /* Lock the mask bitmap */
636 if (hbmMask)
637 psurfMask = SURFACE_ShareLockSurface(hbmMask);
638 else
639 psurfMask = NULL;
640
641 /* Check for color bitmap */
642 if (hbmColor)
643 {
644 /* We have one, lock it */
645 psurfColor = SURFACE_ShareLockSurface(hbmColor);
646
647 if (psurfColor)
648 {
649 /* Create an XLATEOBJ, no mono support */
650 EXLATEOBJ_vInitialize(&exlo, psurfColor->ppal, psurf->ppal, 0, 0, 0);
651 }
652 }
653 else
654 psurfColor = NULL;
655
656 /* Call the driver or eng function */
657 ulResult = IntEngSetPointerShape(&psurf->SurfObj,
658 psurfMask ? &psurfMask->SurfObj : NULL,
659 psurfColor ? &psurfColor->SurfObj : NULL,
660 psurfColor ? &exlo.xlo : NULL,
661 xHot,
662 yHot,
663 x,
664 y,
665 &pdc->ppdev->Pointer.Exclude,
666 fl | SPS_CHANGE);
667
668 /* Cleanup */
669 if (psurfColor)
670 {
671 EXLATEOBJ_vCleanup(&exlo);
672 SURFACE_ShareUnlockSurface(psurfColor);
673 }
674
675 if (psurfMask)
676 SURFACE_ShareUnlockSurface(psurfMask);
677
678 /* Unlock the DC */
679 DC_UnlockDc(pdc);
680
681 /* Return result */
682 return ulResult;
683 }
684
685 VOID
686 NTAPI
687 GreMovePointer(
688 HDC hdc,
689 LONG x,
690 LONG y)
691 {
692 PDC pdc;
693 PRECTL prcl;
694
695 /* Lock the DC */
696 pdc = DC_LockDc(hdc);
697 if (!pdc)
698 {
699 DPRINT1("Failed to lock the DC.\n");
700 return;
701 }
702 ASSERT(pdc->dctype == DCTYPE_DIRECT);
703
704 /* Store the cursor exclude position in the PDEV */
705 prcl = &pdc->ppdev->Pointer.Exclude;
706
707 /* Call Eng/Drv function */
708 IntEngMovePointer(&pdc->ppdev->pSurface->SurfObj, x, y, prcl);
709
710 /* Unlock the DC */
711 DC_UnlockDc(pdc);
712 }
713
714
715 /* EOF */