2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
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.
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.
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.
19 /* $Id: mouse.c,v 1.75 2004/07/03 17:40:25 navaraf Exp $
21 * PROJECT: ReactOS kernel
23 * FILE: subsys/win32k/eng/mouse.c
24 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * 06-06-2001 CSH Created
28 /* INCLUDES ******************************************************************/
31 /* FUNCTIONS *****************************************************************/
34 IntIsPrimarySurface(SURFOBJ
*SurfObj
);
37 EnableMouse(HDC hDisplayDC
)
42 PSYSTEM_CURSORINFO CurInfo
= IntGetSysCursorInfo(InputWindowStation
);
44 if( hDisplayDC
&& InputWindowStation
)
46 if(!IntGetWindowStationObject(InputWindowStation
))
48 CurInfo
->Enabled
= FALSE
;
52 dc
= DC_LockDc(hDisplayDC
);
54 BitmapObj
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
57 /* Move the cursor to the screen center */
58 DPRINT("Setting Cursor up at 0x%x, 0x%x\n", SurfObj
->sizlBitmap
.cx
/ 2, SurfObj
->sizlBitmap
.cy
/ 2);
59 ExAcquireFastMutex(&CurInfo
->CursorMutex
);
60 CurInfo
->x
= BitmapObj
->SurfObj
.sizlBitmap
.cx
/ 2;
61 CurInfo
->y
= BitmapObj
->SurfObj
.sizlBitmap
.cy
/ 2;
62 ExReleaseFastMutex(&CurInfo
->CursorMutex
);
64 GdiDev
= GDIDEV(&BitmapObj
->SurfObj
);
65 BITMAPOBJ_UnlockBitmap(dc
->w
.hBitmap
);
66 DC_UnlockDc( hDisplayDC
);
68 IntSetCursor(InputWindowStation
, NULL
, TRUE
);
70 CurInfo
->Enabled
= (SPS_ACCEPT_EXCLUDE
== GdiDev
->PointerStatus
||
71 SPS_ACCEPT_NOEXCLUDE
== GdiDev
->PointerStatus
);
73 IntLoadDefaultCursors();
75 ObDereferenceObject(InputWindowStation
);
79 if(IntGetWindowStationObject(InputWindowStation
))
81 IntSetCursor(InputWindowStation
, NULL
, TRUE
);
82 CurInfo
->Enabled
= FALSE
;
83 CurInfo
->CursorClipInfo
.IsClipped
= FALSE
;
84 ObDereferenceObject(InputWindowStation
);
91 MouseSafetyOnDrawStart(SURFOBJ
*SurfObj
, LONG HazardX1
,
92 LONG HazardY1
, LONG HazardX2
, LONG HazardY2
)
94 * FUNCTION: Notify the mouse driver that drawing is about to begin in
95 * a rectangle on a particular surface.
99 PSYSTEM_CURSORINFO CurInfo
;
100 BOOL MouseEnabled
= FALSE
;
101 PCURICON_OBJECT Cursor
;
104 /* Mouse is not allowed to move if GDI is busy drawing */
106 if(IntGetWindowStationObject(InputWindowStation
))
108 CurInfo
= IntGetSysCursorInfo(InputWindowStation
);
110 MouseEnabled
= CurInfo
->Enabled
&& CurInfo
->ShowingCursor
;
117 ObDereferenceObject(InputWindowStation
);
120 if (!IntIsPrimarySurface(SurfObj
) || MouseEnabled
== FALSE
)
122 ObDereferenceObject(InputWindowStation
);
126 if (SPS_ACCEPT_NOEXCLUDE
== GDIDEV(SurfObj
)->PointerStatus
)
128 /* Hardware cursor, no need to remove it */
129 ObDereferenceObject(InputWindowStation
);
133 if(!(Cursor
= CurInfo
->CurrentCursorObject
))
135 ObDereferenceObject(InputWindowStation
);
139 if (HazardX1
> HazardX2
)
141 tmp
= HazardX2
; HazardX2
= HazardX1
; HazardX1
= tmp
;
143 if (HazardY1
> HazardY2
)
145 tmp
= HazardY2
; HazardY2
= HazardY1
; HazardY1
= tmp
;
148 if (CurInfo
->PointerRectRight
>= HazardX1
149 && CurInfo
->PointerRectLeft
<= HazardX2
150 && CurInfo
->PointerRectBottom
>= HazardY1
151 && CurInfo
->PointerRectTop
<= HazardY2
)
153 /* Mouse is not allowed to move if GDI is busy drawing */
154 ExAcquireFastMutex(&CurInfo
->CursorMutex
);
155 if (0 != CurInfo
->SafetyRemoveCount
++)
157 /* Was already removed */
158 ExReleaseFastMutex(&CurInfo
->CursorMutex
);
159 ObDereferenceObject(InputWindowStation
);
162 CurInfo
->SafetySwitch
= TRUE
;
163 if (GDIDEVFUNCS(SurfObj
).MovePointer
)
164 GDIDEVFUNCS(SurfObj
).MovePointer(SurfObj
, -1, -1, NULL
);
166 EngMovePointer(SurfObj
, -1, -1, NULL
);
167 ExReleaseFastMutex(&CurInfo
->CursorMutex
);
170 ObDereferenceObject(InputWindowStation
);
175 SetPointerRect(PSYSTEM_CURSORINFO CurInfo
, PRECTL PointerRect
)
177 CurInfo
->PointerRectLeft
= PointerRect
->left
;
178 CurInfo
->PointerRectRight
= PointerRect
->right
;
179 CurInfo
->PointerRectTop
= PointerRect
->top
;
180 CurInfo
->PointerRectBottom
= PointerRect
->bottom
;
184 MouseSafetyOnDrawEnd(SURFOBJ
*SurfObj
)
186 * FUNCTION: Notify the mouse driver that drawing has finished on a surface.
189 PSYSTEM_CURSORINFO CurInfo
;
190 BOOL MouseEnabled
= FALSE
;
193 if(IntGetWindowStationObject(InputWindowStation
))
195 CurInfo
= IntGetSysCursorInfo(InputWindowStation
);
200 ExAcquireFastMutex(&CurInfo
->CursorMutex
);
203 ExReleaseFastMutex(&CurInfo
->CursorMutex
);
204 ObDereferenceObject(InputWindowStation
);
208 MouseEnabled
= CurInfo
->Enabled
&& CurInfo
->ShowingCursor
;
209 if (!IntIsPrimarySurface(SurfObj
) || MouseEnabled
== FALSE
)
211 ExReleaseFastMutex(&CurInfo
->CursorMutex
);
212 ObDereferenceObject(InputWindowStation
);
216 if (SPS_ACCEPT_NOEXCLUDE
== GDIDEV(SurfObj
)->PointerStatus
)
218 /* Hardware cursor, it wasn't removed so need to restore it */
219 ExReleaseFastMutex(&CurInfo
->CursorMutex
);
220 ObDereferenceObject(InputWindowStation
);
224 if (CurInfo
->SafetySwitch
)
226 if (1 < CurInfo
->SafetyRemoveCount
--)
228 /* Someone else removed it too, let them restore it */
229 ExReleaseFastMutex(&CurInfo
->CursorMutex
);
230 ObDereferenceObject(InputWindowStation
);
233 if (GDIDEVFUNCS(SurfObj
).MovePointer
)
234 GDIDEVFUNCS(SurfObj
).MovePointer(SurfObj
, CurInfo
->x
, CurInfo
->y
, &PointerRect
);
236 EngMovePointer(SurfObj
, CurInfo
->x
, CurInfo
->y
, &PointerRect
);
237 SetPointerRect(CurInfo
, &PointerRect
);
238 CurInfo
->SafetySwitch
= FALSE
;
241 ExReleaseFastMutex(&CurInfo
->CursorMutex
);
242 ObDereferenceObject(InputWindowStation
);
246 #define ClearMouseInput(mi) \
252 #define SendMouseEvent(mi) \
253 if(mi.dx != 0 || mi.dy != 0) \
254 mi.dwFlags |= MOUSEEVENTF_MOVE; \
256 IntMouseInput(&mi); \
260 MouseGDICallBack(PMOUSE_INPUT_DATA Data
, ULONG InputCount
)
262 PMOUSE_INPUT_DATA mid
;
269 for(i
= 0; i
< InputCount
; i
++)
277 if(mid
->ButtonFlags
& MOUSE_LEFT_BUTTON_DOWN
)
279 mi
.dwFlags
|= MOUSEEVENTF_LEFTDOWN
;
282 if(mid
->ButtonFlags
& MOUSE_LEFT_BUTTON_UP
)
284 mi
.dwFlags
|= MOUSEEVENTF_LEFTUP
;
287 if(mid
->ButtonFlags
& MOUSE_MIDDLE_BUTTON_DOWN
)
289 mi
.dwFlags
|= MOUSEEVENTF_MIDDLEDOWN
;
292 if(mid
->ButtonFlags
& MOUSE_MIDDLE_BUTTON_UP
)
294 mi
.dwFlags
|= MOUSEEVENTF_MIDDLEUP
;
297 if(mid
->ButtonFlags
& MOUSE_RIGHT_BUTTON_DOWN
)
299 mi
.dwFlags
|= MOUSEEVENTF_RIGHTDOWN
;
302 if(mid
->ButtonFlags
& MOUSE_RIGHT_BUTTON_UP
)
304 mi
.dwFlags
|= MOUSEEVENTF_RIGHTUP
;
307 if(mid
->ButtonFlags
& MOUSE_BUTTON_4_DOWN
)
309 mi
.mouseData
|= XBUTTON1
;
310 mi
.dwFlags
|= MOUSEEVENTF_XDOWN
;
313 if(mid
->ButtonFlags
& MOUSE_BUTTON_4_UP
)
315 mi
.mouseData
|= XBUTTON1
;
316 mi
.dwFlags
|= MOUSEEVENTF_XUP
;
319 if(mid
->ButtonFlags
& MOUSE_BUTTON_5_DOWN
)
321 mi
.mouseData
|= XBUTTON2
;
322 mi
.dwFlags
|= MOUSEEVENTF_XDOWN
;
325 if(mid
->ButtonFlags
& MOUSE_BUTTON_5_UP
)
327 mi
.mouseData
|= XBUTTON2
;
328 mi
.dwFlags
|= MOUSEEVENTF_XUP
;
331 if(mid
->ButtonFlags
& MOUSE_WHEEL
)
333 mi
.mouseData
= mid
->ButtonData
;
334 mi
.dwFlags
|= MOUSEEVENTF_WHEEL
;
343 /* SOFTWARE MOUSE POINTER IMPLEMENTATION **************************************/
346 IntHideMousePointer(GDIDEVICE
*ppdev
, SURFOBJ
*DestSurface
)
348 if (ppdev
->PointerAttributes
.Enable
== FALSE
)
353 ppdev
->PointerAttributes
.Enable
= FALSE
;
355 if (ppdev
->PointerAttributes
.Column
+ ppdev
->PointerHotSpot
.x
== -1)
360 if (ppdev
->PointerSaveSurface
!= NULL
)
364 SURFOBJ
*SaveSurface
;
365 SURFOBJ
*MaskSurface
;
367 DestRect
.left
= max(ppdev
->PointerAttributes
.Column
, 0);
368 DestRect
.top
= max(ppdev
->PointerAttributes
.Row
, 0);
369 DestRect
.right
= min(
370 ppdev
->PointerAttributes
.Column
+ ppdev
->PointerAttributes
.Width
,
371 DestSurface
->sizlBitmap
.cx
);
372 DestRect
.bottom
= min(
373 ppdev
->PointerAttributes
.Row
+ ppdev
->PointerAttributes
.Height
,
374 DestSurface
->sizlBitmap
.cy
);
376 SrcPoint
.x
= max(-ppdev
->PointerAttributes
.Column
, 0);
377 SrcPoint
.y
= max(-ppdev
->PointerAttributes
.Row
, 0);
379 SaveSurface
= EngLockSurface(ppdev
->PointerSaveSurface
);
380 MaskSurface
= EngLockSurface(ppdev
->PointerMaskSurface
);
381 EngBitBlt(DestSurface
, SaveSurface
, MaskSurface
, NULL
, NULL
,
382 &DestRect
, &SrcPoint
, &SrcPoint
, NULL
, NULL
, SRCCOPY
);
383 EngUnlockSurface(MaskSurface
);
384 EngUnlockSurface(SaveSurface
);
389 IntShowMousePointer(GDIDEVICE
*ppdev
, SURFOBJ
*DestSurface
)
391 if (ppdev
->PointerAttributes
.Enable
== TRUE
)
396 ppdev
->PointerAttributes
.Enable
= TRUE
;
399 * Copy the pixels under the cursor to temporary surface.
402 if (ppdev
->PointerSaveSurface
!= NULL
)
406 SURFOBJ
*SaveSurface
;
408 SrcPoint
.x
= max(ppdev
->PointerAttributes
.Column
, 0);
409 SrcPoint
.y
= max(ppdev
->PointerAttributes
.Row
, 0);
411 DestRect
.left
= SrcPoint
.x
- ppdev
->PointerAttributes
.Column
;
412 DestRect
.top
= SrcPoint
.y
- ppdev
->PointerAttributes
.Row
;
413 DestRect
.right
= min(
414 ppdev
->PointerAttributes
.Width
,
415 DestSurface
->sizlBitmap
.cx
- ppdev
->PointerAttributes
.Column
);
416 DestRect
.bottom
= min(
417 ppdev
->PointerAttributes
.Height
,
418 DestSurface
->sizlBitmap
.cy
- ppdev
->PointerAttributes
.Row
);
420 SaveSurface
= EngLockSurface(ppdev
->PointerSaveSurface
);
421 EngBitBlt(SaveSurface
, DestSurface
, NULL
, NULL
, NULL
,
422 &DestRect
, &SrcPoint
, NULL
, NULL
, NULL
, SRCCOPY
);
423 EngUnlockSurface(SaveSurface
);
427 * Blit the cursor on the screen.
436 DestRect
.left
= max(ppdev
->PointerAttributes
.Column
, 0);
437 DestRect
.top
= max(ppdev
->PointerAttributes
.Row
, 0);
438 DestRect
.right
= min(
439 ppdev
->PointerAttributes
.Column
+ ppdev
->PointerAttributes
.Width
,
440 DestSurface
->sizlBitmap
.cx
);
441 DestRect
.bottom
= min(
442 ppdev
->PointerAttributes
.Row
+ ppdev
->PointerAttributes
.Height
,
443 DestSurface
->sizlBitmap
.cy
);
445 SrcPoint
.x
= max(-ppdev
->PointerAttributes
.Column
, 0);
446 SrcPoint
.y
= max(-ppdev
->PointerAttributes
.Row
, 0);
448 MaskSurf
= EngLockSurface(ppdev
->PointerMaskSurface
);
449 if (ppdev
->PointerColorSurface
!= NULL
)
451 ColorSurf
= EngLockSurface(ppdev
->PointerColorSurface
);
452 EngBitBlt(DestSurface
, ColorSurf
, MaskSurf
, NULL
, ppdev
->PointerXlateObject
,
453 &DestRect
, &SrcPoint
, &SrcPoint
, NULL
, NULL
, 0xAACC);
454 EngUnlockSurface(ColorSurf
);
458 EngBitBlt(DestSurface
, MaskSurf
, NULL
, NULL
, ppdev
->PointerXlateObject
,
459 &DestRect
, &SrcPoint
, NULL
, NULL
, NULL
, SRCAND
);
460 SrcPoint
.y
+= ppdev
->PointerAttributes
.Height
;
461 EngBitBlt(DestSurface
, MaskSurf
, NULL
, NULL
, ppdev
->PointerXlateObject
,
462 &DestRect
, &SrcPoint
, NULL
, NULL
, NULL
, SRCINVERT
);
464 EngUnlockSurface(MaskSurf
);
476 IN SURFOBJ
*psoColor
,
485 GDIDEVICE
*ppdev
= (GDIDEVICE
*)pso
->hdev
;
486 SURFOBJ
*TempSurfObj
;
488 IntHideMousePointer(ppdev
, pso
);
490 if (ppdev
->PointerColorSurface
!= NULL
)
492 /* FIXME: Is this really needed? */
493 TempSurfObj
= EngLockSurface(ppdev
->PointerColorSurface
);
494 EngFreeMem(TempSurfObj
->pvBits
);
495 TempSurfObj
->pvBits
= 0;
496 EngUnlockSurface(TempSurfObj
);
498 EngDeleteSurface(ppdev
->PointerColorSurface
);
499 ppdev
->PointerMaskSurface
= NULL
;
502 if (ppdev
->PointerMaskSurface
!= NULL
)
504 /* FIXME: Is this really needed? */
505 TempSurfObj
= EngLockSurface(ppdev
->PointerMaskSurface
);
506 EngFreeMem(TempSurfObj
->pvBits
);
507 TempSurfObj
->pvBits
= 0;
508 EngUnlockSurface(TempSurfObj
);
510 EngDeleteSurface(ppdev
->PointerMaskSurface
);
511 ppdev
->PointerMaskSurface
= NULL
;
514 if (ppdev
->PointerSaveSurface
!= NULL
)
516 EngDeleteSurface(ppdev
->PointerSaveSurface
);
517 ppdev
->PointerSaveSurface
= NULL
;
520 if (ppdev
->PointerXlateObject
!= NULL
)
522 EngDeleteXlate(ppdev
->PointerXlateObject
);
523 ppdev
->PointerXlateObject
= NULL
;
527 * See if we are being asked to hide the pointer.
532 return SPS_ACCEPT_NOEXCLUDE
;
535 ppdev
->PointerHotSpot
.x
= xHot
;
536 ppdev
->PointerHotSpot
.y
= yHot
;
538 ppdev
->PointerAttributes
.Column
= x
- xHot
;
539 ppdev
->PointerAttributes
.Row
= y
- yHot
;
540 ppdev
->PointerAttributes
.Width
= abs(psoMask
->lDelta
) << 3;
541 ppdev
->PointerAttributes
.Height
= (psoMask
->cjBits
/ abs(psoMask
->lDelta
)) >> 1;
545 prcl
->left
= ppdev
->PointerAttributes
.Column
;
546 prcl
->top
= ppdev
->PointerAttributes
.Row
;
547 prcl
->right
= prcl
->left
+ ppdev
->PointerAttributes
.Width
;
548 prcl
->bottom
= prcl
->top
+ ppdev
->PointerAttributes
.Height
;
551 if (psoColor
!= NULL
)
556 Size
.cx
= ppdev
->PointerAttributes
.Width
;
557 Size
.cy
= ppdev
->PointerAttributes
.Height
;
558 Bits
= EngAllocMem(0, psoColor
->cjBits
, TAG_MOUSE
);
559 memcpy(Bits
, psoColor
->pvBits
, psoColor
->cjBits
);
561 ppdev
->PointerColorSurface
= (HSURF
)EngCreateBitmap(Size
,
562 psoColor
->lDelta
, psoColor
->iBitmapFormat
,
563 psoColor
->lDelta
< 0 ? 0 : BMF_TOPDOWN
, Bits
);
567 ppdev
->PointerColorSurface
= NULL
;
574 Size
.cx
= ppdev
->PointerAttributes
.Width
;
575 Size
.cy
= ppdev
->PointerAttributes
.Height
<< 1;
576 Bits
= EngAllocMem(0, psoMask
->cjBits
, TAG_MOUSE
);
577 memcpy(Bits
, psoMask
->pvBits
, psoMask
->cjBits
);
579 ppdev
->PointerMaskSurface
= (HSURF
)EngCreateBitmap(Size
,
580 psoMask
->lDelta
, psoMask
->iBitmapFormat
,
581 psoMask
->lDelta
< 0 ? 0 : BMF_TOPDOWN
, Bits
);
585 * Create an XLATEOBJ that will be used for drawing masks.
586 * FIXME: We should get this in pxlo parameter!
591 HPALETTE BWPalette
, DestPalette
;
592 ULONG BWColors
[] = {0, 0xFFFFFF};
597 BWPalette
= EngCreatePalette(PAL_INDEXED
, sizeof(BWColors
) / sizeof(ULONG
),
599 Dc
= DC_LockDc(IntGetScreenDC());
600 DestPalette
= Dc
->w
.hPalette
;
601 PalObj
= PALETTE_LockPalette(DestPalette
);
602 DestMode
= PalObj
->Mode
;
603 PALETTE_UnlockPalette(DestPalette
);
604 DC_UnlockDc(IntGetScreenDC());
605 ppdev
->PointerXlateObject
= IntEngCreateXlate(DestMode
, PAL_INDEXED
,
606 DestPalette
, BWPalette
);
607 EngDeletePalette(BWPalette
);
611 ppdev
->PointerXlateObject
= pxlo
;
615 * Create surface for saving the pixels under the cursor.
622 Size
.cx
= ppdev
->PointerAttributes
.Width
;
623 Size
.cy
= ppdev
->PointerAttributes
.Height
;
625 switch (pso
->iBitmapFormat
)
627 case BMF_1BPP
: lDelta
= Size
.cx
>> 3; break;
628 case BMF_4BPP
: lDelta
= Size
.cx
>> 1; break;
629 case BMF_8BPP
: lDelta
= Size
.cx
; break;
630 case BMF_16BPP
: lDelta
= Size
.cx
<< 1; break;
631 case BMF_24BPP
: lDelta
= Size
.cx
* 3; break;
632 case BMF_32BPP
: lDelta
= Size
.cx
<< 2; break;
633 default: lDelta
= 0; break;
636 ppdev
->PointerSaveSurface
= (HSURF
)EngCreateBitmap(
637 Size
, lDelta
, pso
->iBitmapFormat
, BMF_TOPDOWN
| BMF_NOZEROINIT
, NULL
);
640 IntShowMousePointer(ppdev
, pso
);
642 return SPS_ACCEPT_EXCLUDE
;
656 GDIDEVICE
*ppdev
= (GDIDEVICE
*)pso
->hdev
;
658 IntHideMousePointer(ppdev
, pso
);
659 ppdev
->PointerAttributes
.Column
= x
- ppdev
->PointerHotSpot
.x
;
660 ppdev
->PointerAttributes
.Row
= y
- ppdev
->PointerHotSpot
.y
;
663 IntShowMousePointer(ppdev
, pso
);
668 prcl
->left
= ppdev
->PointerAttributes
.Column
;
669 prcl
->top
= ppdev
->PointerAttributes
.Row
;
670 prcl
->right
= prcl
->left
+ ppdev
->PointerAttributes
.Width
;
671 prcl
->bottom
= prcl
->top
+ ppdev
->PointerAttributes
.Height
;