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