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