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