mirror of
https://github.com/reactos/reactos.git
synced 2024-11-07 15:10:53 +00:00
372 lines
11 KiB
C
372 lines
11 KiB
C
/*
|
|
* PROJECT: ReactOS VGA display driver
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* FILE: win32ss/drivers/displays/vga/objects/pointer.c
|
|
* PURPOSE: Draws the mouse pointer
|
|
* PROGRAMMERS: Copyright (C) 1998-2001 ReactOS Team
|
|
*/
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
#include <vgaddi.h>
|
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
static VOID VGADDI_HideCursor(PPDEV ppdev);
|
|
static VOID VGADDI_ShowCursor(PPDEV ppdev, PRECTL prcl);
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
VOID
|
|
VGADDI_BltPointerToVGA(
|
|
IN LONG StartX,
|
|
IN LONG StartY,
|
|
IN ULONG SizeX,
|
|
IN ULONG SizeY,
|
|
IN PUCHAR MaskBits,
|
|
IN ULONG MaskPitch,
|
|
IN ULONG MaskOp)
|
|
{
|
|
ULONG DestX, EndX, DestY, EndY;
|
|
UCHAR Mask;
|
|
PUCHAR Video;
|
|
PUCHAR Src;
|
|
UCHAR SrcValue;
|
|
ULONG i, j;
|
|
ULONG Left;
|
|
ULONG Length;
|
|
LONG Bits;
|
|
|
|
DestX = StartX < 0 ? 0 : StartX;
|
|
DestY = StartY < 0 ? 0 : StartY;
|
|
EndX = StartX + SizeX;
|
|
EndY = StartY + SizeY;
|
|
|
|
/* Set write mode zero. */
|
|
WRITE_PORT_UCHAR((PUCHAR)GRA_I, 5);
|
|
WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0);
|
|
|
|
/* Select raster op. */
|
|
WRITE_PORT_UCHAR((PUCHAR)GRA_I, 3);
|
|
WRITE_PORT_UCHAR((PUCHAR)GRA_D, MaskOp);
|
|
|
|
if ((DestX % 8) != 0)
|
|
{
|
|
/* Disable writes to pixels outside of the destination rectangle. */
|
|
Mask = (1 << (8 - (DestX % 8))) - 1;
|
|
if ((EndX - DestX) < (8 - (DestX % 8)))
|
|
{
|
|
Mask &= ~((1 << (8 - (EndX % 8))) - 1);
|
|
}
|
|
WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x8);
|
|
WRITE_PORT_UCHAR((PUCHAR)GRA_D, Mask);
|
|
|
|
/* Write the mask. */
|
|
Video = (PUCHAR)vidmem + DestY * 80 + (DestX >> 3);
|
|
Src = MaskBits + (SizeY - (DestY - StartY)) * MaskPitch;
|
|
for (i = DestY; i < EndY; i++, Video += 80)
|
|
{
|
|
Src -= MaskPitch;
|
|
SrcValue = (*Src) >> (DestX % 8);
|
|
(VOID)READ_REGISTER_UCHAR(Video);
|
|
WRITE_REGISTER_UCHAR(Video, SrcValue);
|
|
}
|
|
}
|
|
|
|
/* Enable writes to all pixels. */
|
|
WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x8);
|
|
WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0xFF);
|
|
|
|
/* Have we finished. */
|
|
if ((EndX - DestX) < (8 - (DestX % 8)))
|
|
return;
|
|
|
|
/* Fill any whole rows of eight pixels. */
|
|
Left = (DestX + 7) & ~0x7;
|
|
Length = (EndX >> 3) - (Left >> 3);
|
|
Bits = StartX;
|
|
while (Bits < 0)
|
|
Bits += 8;
|
|
Bits = Bits % 8;
|
|
for (i = DestY; i < EndY; i++)
|
|
{
|
|
Video = (PUCHAR)vidmem + i * 80 + (Left >> 3);
|
|
Src = MaskBits + (EndY - i - 1) * MaskPitch + ((DestX - StartX) >> 3);
|
|
for (j = 0; j < Length; j++, Video++, Src++)
|
|
{
|
|
if (Bits != 0)
|
|
{
|
|
SrcValue = (Src[0] << (8 - Bits));
|
|
SrcValue |= (Src[1] >> Bits);
|
|
}
|
|
else
|
|
{
|
|
SrcValue = Src[0];
|
|
}
|
|
(VOID)READ_REGISTER_UCHAR(Video);
|
|
WRITE_REGISTER_UCHAR(Video, SrcValue);
|
|
}
|
|
}
|
|
|
|
/* Fill any pixels on the right which don't fall into a complete row. */
|
|
if ((EndX % 8) != 0)
|
|
{
|
|
/* Disable writes to pixels outside the destination rectangle. */
|
|
Mask = ~((1 << (8 - (EndX % 8))) - 1);
|
|
WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x8);
|
|
WRITE_PORT_UCHAR((PUCHAR)GRA_D, Mask);
|
|
|
|
Video = (PUCHAR)vidmem + DestY * 80 + (EndX >> 3);
|
|
Src = MaskBits + (SizeY - (DestY - StartY)) * MaskPitch + (SizeX >> 3) - 1;
|
|
for (i = DestY; i < EndY; i++, Video += 80)
|
|
{
|
|
Src -= MaskPitch;
|
|
SrcValue = (Src[0] << (8 - Bits));
|
|
(VOID)READ_REGISTER_UCHAR(Video);
|
|
WRITE_REGISTER_UCHAR(Video, SrcValue);
|
|
}
|
|
|
|
/* Restore the default write masks. */
|
|
WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x8);
|
|
WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0xFF);
|
|
}
|
|
|
|
/* Set write mode two. */
|
|
WRITE_PORT_UCHAR((PUCHAR)GRA_I, 5);
|
|
WRITE_PORT_UCHAR((PUCHAR)GRA_D, 2);
|
|
|
|
/* Select raster op replace. */
|
|
WRITE_PORT_UCHAR((PUCHAR)GRA_I, 3);
|
|
WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0);
|
|
}
|
|
|
|
BOOL InitPointer(PPDEV ppdev)
|
|
{
|
|
ULONG CursorWidth = 32, CursorHeight = 32;
|
|
ULONG PointerAttributesSize;
|
|
ULONG SavedMemSize;
|
|
|
|
ppdev->xyHotSpot.x = 0;
|
|
ppdev->xyHotSpot.y = 0;
|
|
|
|
/* Determine the size of the pointer attributes */
|
|
PointerAttributesSize = sizeof(VIDEO_POINTER_ATTRIBUTES) +
|
|
((CursorWidth * CursorHeight * 2) >> 3);
|
|
|
|
/* Allocate memory for pointer attributes */
|
|
ppdev->pPointerAttributes = EngAllocMem(0, PointerAttributesSize, ALLOC_TAG);
|
|
|
|
ppdev->pPointerAttributes->Flags = 0; /* FIXME: Do this right */
|
|
ppdev->pPointerAttributes->Width = CursorWidth;
|
|
ppdev->pPointerAttributes->Height = CursorHeight;
|
|
ppdev->pPointerAttributes->WidthInBytes = CursorWidth >> 3;
|
|
ppdev->pPointerAttributes->Enable = 0;
|
|
ppdev->pPointerAttributes->Column = 0;
|
|
ppdev->pPointerAttributes->Row = 0;
|
|
|
|
/* Allocate memory for the pixels behind the cursor */
|
|
SavedMemSize = ((((CursorWidth + 7) & ~0x7) + 16) * CursorHeight) >> 3;
|
|
ppdev->ImageBehindCursor = VGADDI_AllocSavedScreenBits(SavedMemSize);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID APIENTRY
|
|
DrvMovePointer(
|
|
IN SURFOBJ* pso,
|
|
IN LONG x,
|
|
IN LONG y,
|
|
IN PRECTL prcl)
|
|
{
|
|
PPDEV ppdev = (PPDEV)pso->dhpdev;
|
|
|
|
VGADDI_HideCursor(ppdev);
|
|
|
|
if(x != -1)
|
|
{
|
|
ppdev->pPointerAttributes->Column = x;
|
|
ppdev->pPointerAttributes->Row = y;
|
|
|
|
VGADDI_ShowCursor(ppdev, prcl);
|
|
}
|
|
}
|
|
|
|
|
|
ULONG APIENTRY
|
|
DrvSetPointerShape(
|
|
IN SURFOBJ* pso,
|
|
IN SURFOBJ* psoMask,
|
|
IN SURFOBJ* psoColor,
|
|
IN XLATEOBJ* pxlo,
|
|
IN LONG xHot,
|
|
IN LONG yHot,
|
|
IN LONG x,
|
|
IN LONG y,
|
|
IN PRECTL prcl,
|
|
IN ULONG fl)
|
|
{
|
|
PPDEV ppdev = (PPDEV)pso->dhpdev;
|
|
ULONG NewWidth, NewHeight;
|
|
PUCHAR Src, Dest;
|
|
ULONG i;
|
|
|
|
if (!psoMask)
|
|
return SPS_DECLINE;
|
|
|
|
/* Hide the cursor */
|
|
VGADDI_HideCursor(ppdev);
|
|
|
|
NewWidth = abs(psoMask->lDelta) << 3;
|
|
NewHeight = (psoMask->cjBits / abs(psoMask->lDelta)) / 2;
|
|
|
|
/* Reallocate the space for the cursor if necessary. */
|
|
if (ppdev->pPointerAttributes->Width != NewWidth ||
|
|
ppdev->pPointerAttributes->Height != NewHeight)
|
|
{
|
|
ULONG PointerAttributesSize;
|
|
PVIDEO_POINTER_ATTRIBUTES NewPointerAttributes;
|
|
ULONG SavedMemSize;
|
|
|
|
/* Determine the size of the pointer attributes */
|
|
PointerAttributesSize = sizeof(VIDEO_POINTER_ATTRIBUTES) +
|
|
((NewWidth * NewHeight * 2) >> 3);
|
|
|
|
/* Allocate memory for pointer attributes */
|
|
NewPointerAttributes = EngAllocMem(0, PointerAttributesSize, ALLOC_TAG);
|
|
*NewPointerAttributes = *ppdev->pPointerAttributes;
|
|
NewPointerAttributes->Width = NewWidth;
|
|
NewPointerAttributes->Height = NewHeight;
|
|
NewPointerAttributes->WidthInBytes = NewWidth >> 3;
|
|
EngFreeMem(ppdev->pPointerAttributes);
|
|
ppdev->pPointerAttributes = NewPointerAttributes;
|
|
|
|
/* Reallocate the space for the saved bits. */
|
|
VGADDI_FreeSavedScreenBits(ppdev->ImageBehindCursor);
|
|
SavedMemSize = ((((NewWidth + 7) & ~0x7) + 16) * NewHeight) >> 3;
|
|
ppdev->ImageBehindCursor = VGADDI_AllocSavedScreenBits(SavedMemSize);
|
|
}
|
|
|
|
Src = (PUCHAR)psoMask->pvScan0;
|
|
/* Copy the new cursor in. */
|
|
for (i = 0; i < (NewHeight * 2); i++)
|
|
{
|
|
Dest = (PUCHAR)ppdev->pPointerAttributes->Pixels;
|
|
if (i >= NewHeight)
|
|
Dest += (((NewHeight * 3) - i - 1) * (NewWidth >> 3));
|
|
else
|
|
Dest += ((NewHeight - i - 1) * (NewWidth >> 3));
|
|
memcpy(Dest, Src, NewWidth >> 3);
|
|
Src += psoMask->lDelta;
|
|
}
|
|
|
|
/* Set the new cursor position */
|
|
ppdev->xyHotSpot.x = xHot;
|
|
ppdev->xyHotSpot.y = yHot;
|
|
|
|
if(x != -1)
|
|
{
|
|
ppdev->pPointerAttributes->Column = x;
|
|
ppdev->pPointerAttributes->Row = y;
|
|
|
|
/* show the cursor */
|
|
VGADDI_ShowCursor(ppdev, prcl);
|
|
}
|
|
|
|
return SPS_ACCEPT_NOEXCLUDE;
|
|
}
|
|
|
|
static VOID FASTCALL
|
|
VGADDI_ComputePointerRect(
|
|
IN PPDEV ppdev,
|
|
IN LONG X,
|
|
IN LONG Y,
|
|
IN PRECTL Rect)
|
|
{
|
|
ULONG SizeX, SizeY;
|
|
|
|
SizeX = min(((X + (LONG)ppdev->pPointerAttributes->Width) + 7) & ~0x7, ppdev->sizeSurf.cx);
|
|
SizeX -= (X & ~0x7);
|
|
SizeY = min((LONG)ppdev->pPointerAttributes->Height, ppdev->sizeSurf.cy - Y);
|
|
|
|
Rect->left = max(X, 0) & ~0x7;
|
|
Rect->top = max(Y, 0);
|
|
Rect->right = Rect->left + SizeX;
|
|
Rect->bottom = Rect->top + SizeY;
|
|
}
|
|
|
|
static VOID
|
|
VGADDI_HideCursor(PPDEV ppdev)
|
|
{
|
|
if(ppdev->pPointerAttributes->Enable)
|
|
{
|
|
LONG cx, cy;
|
|
RECTL Rect;
|
|
|
|
ppdev->pPointerAttributes->Enable = 0;
|
|
|
|
cx = ppdev->pPointerAttributes->Column - ppdev->xyHotSpot.x;
|
|
cy = ppdev->pPointerAttributes->Row - ppdev->xyHotSpot.y;
|
|
|
|
VGADDI_ComputePointerRect(ppdev, cx, cy, &Rect);
|
|
|
|
/* Display what was behind cursor */
|
|
VGADDI_BltFromSavedScreenBits(Rect.left,
|
|
Rect.top,
|
|
ppdev->ImageBehindCursor,
|
|
Rect.right - Rect.left,
|
|
Rect.bottom - Rect.top);
|
|
}
|
|
}
|
|
|
|
static VOID
|
|
VGADDI_ShowCursor(PPDEV ppdev, PRECTL prcl)
|
|
{
|
|
LONG cx, cy;
|
|
PUCHAR AndMask, XorMask;
|
|
ULONG SizeX, SizeY;
|
|
RECTL Rect;
|
|
|
|
if(ppdev->pPointerAttributes->Enable)
|
|
return;
|
|
|
|
/* Mark the cursor as currently displayed. */
|
|
ppdev->pPointerAttributes->Enable = 1;
|
|
|
|
cx = ppdev->pPointerAttributes->Column - ppdev->xyHotSpot.x;
|
|
cy = ppdev->pPointerAttributes->Row - ppdev->xyHotSpot.y;
|
|
|
|
/* Capture pixels behind the cursor */
|
|
VGADDI_ComputePointerRect(ppdev, cx, cy, &Rect);
|
|
|
|
VGADDI_BltToSavedScreenBits(ppdev->ImageBehindCursor,
|
|
Rect.left,
|
|
Rect.top,
|
|
Rect.right - Rect.left,
|
|
Rect.bottom - Rect.top);
|
|
|
|
/* Display the cursor. */
|
|
SizeX = min((LONG)ppdev->pPointerAttributes->Width, ppdev->sizeSurf.cx - cx);
|
|
SizeY = min((LONG)ppdev->pPointerAttributes->Height, ppdev->sizeSurf.cy - cy);
|
|
AndMask = ppdev->pPointerAttributes->Pixels +
|
|
(ppdev->pPointerAttributes->Height - SizeY) * ppdev->pPointerAttributes->WidthInBytes;
|
|
VGADDI_BltPointerToVGA(cx,
|
|
cy,
|
|
SizeX,
|
|
SizeY,
|
|
AndMask,
|
|
ppdev->pPointerAttributes->WidthInBytes,
|
|
VGA_AND);
|
|
XorMask = AndMask +
|
|
ppdev->pPointerAttributes->WidthInBytes *
|
|
ppdev->pPointerAttributes->Height;
|
|
VGADDI_BltPointerToVGA(cx,
|
|
cy,
|
|
SizeX,
|
|
SizeY,
|
|
XorMask,
|
|
ppdev->pPointerAttributes->WidthInBytes,
|
|
VGA_XOR);
|
|
|
|
if (NULL != prcl)
|
|
*prcl = Rect;
|
|
}
|