1 /* 2 * PROJECT: ReactOS VGA display driver 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: win32ss/drivers/displays/vga/objects/pointer.c 5 * PURPOSE: Draws the mouse pointer 6 * PROGRAMMERS: Copyright (C) 1998-2001 ReactOS Team 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include <vgaddi.h> 12 13 /* GLOBALS *******************************************************************/ 14 15 static VOID VGADDI_HideCursor(PPDEV ppdev); 16 static VOID VGADDI_ShowCursor(PPDEV ppdev, PRECTL prcl); 17 18 /* FUNCTIONS *****************************************************************/ 19 20 VOID 21 VGADDI_BltPointerToVGA( 22 IN LONG StartX, 23 IN LONG StartY, 24 IN ULONG SizeX, 25 IN ULONG SizeY, 26 IN PUCHAR MaskBits, 27 IN ULONG MaskPitch, 28 IN ULONG MaskOp) 29 { 30 ULONG DestX, EndX, DestY, EndY; 31 UCHAR Mask; 32 PUCHAR Video; 33 PUCHAR Src; 34 UCHAR SrcValue; 35 ULONG i, j; 36 ULONG Left; 37 ULONG Length; 38 LONG Bits; 39 40 DestX = StartX < 0 ? 0 : StartX; 41 DestY = StartY < 0 ? 0 : StartY; 42 EndX = StartX + SizeX; 43 EndY = StartY + SizeY; 44 45 /* Set write mode zero. */ 46 WRITE_PORT_UCHAR((PUCHAR)GRA_I, 5); 47 WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0); 48 49 /* Select raster op. */ 50 WRITE_PORT_UCHAR((PUCHAR)GRA_I, 3); 51 WRITE_PORT_UCHAR((PUCHAR)GRA_D, MaskOp); 52 53 if ((DestX % 8) != 0) 54 { 55 /* Disable writes to pixels outside of the destination rectangle. */ 56 Mask = (1 << (8 - (DestX % 8))) - 1; 57 if ((EndX - DestX) < (8 - (DestX % 8))) 58 { 59 Mask &= ~((1 << (8 - (EndX % 8))) - 1); 60 } 61 WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x8); 62 WRITE_PORT_UCHAR((PUCHAR)GRA_D, Mask); 63 64 /* Write the mask. */ 65 Video = (PUCHAR)vidmem + DestY * 80 + (DestX >> 3); 66 Src = MaskBits + (SizeY - (DestY - StartY)) * MaskPitch; 67 for (i = DestY; i < EndY; i++, Video += 80) 68 { 69 Src -= MaskPitch; 70 SrcValue = (*Src) >> (DestX % 8); 71 (VOID)READ_REGISTER_UCHAR(Video); 72 WRITE_REGISTER_UCHAR(Video, SrcValue); 73 } 74 } 75 76 /* Enable writes to all pixels. */ 77 WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x8); 78 WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0xFF); 79 80 /* Have we finished. */ 81 if ((EndX - DestX) < (8 - (DestX % 8))) 82 return; 83 84 /* Fill any whole rows of eight pixels. */ 85 Left = (DestX + 7) & ~0x7; 86 Length = (EndX >> 3) - (Left >> 3); 87 Bits = StartX; 88 while (Bits < 0) 89 Bits += 8; 90 Bits = Bits % 8; 91 for (i = DestY; i < EndY; i++) 92 { 93 Video = (PUCHAR)vidmem + i * 80 + (Left >> 3); 94 Src = MaskBits + (EndY - i - 1) * MaskPitch + ((DestX - StartX) >> 3); 95 for (j = 0; j < Length; j++, Video++, Src++) 96 { 97 if (Bits != 0) 98 { 99 SrcValue = (Src[0] << (8 - Bits)); 100 SrcValue |= (Src[1] >> Bits); 101 } 102 else 103 { 104 SrcValue = Src[0]; 105 } 106 (VOID)READ_REGISTER_UCHAR(Video); 107 WRITE_REGISTER_UCHAR(Video, SrcValue); 108 } 109 } 110 111 /* Fill any pixels on the right which don't fall into a complete row. */ 112 if ((EndX % 8) != 0) 113 { 114 /* Disable writes to pixels outside the destination rectangle. */ 115 Mask = ~((1 << (8 - (EndX % 8))) - 1); 116 WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x8); 117 WRITE_PORT_UCHAR((PUCHAR)GRA_D, Mask); 118 119 Video = (PUCHAR)vidmem + DestY * 80 + (EndX >> 3); 120 Src = MaskBits + (SizeY - (DestY - StartY)) * MaskPitch + (SizeX >> 3) - 1; 121 for (i = DestY; i < EndY; i++, Video += 80) 122 { 123 Src -= MaskPitch; 124 SrcValue = (Src[0] << (8 - Bits)); 125 (VOID)READ_REGISTER_UCHAR(Video); 126 WRITE_REGISTER_UCHAR(Video, SrcValue); 127 } 128 129 /* Restore the default write masks. */ 130 WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x8); 131 WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0xFF); 132 } 133 134 /* Set write mode two. */ 135 WRITE_PORT_UCHAR((PUCHAR)GRA_I, 5); 136 WRITE_PORT_UCHAR((PUCHAR)GRA_D, 2); 137 138 /* Select raster op replace. */ 139 WRITE_PORT_UCHAR((PUCHAR)GRA_I, 3); 140 WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0); 141 } 142 143 BOOL InitPointer(PPDEV ppdev) 144 { 145 ULONG CursorWidth = 32, CursorHeight = 32; 146 ULONG PointerAttributesSize; 147 ULONG SavedMemSize; 148 149 ppdev->xyHotSpot.x = 0; 150 ppdev->xyHotSpot.y = 0; 151 152 /* Determine the size of the pointer attributes */ 153 PointerAttributesSize = sizeof(VIDEO_POINTER_ATTRIBUTES) + 154 ((CursorWidth * CursorHeight * 2) >> 3); 155 156 /* Allocate memory for pointer attributes */ 157 ppdev->pPointerAttributes = EngAllocMem(0, PointerAttributesSize, ALLOC_TAG); 158 159 ppdev->pPointerAttributes->Flags = 0; /* FIXME: Do this right */ 160 ppdev->pPointerAttributes->Width = CursorWidth; 161 ppdev->pPointerAttributes->Height = CursorHeight; 162 ppdev->pPointerAttributes->WidthInBytes = CursorWidth >> 3; 163 ppdev->pPointerAttributes->Enable = 0; 164 ppdev->pPointerAttributes->Column = 0; 165 ppdev->pPointerAttributes->Row = 0; 166 167 /* Allocate memory for the pixels behind the cursor */ 168 SavedMemSize = ((((CursorWidth + 7) & ~0x7) + 16) * CursorHeight) >> 3; 169 ppdev->ImageBehindCursor = VGADDI_AllocSavedScreenBits(SavedMemSize); 170 171 return TRUE; 172 } 173 174 VOID APIENTRY 175 DrvMovePointer( 176 IN SURFOBJ* pso, 177 IN LONG x, 178 IN LONG y, 179 IN PRECTL prcl) 180 { 181 PPDEV ppdev = (PPDEV)pso->dhpdev; 182 183 VGADDI_HideCursor(ppdev); 184 185 if(x != -1) 186 { 187 ppdev->pPointerAttributes->Column = x; 188 ppdev->pPointerAttributes->Row = y; 189 190 VGADDI_ShowCursor(ppdev, prcl); 191 } 192 } 193 194 195 ULONG APIENTRY 196 DrvSetPointerShape( 197 IN SURFOBJ* pso, 198 IN SURFOBJ* psoMask, 199 IN SURFOBJ* psoColor, 200 IN XLATEOBJ* pxlo, 201 IN LONG xHot, 202 IN LONG yHot, 203 IN LONG x, 204 IN LONG y, 205 IN PRECTL prcl, 206 IN ULONG fl) 207 { 208 PPDEV ppdev = (PPDEV)pso->dhpdev; 209 ULONG NewWidth, NewHeight; 210 PUCHAR Src, Dest; 211 ULONG i; 212 213 if (!psoMask) 214 return SPS_DECLINE; 215 216 /* Hide the cursor */ 217 VGADDI_HideCursor(ppdev); 218 219 NewWidth = abs(psoMask->lDelta) << 3; 220 NewHeight = (psoMask->cjBits / abs(psoMask->lDelta)) / 2; 221 222 /* Reallocate the space for the cursor if necessary. */ 223 if (ppdev->pPointerAttributes->Width != NewWidth || 224 ppdev->pPointerAttributes->Height != NewHeight) 225 { 226 ULONG PointerAttributesSize; 227 PVIDEO_POINTER_ATTRIBUTES NewPointerAttributes; 228 ULONG SavedMemSize; 229 230 /* Determine the size of the pointer attributes */ 231 PointerAttributesSize = sizeof(VIDEO_POINTER_ATTRIBUTES) + 232 ((NewWidth * NewHeight * 2) >> 3); 233 234 /* Allocate memory for pointer attributes */ 235 NewPointerAttributes = EngAllocMem(0, PointerAttributesSize, ALLOC_TAG); 236 *NewPointerAttributes = *ppdev->pPointerAttributes; 237 NewPointerAttributes->Width = NewWidth; 238 NewPointerAttributes->Height = NewHeight; 239 NewPointerAttributes->WidthInBytes = NewWidth >> 3; 240 EngFreeMem(ppdev->pPointerAttributes); 241 ppdev->pPointerAttributes = NewPointerAttributes; 242 243 /* Reallocate the space for the saved bits. */ 244 VGADDI_FreeSavedScreenBits(ppdev->ImageBehindCursor); 245 SavedMemSize = ((((NewWidth + 7) & ~0x7) + 16) * NewHeight) >> 3; 246 ppdev->ImageBehindCursor = VGADDI_AllocSavedScreenBits(SavedMemSize); 247 } 248 249 Src = (PUCHAR)psoMask->pvScan0; 250 /* Copy the new cursor in. */ 251 for (i = 0; i < (NewHeight * 2); i++) 252 { 253 Dest = (PUCHAR)ppdev->pPointerAttributes->Pixels; 254 if (i >= NewHeight) 255 Dest += (((NewHeight * 3) - i - 1) * (NewWidth >> 3)); 256 else 257 Dest += ((NewHeight - i - 1) * (NewWidth >> 3)); 258 memcpy(Dest, Src, NewWidth >> 3); 259 Src += psoMask->lDelta; 260 } 261 262 /* Set the new cursor position */ 263 ppdev->xyHotSpot.x = xHot; 264 ppdev->xyHotSpot.y = yHot; 265 266 if(x != -1) 267 { 268 ppdev->pPointerAttributes->Column = x; 269 ppdev->pPointerAttributes->Row = y; 270 271 /* show the cursor */ 272 VGADDI_ShowCursor(ppdev, prcl); 273 } 274 275 return SPS_ACCEPT_NOEXCLUDE; 276 } 277 278 static VOID FASTCALL 279 VGADDI_ComputePointerRect( 280 IN PPDEV ppdev, 281 IN LONG X, 282 IN LONG Y, 283 IN PRECTL Rect) 284 { 285 ULONG SizeX, SizeY; 286 287 SizeX = min(((X + (LONG)ppdev->pPointerAttributes->Width) + 7) & ~0x7, ppdev->sizeSurf.cx); 288 SizeX -= (X & ~0x7); 289 SizeY = min((LONG)ppdev->pPointerAttributes->Height, ppdev->sizeSurf.cy - Y); 290 291 Rect->left = max(X, 0) & ~0x7; 292 Rect->top = max(Y, 0); 293 Rect->right = Rect->left + SizeX; 294 Rect->bottom = Rect->top + SizeY; 295 } 296 297 static VOID 298 VGADDI_HideCursor(PPDEV ppdev) 299 { 300 if(ppdev->pPointerAttributes->Enable) 301 { 302 LONG cx, cy; 303 RECTL Rect; 304 305 ppdev->pPointerAttributes->Enable = 0; 306 307 cx = ppdev->pPointerAttributes->Column - ppdev->xyHotSpot.x; 308 cy = ppdev->pPointerAttributes->Row - ppdev->xyHotSpot.y; 309 310 VGADDI_ComputePointerRect(ppdev, cx, cy, &Rect); 311 312 /* Display what was behind cursor */ 313 VGADDI_BltFromSavedScreenBits(Rect.left, 314 Rect.top, 315 ppdev->ImageBehindCursor, 316 Rect.right - Rect.left, 317 Rect.bottom - Rect.top); 318 } 319 } 320 321 static VOID 322 VGADDI_ShowCursor(PPDEV ppdev, PRECTL prcl) 323 { 324 LONG cx, cy; 325 PUCHAR AndMask, XorMask; 326 ULONG SizeX, SizeY; 327 RECTL Rect; 328 329 if(ppdev->pPointerAttributes->Enable) 330 return; 331 332 /* Mark the cursor as currently displayed. */ 333 ppdev->pPointerAttributes->Enable = 1; 334 335 cx = ppdev->pPointerAttributes->Column - ppdev->xyHotSpot.x; 336 cy = ppdev->pPointerAttributes->Row - ppdev->xyHotSpot.y; 337 338 /* Capture pixels behind the cursor */ 339 VGADDI_ComputePointerRect(ppdev, cx, cy, &Rect); 340 341 VGADDI_BltToSavedScreenBits(ppdev->ImageBehindCursor, 342 Rect.left, 343 Rect.top, 344 Rect.right - Rect.left, 345 Rect.bottom - Rect.top); 346 347 /* Display the cursor. */ 348 SizeX = min((LONG)ppdev->pPointerAttributes->Width, ppdev->sizeSurf.cx - cx); 349 SizeY = min((LONG)ppdev->pPointerAttributes->Height, ppdev->sizeSurf.cy - cy); 350 AndMask = ppdev->pPointerAttributes->Pixels + 351 (ppdev->pPointerAttributes->Height - SizeY) * ppdev->pPointerAttributes->WidthInBytes; 352 VGADDI_BltPointerToVGA(cx, 353 cy, 354 SizeX, 355 SizeY, 356 AndMask, 357 ppdev->pPointerAttributes->WidthInBytes, 358 VGA_AND); 359 XorMask = AndMask + 360 ppdev->pPointerAttributes->WidthInBytes * 361 ppdev->pPointerAttributes->Height; 362 VGADDI_BltPointerToVGA(cx, 363 cy, 364 SizeX, 365 SizeY, 366 XorMask, 367 ppdev->pPointerAttributes->WidthInBytes, 368 VGA_XOR); 369 370 if (NULL != prcl) 371 *prcl = Rect; 372 } 373