Merge freeldr from amd64 branch:
[reactos.git] / reactos / subsystems / win32 / win32k / eng / mouse.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * PROJECT: ReactOS kernel
22 * PURPOSE: Mouse
23 * FILE: subsys/win32k/eng/mouse.c
24 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 * REVISION HISTORY:
26 * 06-06-2001 CSH Created
27 */
28 /* INCLUDES ******************************************************************/
29
30 #include <w32k.h>
31
32 #define NDEBUG
33 #include <debug.h>
34
35 /* FUNCTIONS *****************************************************************/
36
37 INT INTERNAL_CALL
38 MouseSafetyOnDrawStart(SURFOBJ *SurfObj, LONG HazardX1,
39 LONG HazardY1, LONG HazardX2, LONG HazardY2)
40 /*
41 * FUNCTION: Notify the mouse driver that drawing is about to begin in
42 * a rectangle on a particular surface.
43 */
44 {
45 LONG tmp;
46 GDIDEVICE *ppdev;
47 GDIPOINTER *pgp;
48
49 ASSERT(SurfObj != NULL);
50
51 ppdev = GDIDEV(SurfObj);
52
53 if(ppdev == NULL)
54 {
55 return(FALSE);
56 }
57
58 pgp = &ppdev->Pointer;
59
60 if (SPS_ACCEPT_NOEXCLUDE == pgp->Status ||
61 pgp->Exclude.right == -1)
62 {
63 return(FALSE);
64 }
65
66 if (HazardX1 > HazardX2)
67 {
68 tmp = HazardX2; HazardX2 = HazardX1; HazardX1 = tmp;
69 }
70 if (HazardY1 > HazardY2)
71 {
72 tmp = HazardY2; HazardY2 = HazardY1; HazardY1 = tmp;
73 }
74
75 if (ppdev->SafetyRemoveLevel != 0)
76 {
77 ppdev->SafetyRemoveCount++;
78 return FALSE;
79 }
80
81 ppdev->SafetyRemoveCount++;
82
83 if (pgp->Exclude.right >= HazardX1
84 && pgp->Exclude.left <= HazardX2
85 && pgp->Exclude.bottom >= HazardY1
86 && pgp->Exclude.top <= HazardY2)
87 {
88 ppdev->SafetyRemoveLevel = ppdev->SafetyRemoveCount;
89 if (pgp->MovePointer)
90 pgp->MovePointer(SurfObj, -1, -1, NULL);
91 else
92 EngMovePointer(SurfObj, -1, -1, NULL);
93 }
94
95 return(TRUE);
96 }
97
98 INT INTERNAL_CALL
99 MouseSafetyOnDrawEnd(SURFOBJ *SurfObj)
100 /*
101 * FUNCTION: Notify the mouse driver that drawing has finished on a surface.
102 */
103 {
104 GDIDEVICE *ppdev;
105 GDIPOINTER *pgp;
106
107 ASSERT(SurfObj != NULL);
108
109 ppdev = GDIDEV(SurfObj);
110
111 if(ppdev == NULL)
112 {
113 return(FALSE);
114 }
115
116 pgp = &ppdev->Pointer;
117
118 if(SPS_ACCEPT_NOEXCLUDE == pgp->Status ||
119 pgp->Exclude.right == -1)
120 {
121 return FALSE;
122 }
123
124 if (--ppdev->SafetyRemoveCount >= ppdev->SafetyRemoveLevel)
125 {
126 return FALSE;
127 }
128 if (pgp->MovePointer)
129 pgp->MovePointer(SurfObj, gpsi->ptCursor.x, gpsi->ptCursor.y, &pgp->Exclude);
130 else
131 EngMovePointer(SurfObj, gpsi->ptCursor.x, gpsi->ptCursor.y, &pgp->Exclude);
132
133 ppdev->SafetyRemoveLevel = 0;
134
135 return(TRUE);
136 }
137
138 /* SOFTWARE MOUSE POINTER IMPLEMENTATION **************************************/
139
140 VOID INTERNAL_CALL
141 IntHideMousePointer(GDIDEVICE *ppdev, SURFOBJ *psoDest)
142 {
143 GDIPOINTER *pgp;
144 POINTL pt;
145
146 ASSERT(ppdev);
147 ASSERT(psoDest);
148
149 pgp = &ppdev->Pointer;
150
151 if (!pgp->Enabled)
152 {
153 return;
154 }
155
156
157
158 pgp->Enabled = FALSE;
159
160 /*
161 * The mouse is hide from ShowCours and it is frist ??
162 */
163 if (pgp->ShowPointer < 0)
164 {
165 return ;
166 }
167
168
169 /*
170 * Hide the cours
171 */
172 pt.x = gpsi->ptCursor.x - pgp->HotSpot.x;
173 pt.y = gpsi->ptCursor.y - pgp->HotSpot.y;
174
175
176 if (pgp->SaveSurface != NULL)
177 {
178 RECTL DestRect;
179 POINTL SrcPoint;
180 SURFOBJ *SaveSurface;
181 SURFOBJ *MaskSurface;
182
183 DestRect.left = max(pt.x, 0);
184 DestRect.top = max(pt.y, 0);
185 DestRect.right = min(
186 pt.x + pgp->Size.cx,
187 psoDest->sizlBitmap.cx);
188 DestRect.bottom = min(
189 pt.y + pgp->Size.cy,
190 psoDest->sizlBitmap.cy);
191
192 SrcPoint.x = max(-pt.x, 0);
193 SrcPoint.y = max(-pt.y, 0);
194
195 if((SaveSurface = EngLockSurface(pgp->SaveSurface)))
196 {
197 if((MaskSurface = EngLockSurface(pgp->MaskSurface)))
198 {
199 IntEngBitBltEx(psoDest, SaveSurface, MaskSurface, NULL, NULL,
200 &DestRect, &SrcPoint, &SrcPoint, NULL, NULL,
201 ROP3_TO_ROP4(SRCCOPY), FALSE);
202 EngUnlockSurface(MaskSurface);
203 }
204 EngUnlockSurface(SaveSurface);
205 }
206 }
207 }
208
209 VOID INTERNAL_CALL
210 IntShowMousePointer(GDIDEVICE *ppdev, SURFOBJ *psoDest)
211 {
212 GDIPOINTER *pgp;
213 SURFOBJ *SaveSurface;
214 POINTL pt;
215
216 ASSERT(ppdev);
217 ASSERT(psoDest);
218
219 pgp = &ppdev->Pointer;
220
221 if (pgp->Enabled)
222 {
223 return;
224 }
225
226 pgp->Enabled = TRUE;
227
228 /*
229 * Do not blt the mouse if it in hide
230 */
231 if (pgp->ShowPointer < 0)
232 {
233 return ;
234 }
235
236 pt.x = gpsi->ptCursor.x - pgp->HotSpot.x;
237 pt.y = gpsi->ptCursor.y - pgp->HotSpot.y;
238
239 /*
240 * Copy the pixels under the cursor to temporary surface.
241 */
242
243 if (pgp->SaveSurface != NULL &&
244 (SaveSurface = EngLockSurface(pgp->SaveSurface)))
245 {
246 RECTL DestRect;
247 POINTL SrcPoint;
248
249 SrcPoint.x = max(pt.x, 0);
250 SrcPoint.y = max(pt.y, 0);
251
252 DestRect.left = SrcPoint.x - pt.x;
253 DestRect.top = SrcPoint.y - pt.y;
254 DestRect.right = min(
255 pgp->Size.cx,
256 psoDest->sizlBitmap.cx - pt.x);
257 DestRect.bottom = min(
258 pgp->Size.cy,
259 psoDest->sizlBitmap.cy - pt.y);
260
261 IntEngBitBltEx(SaveSurface, psoDest, NULL, NULL, NULL,
262 &DestRect, &SrcPoint, NULL, NULL, NULL,
263 ROP3_TO_ROP4(SRCCOPY), FALSE);
264 EngUnlockSurface(SaveSurface);
265 }
266
267
268 /*
269 * Blit the cursor on the screen.
270 */
271
272 {
273 RECTL DestRect;
274 POINTL SrcPoint;
275 SURFOBJ *psoColor;
276 SURFOBJ *psoMask = NULL;
277
278 DestRect.left = max(pt.x, 0);
279 DestRect.top = max(pt.y, 0);
280 DestRect.right = min(
281 pt.x + pgp->Size.cx,
282 psoDest->sizlBitmap.cx);
283 DestRect.bottom = min(
284 pt.y + pgp->Size.cy,
285 psoDest->sizlBitmap.cy);
286
287 SrcPoint.x = max(-pt.x, 0);
288 SrcPoint.y = max(-pt.y, 0);
289
290
291 if (pgp->MaskSurface)
292 psoMask = EngLockSurface(pgp->MaskSurface);
293
294 if (psoMask != NULL)
295 {
296 if (pgp->ColorSurface != NULL)
297 {
298 if((psoColor = EngLockSurface(pgp->ColorSurface)))
299 {
300 IntEngBitBltEx(psoDest, psoColor, psoMask, NULL,
301 pgp->XlateObject, &DestRect, &SrcPoint, &SrcPoint,
302 NULL, NULL, R4_MASK, FALSE);
303 EngUnlockSurface(psoColor);
304 }
305 }
306 else
307 {
308 IntEngBitBltEx(psoDest, psoMask, NULL, NULL, pgp->XlateObject,
309 &DestRect, &SrcPoint, NULL, NULL, NULL,
310 ROP3_TO_ROP4(SRCAND), FALSE);
311 SrcPoint.y += pgp->Size.cy;
312 IntEngBitBltEx(psoDest, psoMask, NULL, NULL, pgp->XlateObject,
313 &DestRect, &SrcPoint, NULL, NULL, NULL,
314 ROP3_TO_ROP4(SRCINVERT), FALSE);
315 }
316 EngUnlockSurface(psoMask);
317 }
318 }
319 }
320
321 /*
322 * @implemented
323 */
324
325 ULONG APIENTRY
326 EngSetPointerShape(
327 IN SURFOBJ *pso,
328 IN SURFOBJ *psoMask,
329 IN SURFOBJ *psoColor,
330 IN XLATEOBJ *pxlo,
331 IN LONG xHot,
332 IN LONG yHot,
333 IN LONG x,
334 IN LONG y,
335 IN RECTL *prcl,
336 IN FLONG fl)
337 {
338 GDIDEVICE *ppdev;
339 SURFOBJ *psoTemp;
340 GDIPOINTER *pgp;
341
342 ASSERT(pso);
343
344 ppdev = GDIDEV(pso);
345 pgp = &ppdev->Pointer;
346
347 IntHideMousePointer(ppdev, pso);
348
349 if (pgp->ColorSurface != NULL)
350 {
351 /* FIXME: Is this really needed? */
352 if((psoTemp = EngLockSurface(pgp->ColorSurface)))
353 {
354 EngFreeMem(psoTemp->pvBits);
355 psoTemp->pvBits = 0;
356 EngUnlockSurface(psoTemp);
357 }
358
359 EngDeleteSurface(pgp->ColorSurface);
360 pgp->MaskSurface = NULL;
361 }
362
363 if (pgp->MaskSurface != NULL)
364 {
365 /* FIXME: Is this really needed? */
366 if((psoTemp = EngLockSurface(pgp->MaskSurface)))
367 {
368 EngFreeMem(psoTemp->pvBits);
369 psoTemp->pvBits = 0;
370 EngUnlockSurface(psoTemp);
371 }
372
373 EngDeleteSurface(pgp->MaskSurface);
374 pgp->MaskSurface = NULL;
375 }
376
377 if (pgp->SaveSurface != NULL)
378 {
379 EngDeleteSurface(pgp->SaveSurface);
380 pgp->SaveSurface = NULL;
381 }
382
383 if (pgp->XlateObject != NULL)
384 {
385 EngDeleteXlate(pgp->XlateObject);
386 pgp->XlateObject = NULL;
387 }
388
389 /*
390 * See if we are being asked to hide the pointer.
391 */
392
393 if (psoMask == NULL)
394 {
395 return SPS_ACCEPT_NOEXCLUDE;
396 }
397
398 pgp->HotSpot.x = xHot;
399 pgp->HotSpot.y = yHot;
400
401 /* Actually this should be set by 'the other side', but it would be
402 * done right after this. It helps IntShowMousePointer. */
403 if (x != -1)
404 {
405 gpsi->ptCursor.x = x;
406 gpsi->ptCursor.y = y;
407 }
408
409 pgp->Size.cx = abs(psoMask->lDelta) << 3;
410 pgp->Size.cy = (psoMask->cjBits / abs(psoMask->lDelta)) >> 1;
411
412 if (psoColor != NULL)
413 {
414 PBYTE Bits;
415
416 Bits = EngAllocMem(0, psoColor->cjBits, TAG_MOUSE);
417 if (Bits == NULL)
418 {
419 return SPS_ERROR;
420 }
421
422 memcpy(Bits, psoColor->pvBits, psoColor->cjBits);
423
424 pgp->ColorSurface = (HSURF)EngCreateBitmap(pgp->Size,
425 psoColor->lDelta, psoColor->iBitmapFormat,
426 psoColor->lDelta < 0 ? 0 : BMF_TOPDOWN, Bits);
427 }
428 else
429 {
430 pgp->ColorSurface = NULL;
431 }
432
433 {
434 SIZEL Size;
435 PBYTE Bits;
436
437 Size.cx = pgp->Size.cx;
438 Size.cy = pgp->Size.cy << 1;
439 Bits = EngAllocMem(0, psoMask->cjBits, TAG_MOUSE);
440 if (Bits == NULL)
441 {
442 return SPS_ERROR;
443 }
444
445 memcpy(Bits, psoMask->pvBits, psoMask->cjBits);
446
447 pgp->MaskSurface = (HSURF)EngCreateBitmap(Size,
448 psoMask->lDelta, psoMask->iBitmapFormat,
449 psoMask->lDelta < 0 ? 0 : BMF_TOPDOWN, Bits);
450 }
451
452 /*
453 * Create an XLATEOBJ that will be used for drawing masks.
454 * FIXME: We should get this in pxlo parameter!
455 */
456
457 if (pxlo == NULL)
458 {
459 HPALETTE BWPalette, DestPalette;
460 ULONG BWColors[] = {0, 0xFFFFFF};
461
462 BWPalette = EngCreatePalette(PAL_INDEXED, sizeof(BWColors) / sizeof(ULONG),
463 BWColors, 0, 0, 0);
464
465 DestPalette = ppdev->DevInfo.hpalDefault;
466 pgp->XlateObject = IntEngCreateXlate(0, PAL_INDEXED,
467 DestPalette, BWPalette);
468 EngDeletePalette(BWPalette);
469 }
470 else
471 {
472 pgp->XlateObject = pxlo;
473 }
474
475 /*
476 * Create surface for saving the pixels under the cursor.
477 */
478
479 {
480 LONG lDelta;
481
482 switch (pso->iBitmapFormat)
483 {
484 case BMF_1BPP:
485 lDelta = pgp->Size.cx >> 3;
486 break;
487 case BMF_4BPP:
488 lDelta = pgp->Size.cx >> 1;
489 break;
490 case BMF_8BPP:
491 lDelta = pgp->Size.cx;
492 break;
493 case BMF_16BPP:
494 lDelta = pgp->Size.cx << 1;
495 break;
496 case BMF_24BPP:
497 lDelta = pgp->Size.cx * 3;
498 break;
499 case BMF_32BPP:
500 lDelta = pgp->Size.cx << 2;
501 break;
502 default:
503 lDelta = 0;
504 break;
505 }
506
507 pgp->SaveSurface = (HSURF)EngCreateBitmap(
508 pgp->Size, lDelta, pso->iBitmapFormat, BMF_TOPDOWN | BMF_NOZEROINIT, NULL);
509 }
510
511 if(x != -1)
512 {
513 IntShowMousePointer(ppdev, pso);
514
515 if (prcl != NULL)
516 {
517 prcl->left = x - pgp->HotSpot.x;
518 prcl->top = y - pgp->HotSpot.x;
519 prcl->right = prcl->left + pgp->Size.cx;
520 prcl->bottom = prcl->top + pgp->Size.cy;
521 }
522 } else if (prcl != NULL)
523 prcl->left = prcl->top = prcl->right = prcl->bottom = -1;
524
525 return SPS_ACCEPT_EXCLUDE;
526 }
527
528 /*
529 * @implemented
530 */
531
532 VOID APIENTRY
533 EngMovePointer(
534 IN SURFOBJ *pso,
535 IN LONG x,
536 IN LONG y,
537 IN RECTL *prcl)
538 {
539 GDIDEVICE *ppdev;
540 GDIPOINTER *pgp;
541
542 ASSERT(pso);
543
544 ppdev = GDIDEV(pso);
545
546 ASSERT(ppdev);
547
548 pgp = &ppdev->Pointer;
549
550 IntHideMousePointer(ppdev, pso);
551 if (x != -1)
552 {
553 /* Actually this should be set by 'the other side', but it would be
554 * done right after this. It helps IntShowMousePointer. */
555 gpsi->ptCursor.x = x;
556 gpsi->ptCursor.y = y;
557 IntShowMousePointer(ppdev, pso);
558 if (prcl != NULL)
559 {
560 prcl->left = x - pgp->HotSpot.x;
561 prcl->top = y - pgp->HotSpot.x;
562 prcl->right = prcl->left + pgp->Size.cx;
563 prcl->bottom = prcl->top + pgp->Size.cy;
564 }
565 } else if (prcl != NULL)
566 prcl->left = prcl->top = prcl->right = prcl->bottom = -1;
567
568 }
569
570 VOID APIENTRY
571 IntEngMovePointer(
572 IN SURFOBJ *pso,
573 IN LONG x,
574 IN LONG y,
575 IN RECTL *prcl)
576 {
577 SURFACE *psurf = CONTAINING_RECORD(pso, SURFACE, SurfObj);
578
579 SURFACE_LockBitmapBits(psurf);
580 if (GDIDEV(pso)->Pointer.MovePointer)
581 {
582 GDIDEV(pso)->Pointer.MovePointer(pso, x, y, prcl);
583 }
584 else
585 {
586 EngMovePointer(pso, x, y, prcl);
587 }
588 SURFACE_UnlockBitmapBits(psurf);
589 }
590
591 /* EOF */