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 /*
20 * FUNCTION: Notify the mouse driver that drawing is about to begin in
21 * a rectangle on a particular surface.
22 */
23 INT INTERNAL_CALL
24 MouseSafetyOnDrawStart(
25 SURFOBJ *pso,
26 LONG HazardX1,
27 LONG HazardY1,
28 LONG HazardX2,
29 LONG HazardY2)
30 {
31 LONG tmp;
32 PDEVOBJ *ppdev;
33 GDIPOINTER *pgp;
34
35 ASSERT(pso != NULL);
36
37 ppdev = GDIDEV(pso);
38 if (ppdev == NULL)
39 {
40 return FALSE;
41 }
42
43 pgp = &ppdev->Pointer;
44
45 if (pgp->Exclude.right == -1)
46 {
47 return FALSE;
48 }
49
50 ppdev->SafetyRemoveCount++;
51
52 if (ppdev->SafetyRemoveLevel != 0)
53 {
54 return FALSE;
55 }
56
57 if (HazardX1 > HazardX2)
58 {
59 tmp = HazardX2;
60 HazardX2 = HazardX1;
61 HazardX1 = tmp;
62 }
63 if (HazardY1 > HazardY2)
64 {
65 tmp = HazardY2;
66 HazardY2 = HazardY1;
67 HazardY1 = tmp;
68 }
69
70 if (pgp->Exclude.right >= HazardX1
71 && pgp->Exclude.left <= HazardX2
72 && pgp->Exclude.bottom >= HazardY1
73 && pgp->Exclude.top <= HazardY2)
74 {
75 ppdev->SafetyRemoveLevel = ppdev->SafetyRemoveCount;
76 ppdev->pfnMovePointer(pso, -1, -1, NULL);
77 }
78
79 return(TRUE);
80 }
81
82 /*
83 * FUNCTION: Notify the mouse driver that drawing has finished on a surface.
84 */
85 INT INTERNAL_CALL
86 MouseSafetyOnDrawEnd(
87 SURFOBJ *pso)
88 {
89 PDEVOBJ *ppdev;
90 GDIPOINTER *pgp;
91
92 ASSERT(pso != NULL);
93
94 ppdev = (PDEVOBJ*)pso->hdev;
95
96 if (ppdev == NULL)
97 {
98 return(FALSE);
99 }
100
101 pgp = &ppdev->Pointer;
102
103 if (pgp->Exclude.right == -1)
104 {
105 return FALSE;
106 }
107
108 if (--ppdev->SafetyRemoveCount >= ppdev->SafetyRemoveLevel)
109 {
110 return FALSE;
111 }
112
113 ppdev->pfnMovePointer(pso, gpsi->ptCursor.x, gpsi->ptCursor.y, &pgp->Exclude);
114
115 ppdev->SafetyRemoveLevel = 0;
116
117 return(TRUE);
118 }
119
120 /* SOFTWARE MOUSE POINTER IMPLEMENTATION **************************************/
121
122 VOID
123 INTERNAL_CALL
124 IntHideMousePointer(
125 PDEVOBJ *ppdev,
126 SURFOBJ *psoDest)
127 {
128 GDIPOINTER *pgp;
129 POINTL pt;
130 RECTL rclDest;
131 POINTL ptlSave;
132
133 ASSERT(ppdev);
134 ASSERT(psoDest);
135
136 pgp = &ppdev->Pointer;
137
138 if (!pgp->Enabled)
139 {
140 return;
141 }
142
143 pgp->Enabled = FALSE;
144
145 /* The mouse is hide from ShowCours and it is frist ?? */
146 if (pgp->ShowPointer < 0)
147 {
148 return;
149 }
150
151 if (!pgp->psurfSave)
152 {
153 DPRINT1("No SaveSurface!\n");
154 return;
155 }
156
157 /* Calculate cursor coordinates */
158 pt.x = ppdev->ptlPointer.x - pgp->HotSpot.x;
159 pt.y = ppdev->ptlPointer.y - pgp->HotSpot.y;
160
161 rclDest.left = max(pt.x, 0);
162 rclDest.top = max(pt.y, 0);
163 rclDest.right = min(pt.x + pgp->Size.cx, psoDest->sizlBitmap.cx);
164 rclDest.bottom = min(pt.y + pgp->Size.cy, psoDest->sizlBitmap.cy);
165
166 ptlSave.x = rclDest.left - pt.x;
167 ptlSave.y = rclDest.top - pt.y;
168
169 IntEngBitBltEx(psoDest,
170 &pgp->psurfSave->SurfObj,
171 NULL,
172 NULL,
173 NULL,
174 &rclDest,
175 &ptlSave,
176 &ptlSave,
177 NULL,
178 NULL,
179 ROP3_TO_ROP4(SRCCOPY),
180 FALSE);
181 }
182
183 VOID
184 INTERNAL_CALL
185 IntShowMousePointer(PDEVOBJ *ppdev, SURFOBJ *psoDest)
186 {
187 GDIPOINTER *pgp;
188 POINTL pt;
189 RECTL rclSurf, rclPointer;
190
191 ASSERT(ppdev);
192 ASSERT(psoDest);
193
194 pgp = &ppdev->Pointer;
195
196 if (pgp->Enabled)
197 {
198 return;
199 }
200
201 pgp->Enabled = TRUE;
202
203 /* Do not blt the pointer, if it is hidden */
204 if (pgp->ShowPointer < 0)
205 {
206 return ;
207 }
208
209 /* Calculate pointer coordinates */
210 pt.x = ppdev->ptlPointer.x - pgp->HotSpot.x;
211 pt.y = ppdev->ptlPointer.y - pgp->HotSpot.y;
212
213 /* Calculate the rect on the surface */
214 rclSurf.left = max(pt.x, 0);
215 rclSurf.top = max(pt.y, 0);
216 rclSurf.right = min(pt.x + pgp->Size.cx, psoDest->sizlBitmap.cx);
217 rclSurf.bottom = min(pt.y + pgp->Size.cy, psoDest->sizlBitmap.cy);
218
219 /* Calculate the rect in the pointer bitmap */
220 rclPointer.left = rclSurf.left - pt.x;
221 rclPointer.top = rclSurf.top - pt.y;
222 rclPointer.right = min(pgp->Size.cx, psoDest->sizlBitmap.cx - pt.x);
223 rclPointer.bottom = min(pgp->Size.cy, psoDest->sizlBitmap.cy - pt.y);
224
225 /* Copy the pixels under the cursor to temporary surface. */
226 IntEngBitBltEx(&pgp->psurfSave->SurfObj,
227 psoDest,
228 NULL,
229 NULL,
230 NULL,
231 &rclPointer,
232 (POINTL*)&rclSurf,
233 NULL,
234 NULL,
235 NULL,
236 ROP3_TO_ROP4(SRCCOPY),
237 FALSE);
238
239 /* Blt the pointer on the screen. */
240 if (pgp->psurfColor)
241 {
242 IntEngBitBltEx(psoDest,
243 &pgp->psurfColor->SurfObj,
244 &pgp->psurfMask->SurfObj,
245 NULL,
246 pgp->XlateObject,
247 &rclSurf,
248 (POINTL*)&rclPointer,
249 (POINTL*)&rclPointer,
250 NULL,
251 NULL,
252 R4_MASK,
253 FALSE);
254 }
255 else
256 {
257 IntEngBitBltEx(psoDest,
258 &pgp->psurfMask->SurfObj,
259 NULL,
260 NULL,
261 pgp->XlateObject,
262 &rclSurf,
263 (POINTL*)&rclPointer,
264 NULL,
265 NULL,
266 NULL,
267 ROP3_TO_ROP4(SRCAND),
268 FALSE);
269
270 rclPointer.top += pgp->Size.cy;
271
272 IntEngBitBltEx(psoDest,
273 &pgp->psurfMask->SurfObj,
274 NULL,
275 NULL,
276 pgp->XlateObject,
277 &rclSurf,
278 (POINTL*)&rclPointer,
279 NULL,
280 NULL,
281 NULL,
282 ROP3_TO_ROP4(SRCINVERT),
283 FALSE);
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 PBYTE Bits;
306 SIZEL Size;
307 LONG lDelta;
308 HBITMAP hbmp;
309
310 ASSERT(pso);
311
312 ppdev = GDIDEV(pso);
313 pgp = &ppdev->Pointer;
314
315 IntHideMousePointer(ppdev, pso);
316
317 if (pgp->psurfColor)
318 {
319 /* FIXME: let GDI allocate/free memory */
320 EngFreeMem(pgp->psurfColor->SurfObj.pvBits);
321 pgp->psurfColor->SurfObj.pvBits = 0;
322
323 EngDeleteSurface(pgp->psurfColor->BaseObject.hHmgr);
324 SURFACE_ShareUnlockSurface(pgp->psurfColor);
325 pgp->psurfColor = NULL;
326 }
327
328 if (pgp->psurfMask)
329 {
330 /* FIXME: let GDI allocate/free memory */
331 EngFreeMem(pgp->psurfMask->SurfObj.pvBits);
332 pgp->psurfMask->SurfObj.pvBits = 0;
333
334 EngDeleteSurface(pgp->psurfMask->BaseObject.hHmgr);
335 SURFACE_ShareUnlockSurface(pgp->psurfMask);
336 pgp->psurfMask = NULL;
337 }
338
339 if (pgp->psurfSave != NULL)
340 {
341 EngDeleteSurface(pgp->psurfSave->BaseObject.hHmgr);
342 SURFACE_ShareUnlockSurface(pgp->psurfSave);
343 pgp->psurfSave = NULL;
344 }
345
346 if (pgp->XlateObject != NULL)
347 {
348 EngDeleteXlate(pgp->XlateObject);
349 pgp->XlateObject = NULL;
350 }
351
352 /* See if we are being asked to hide the pointer. */
353 if (psoMask == NULL)
354 {
355 return SPS_ACCEPT_NOEXCLUDE;
356 }
357
358 pgp->HotSpot.x = xHot;
359 pgp->HotSpot.y = yHot;
360
361 if (x != -1)
362 {
363 ppdev->ptlPointer.x = x;
364 ppdev->ptlPointer.y = y;
365 }
366
367 pgp->Size.cx = abs(psoMask->lDelta) << 3;
368 pgp->Size.cy = (psoMask->cjBits / abs(psoMask->lDelta)) >> 1;
369
370 if (psoColor != NULL)
371 {
372 /* FIXME: let GDI allocate/free memory */
373 Bits = EngAllocMem(0, psoColor->cjBits, TAG_MOUSE);
374 if (Bits == NULL)
375 {
376 return SPS_ERROR;
377 }
378
379 memcpy(Bits, psoColor->pvBits, psoColor->cjBits);
380
381 hbmp = EngCreateBitmap(pgp->Size,
382 psoColor->lDelta,
383 psoColor->iBitmapFormat,
384 psoColor->lDelta < 0 ? 0 : BMF_TOPDOWN,
385 Bits);
386
387 pgp->psurfColor = SURFACE_ShareLockSurface(hbmp);
388 }
389 else
390 {
391 pgp->psurfColor = NULL;
392 }
393
394 Size.cx = pgp->Size.cx;
395 Size.cy = pgp->Size.cy << 1;
396 Bits = EngAllocMem(0, psoMask->cjBits, TAG_MOUSE);
397 if (Bits == NULL)
398 {
399 return SPS_ERROR;
400 }
401
402 memcpy(Bits, psoMask->pvBits, psoMask->cjBits);
403
404 hbmp = EngCreateBitmap(Size,
405 psoMask->lDelta,
406 psoMask->iBitmapFormat,
407 psoMask->lDelta < 0 ? 0 : BMF_TOPDOWN,
408 Bits);
409
410 pgp->psurfMask = SURFACE_ShareLockSurface(hbmp);
411
412 /* Create an XLATEOBJ that will be used for drawing masks.
413 * FIXME: We should get this in pxlo parameter! */
414 if (pxlo == NULL)
415 {
416 HPALETTE BWPalette, DestPalette;
417 ULONG BWColors[] = {0, 0xFFFFFF};
418
419 BWPalette = EngCreatePalette(PAL_INDEXED, sizeof(BWColors) / sizeof(ULONG),
420 BWColors, 0, 0, 0);
421
422 DestPalette = ppdev->DevInfo.hpalDefault;
423 pgp->XlateObject = IntEngCreateXlate(0, PAL_INDEXED,
424 DestPalette, BWPalette);
425 EngDeletePalette(BWPalette);
426 }
427 else
428 {
429 pgp->XlateObject = pxlo;
430 }
431
432 /* Create surface for saving the pixels under the cursor. */
433 switch (pso->iBitmapFormat)
434 {
435 case BMF_1BPP:
436 lDelta = pgp->Size.cx >> 3;
437 break;
438 case BMF_4BPP:
439 lDelta = pgp->Size.cx >> 1;
440 break;
441 case BMF_8BPP:
442 lDelta = pgp->Size.cx;
443 break;
444 case BMF_16BPP:
445 lDelta = pgp->Size.cx << 1;
446 break;
447 case BMF_24BPP:
448 lDelta = pgp->Size.cx * 3;
449 break;
450 case BMF_32BPP:
451 lDelta = pgp->Size.cx << 2;
452 break;
453 default:
454 lDelta = 0;
455 break;
456 }
457
458 hbmp = EngCreateBitmap(pgp->Size,
459 lDelta,
460 pso->iBitmapFormat,
461 BMF_TOPDOWN | BMF_NOZEROINIT,
462 NULL);
463
464 pgp->psurfSave = SURFACE_ShareLockSurface(hbmp);
465
466 if (x != -1)
467 {
468 IntShowMousePointer(ppdev, pso);
469
470 if (prcl != NULL)
471 {
472 prcl->left = x - pgp->HotSpot.x;
473 prcl->top = y - pgp->HotSpot.x;
474 prcl->right = prcl->left + pgp->Size.cx;
475 prcl->bottom = prcl->top + pgp->Size.cy;
476 }
477 } else if (prcl != NULL)
478 prcl->left = prcl->top = prcl->right = prcl->bottom = -1;
479
480 return SPS_ACCEPT_NOEXCLUDE;
481 }
482
483 /*
484 * @implemented
485 */
486
487 VOID APIENTRY
488 EngMovePointer(
489 IN SURFOBJ *pso,
490 IN LONG x,
491 IN LONG y,
492 IN RECTL *prcl)
493 {
494 PDEVOBJ *ppdev;
495 GDIPOINTER *pgp;
496
497 ASSERT(pso);
498
499 ppdev = GDIDEV(pso);
500 ASSERT(ppdev);
501
502 pgp = &ppdev->Pointer;
503
504 IntHideMousePointer(ppdev, pso);
505
506 ppdev->ptlPointer.x = x;
507 ppdev->ptlPointer.y = y;
508
509 if (x != -1)
510 {
511 IntShowMousePointer(ppdev, pso);
512 if (prcl != NULL)
513 {
514 prcl->left = x - pgp->HotSpot.x;
515 prcl->top = y - pgp->HotSpot.x;
516 prcl->right = prcl->left + pgp->Size.cx;
517 prcl->bottom = prcl->top + pgp->Size.cy;
518 }
519 } else if (prcl != NULL)
520 prcl->left = prcl->top = prcl->right = prcl->bottom = -1;
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 SURFACE *psurf = CONTAINING_RECORD(pso, SURFACE, SurfObj);
531 PPDEVOBJ ppdev = (PPDEVOBJ)pso->hdev;
532
533 SURFACE_LockBitmapBits(psurf);
534 ppdev->pfnMovePointer(pso, x, y, prcl);
535 SURFACE_UnlockBitmapBits(psurf);
536 }
537
538 ULONG APIENTRY
539 IntEngSetPointerShape(
540 IN SURFOBJ *pso,
541 IN SURFOBJ *psoMask,
542 IN SURFOBJ *psoColor,
543 IN XLATEOBJ *pxlo,
544 IN LONG xHot,
545 IN LONG yHot,
546 IN LONG x,
547 IN LONG y,
548 IN RECTL *prcl,
549 IN FLONG fl)
550 {
551 ULONG ulResult = SPS_DECLINE;
552 SURFACE *psurf = CONTAINING_RECORD(pso, SURFACE, SurfObj);
553 PFN_DrvSetPointerShape pfnSetPointerShape;
554 PPDEVOBJ ppdev = GDIDEV(pso);
555
556 pfnSetPointerShape = GDIDEVFUNCS(pso).SetPointerShape;
557
558 SURFACE_LockBitmapBits(psurf);
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 SURFACE_UnlockBitmapBits(psurf);
597
598 return ulResult;
599 }
600
601 /* EOF */