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