3bc769cd3152eee162440f8e560f7f8a62b2baa7
[reactos.git] / reactos / subsys / 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, pgp->Pos.x, pgp->Pos.y, &pgp->Exclude);
130 else
131 EngMovePointer(SurfObj, pgp->Pos.x, pgp->Pos.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 *DestSurface)
142 {
143 GDIPOINTER *pgp;
144 POINTL pt;
145
146 ASSERT(ppdev);
147 ASSERT(DestSurface);
148
149 pgp = &ppdev->Pointer;
150
151 if (!pgp->Enabled)
152 {
153 return;
154 }
155
156
157
158 pgp->Enabled = FALSE;
159
160 pt.x = pgp->Pos.x - pgp->HotSpot.x;
161 pt.y = pgp->Pos.y - pgp->HotSpot.y;
162
163
164 if (pgp->SaveSurface != NULL)
165 {
166 RECTL DestRect;
167 POINTL SrcPoint;
168 SURFOBJ *SaveSurface;
169 SURFOBJ *MaskSurface;
170
171 DestRect.left = max(pt.x, 0);
172 DestRect.top = max(pt.y, 0);
173 DestRect.right = min(
174 pt.x + pgp->Size.cx,
175 DestSurface->sizlBitmap.cx);
176 DestRect.bottom = min(
177 pt.y + pgp->Size.cy,
178 DestSurface->sizlBitmap.cy);
179
180 SrcPoint.x = max(-pt.x, 0);
181 SrcPoint.y = max(-pt.y, 0);
182
183 if((SaveSurface = EngLockSurface(pgp->SaveSurface)))
184 {
185 if((MaskSurface = EngLockSurface(pgp->MaskSurface)))
186 {
187 IntEngBitBltEx(DestSurface, SaveSurface, MaskSurface, NULL, NULL,
188 &DestRect, &SrcPoint, &SrcPoint, NULL, NULL,
189 ROP3_TO_ROP4(SRCCOPY), FALSE);
190 EngUnlockSurface(MaskSurface);
191 }
192 EngUnlockSurface(SaveSurface);
193 }
194 }
195 }
196
197 VOID INTERNAL_CALL
198 IntShowMousePointer(GDIDEVICE *ppdev, SURFOBJ *DestSurface)
199 {
200 GDIPOINTER *pgp;
201 SURFOBJ *SaveSurface;
202 POINTL pt;
203
204 ASSERT(ppdev);
205 ASSERT(DestSurface);
206
207 pgp = &ppdev->Pointer;
208
209 if (pgp->Enabled)
210 {
211 return;
212 }
213
214 if (pgp->ShowPointer == 1)
215 {
216 return ;
217 }
218
219
220 pgp->Enabled = TRUE;
221
222 pt.x = pgp->Pos.x - pgp->HotSpot.x;
223 pt.y = pgp->Pos.y - pgp->HotSpot.y;
224
225 /*
226 * Copy the pixels under the cursor to temporary surface.
227 */
228
229 if (pgp->SaveSurface != NULL &&
230 (SaveSurface = EngLockSurface(pgp->SaveSurface)))
231 {
232 RECTL DestRect;
233 POINTL SrcPoint;
234
235 SrcPoint.x = max(pt.x, 0);
236 SrcPoint.y = max(pt.y, 0);
237
238 DestRect.left = SrcPoint.x - pt.x;
239 DestRect.top = SrcPoint.y - pt.y;
240 DestRect.right = min(
241 pgp->Size.cx,
242 DestSurface->sizlBitmap.cx - pt.x);
243 DestRect.bottom = min(
244 pgp->Size.cy,
245 DestSurface->sizlBitmap.cy - pt.y);
246
247 IntEngBitBltEx(SaveSurface, DestSurface, NULL, NULL, NULL,
248 &DestRect, &SrcPoint, NULL, NULL, NULL,
249 ROP3_TO_ROP4(SRCCOPY), FALSE);
250 EngUnlockSurface(SaveSurface);
251 }
252
253 /*
254 * Blit the cursor on the screen.
255 */
256
257 {
258 RECTL DestRect;
259 POINTL SrcPoint;
260 SURFOBJ *ColorSurf;
261 SURFOBJ *MaskSurf = NULL;
262
263 DestRect.left = max(pt.x, 0);
264 DestRect.top = max(pt.y, 0);
265 DestRect.right = min(
266 pt.x + pgp->Size.cx,
267 DestSurface->sizlBitmap.cx);
268 DestRect.bottom = min(
269 pt.y + pgp->Size.cy,
270 DestSurface->sizlBitmap.cy);
271
272 SrcPoint.x = max(-pt.x, 0);
273 SrcPoint.y = max(-pt.y, 0);
274
275 if (pgp->MaskSurface)
276 MaskSurf = EngLockSurface(pgp->MaskSurface);
277
278 if (MaskSurf != NULL)
279 {
280 if (pgp->ColorSurface != NULL)
281 {
282 if((ColorSurf = EngLockSurface(pgp->ColorSurface)))
283 {
284 IntEngBitBltEx(DestSurface, ColorSurf, MaskSurf, NULL,
285 pgp->XlateObject, &DestRect, &SrcPoint, &SrcPoint,
286 NULL, NULL, R4_MASK, FALSE);
287 EngUnlockSurface(ColorSurf);
288 }
289 }
290 else
291 {
292 IntEngBitBltEx(DestSurface, MaskSurf, NULL, NULL, pgp->XlateObject,
293 &DestRect, &SrcPoint, NULL, NULL, NULL,
294 ROP3_TO_ROP4(SRCAND), FALSE);
295 SrcPoint.y += pgp->Size.cy;
296 IntEngBitBltEx(DestSurface, MaskSurf, NULL, NULL, pgp->XlateObject,
297 &DestRect, &SrcPoint, NULL, NULL, NULL,
298 ROP3_TO_ROP4(SRCINVERT), FALSE);
299 }
300 EngUnlockSurface(MaskSurf);
301 }
302 }
303 }
304
305 /*
306 * @implemented
307 */
308
309 ULONG STDCALL
310 EngSetPointerShape(
311 IN SURFOBJ *pso,
312 IN SURFOBJ *psoMask,
313 IN SURFOBJ *psoColor,
314 IN XLATEOBJ *pxlo,
315 IN LONG xHot,
316 IN LONG yHot,
317 IN LONG x,
318 IN LONG y,
319 IN RECTL *prcl,
320 IN FLONG fl)
321 {
322 GDIDEVICE *ppdev;
323 SURFOBJ *TempSurfObj;
324 GDIPOINTER *pgp;
325
326 ASSERT(pso);
327
328 ppdev = GDIDEV(pso);
329 pgp = &ppdev->Pointer;
330
331 IntHideMousePointer(ppdev, pso);
332
333 if (pgp->ColorSurface != NULL)
334 {
335 /* FIXME: Is this really needed? */
336 if((TempSurfObj = EngLockSurface(pgp->ColorSurface)))
337 {
338 EngFreeMem(TempSurfObj->pvBits);
339 TempSurfObj->pvBits = 0;
340 EngUnlockSurface(TempSurfObj);
341 }
342
343 EngDeleteSurface(pgp->ColorSurface);
344 pgp->MaskSurface = NULL;
345 }
346
347 if (pgp->MaskSurface != NULL)
348 {
349 /* FIXME: Is this really needed? */
350 if((TempSurfObj = EngLockSurface(pgp->MaskSurface)))
351 {
352 EngFreeMem(TempSurfObj->pvBits);
353 TempSurfObj->pvBits = 0;
354 EngUnlockSurface(TempSurfObj);
355 }
356
357 EngDeleteSurface(pgp->MaskSurface);
358 pgp->MaskSurface = NULL;
359 }
360
361 if (pgp->SaveSurface != NULL)
362 {
363 EngDeleteSurface(pgp->SaveSurface);
364 pgp->SaveSurface = NULL;
365 }
366
367 if (pgp->XlateObject != NULL)
368 {
369 EngDeleteXlate(pgp->XlateObject);
370 pgp->XlateObject = NULL;
371 }
372
373 /*
374 * See if we are being asked to hide the pointer.
375 */
376
377 if (psoMask == NULL)
378 {
379 return SPS_ACCEPT_NOEXCLUDE;
380 }
381
382 pgp->HotSpot.x = xHot;
383 pgp->HotSpot.y = yHot;
384
385 /* Actually this should be set by 'the other side', but it would be
386 * done right after this. It helps IntShowMousePointer. */
387 if (x != -1)
388 {
389 pgp->Pos.x = x;
390 pgp->Pos.y = y;
391 }
392
393 pgp->Size.cx = abs(psoMask->lDelta) << 3;
394 pgp->Size.cy = (psoMask->cjBits / abs(psoMask->lDelta)) >> 1;
395
396 if (psoColor != NULL)
397 {
398 PBYTE Bits;
399
400 Bits = EngAllocMem(0, psoColor->cjBits, TAG_MOUSE);
401 if (Bits == NULL)
402 {
403 return SPS_ERROR;
404 }
405
406 memcpy(Bits, psoColor->pvBits, psoColor->cjBits);
407
408 pgp->ColorSurface = (HSURF)EngCreateBitmap(pgp->Size,
409 psoColor->lDelta, psoColor->iBitmapFormat,
410 psoColor->lDelta < 0 ? 0 : BMF_TOPDOWN, Bits);
411 }
412 else
413 {
414 pgp->ColorSurface = NULL;
415 }
416
417 {
418 SIZEL Size;
419 PBYTE Bits;
420
421 Size.cx = pgp->Size.cx;
422 Size.cy = pgp->Size.cy << 1;
423 Bits = EngAllocMem(0, psoMask->cjBits, TAG_MOUSE);
424 if (Bits == NULL)
425 {
426 return SPS_ERROR;
427 }
428
429 memcpy(Bits, psoMask->pvBits, psoMask->cjBits);
430
431 pgp->MaskSurface = (HSURF)EngCreateBitmap(Size,
432 psoMask->lDelta, psoMask->iBitmapFormat,
433 psoMask->lDelta < 0 ? 0 : BMF_TOPDOWN, Bits);
434 }
435
436 /*
437 * Create an XLATEOBJ that will be used for drawing masks.
438 * FIXME: We should get this in pxlo parameter!
439 */
440
441 if (pxlo == NULL)
442 {
443 HPALETTE BWPalette, DestPalette;
444 ULONG BWColors[] = {0, 0xFFFFFF};
445
446 BWPalette = EngCreatePalette(PAL_INDEXED, sizeof(BWColors) / sizeof(ULONG),
447 BWColors, 0, 0, 0);
448
449 DestPalette = ppdev->DevInfo.hpalDefault;
450 pgp->XlateObject = IntEngCreateXlate(0, PAL_INDEXED,
451 DestPalette, BWPalette);
452 EngDeletePalette(BWPalette);
453 }
454 else
455 {
456 pgp->XlateObject = pxlo;
457 }
458
459 /*
460 * Create surface for saving the pixels under the cursor.
461 */
462
463 {
464 LONG lDelta;
465
466 switch (pso->iBitmapFormat)
467 {
468 case BMF_1BPP:
469 lDelta = pgp->Size.cx >> 3;
470 break;
471 case BMF_4BPP:
472 lDelta = pgp->Size.cx >> 1;
473 break;
474 case BMF_8BPP:
475 lDelta = pgp->Size.cx;
476 break;
477 case BMF_16BPP:
478 lDelta = pgp->Size.cx << 1;
479 break;
480 case BMF_24BPP:
481 lDelta = pgp->Size.cx * 3;
482 break;
483 case BMF_32BPP:
484 lDelta = pgp->Size.cx << 2;
485 break;
486 default:
487 lDelta = 0;
488 break;
489 }
490
491 pgp->SaveSurface = (HSURF)EngCreateBitmap(
492 pgp->Size, lDelta, pso->iBitmapFormat, BMF_TOPDOWN | BMF_NOZEROINIT, NULL);
493 }
494
495 if(x != -1)
496 {
497 IntShowMousePointer(ppdev, pso);
498
499 if (prcl != NULL)
500 {
501 prcl->left = x - pgp->HotSpot.x;
502 prcl->top = y - pgp->HotSpot.x;
503 prcl->right = prcl->left + pgp->Size.cx;
504 prcl->bottom = prcl->top + pgp->Size.cy;
505 }
506 } else if (prcl != NULL)
507 prcl->left = prcl->top = prcl->right = prcl->bottom = -1;
508
509 return SPS_ACCEPT_EXCLUDE;
510 }
511
512 /*
513 * @implemented
514 */
515
516 VOID STDCALL
517 EngMovePointer(
518 IN SURFOBJ *pso,
519 IN LONG x,
520 IN LONG y,
521 IN RECTL *prcl)
522 {
523 GDIDEVICE *ppdev;
524 GDIPOINTER *pgp;
525
526 ASSERT(pso);
527
528 ppdev = GDIDEV(pso);
529
530 ASSERT(ppdev);
531
532 pgp = &ppdev->Pointer;
533
534 IntHideMousePointer(ppdev, pso);
535 if (x != -1)
536 {
537 /* Actually this should be set by 'the other side', but it would be
538 * done right after this. It helps IntShowMousePointer. */
539 pgp->Pos.x = x;
540 pgp->Pos.y = y;
541 IntShowMousePointer(ppdev, pso);
542 if (prcl != NULL)
543 {
544 prcl->left = x - pgp->HotSpot.x;
545 prcl->top = y - pgp->HotSpot.x;
546 prcl->right = prcl->left + pgp->Size.cx;
547 prcl->bottom = prcl->top + pgp->Size.cy;
548 }
549 } else if (prcl != NULL)
550 prcl->left = prcl->top = prcl->right = prcl->bottom = -1;
551
552 }
553
554 VOID STDCALL
555 IntEngMovePointer(
556 IN SURFOBJ *SurfObj,
557 IN LONG x,
558 IN LONG y,
559 IN RECTL *prcl)
560 {
561 BITMAPOBJ *BitmapObj = CONTAINING_RECORD(SurfObj, BITMAPOBJ, SurfObj);
562
563 BITMAPOBJ_LockBitmapBits(BitmapObj);
564 if (GDIDEV(SurfObj)->Pointer.MovePointer)
565 {
566 GDIDEV(SurfObj)->Pointer.MovePointer(SurfObj, x, y, prcl);
567 }
568 else
569 {
570 EngMovePointer(SurfObj, x, y, prcl);
571 }
572 BITMAPOBJ_UnlockBitmapBits(BitmapObj);
573 }
574
575 /* EOF */