[WIN32SS]
[reactos.git] / reactos / win32ss / drivers / displays / vga / objects / pointer.c
1 /*
2 * PROJECT: ReactOS VGA display driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/video/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 }