branch update for HEAD-2003021201
[reactos.git] / drivers / dd / vga / display / 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 /* GLOBALS *******************************************************************/
32
33 static ULONG oldx, oldy;
34 static PSAVED_SCREEN_BITS ImageBehindCursor = NULL;
35 VOID VGADDI_HideCursor(PPDEV ppdev);
36 VOID VGADDI_ShowCursor(PPDEV ppdev);
37
38 /* FUNCTIONS *****************************************************************/
39
40 VOID
41 VGADDI_BltPointerToVGA(ULONG StartX, ULONG StartY, ULONG SizeX,
42                        ULONG SizeY, PUCHAR MaskBits, ULONG MaskOp)
43 {
44   ULONG EndX, EndY;
45   UCHAR Mask;
46   PUCHAR Video;
47   PUCHAR Src;
48   ULONG MaskPitch;
49   UCHAR SrcValue;
50   ULONG i, j;
51   ULONG Left;
52   ULONG Length;
53
54   EndX = StartX + SizeX;
55   EndY = StartY + SizeY;
56   MaskPitch = SizeX >> 3;
57
58   /* Set write mode zero. */
59   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 5);
60   WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0);
61
62   /* Select raster op. */
63   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 3);
64   WRITE_PORT_UCHAR((PUCHAR)GRA_D, MaskOp);
65
66   if ((StartX % 8) != 0)
67     {
68       /* Disable writes to pixels outside of the destination rectangle. */
69       Mask = (1 << (8 - (StartX % 8))) - 1;
70       if ((EndX - StartX) < (8 - (StartX % 8)))
71         {
72           Mask &= ~((1 << (8 - (EndX % 8))) - 1);
73         }
74       WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x8);
75       WRITE_PORT_UCHAR((PUCHAR)GRA_D, Mask);
76
77       /* Write the mask. */
78       Video = (PUCHAR)vidmem + StartY * 80 + (StartX >> 3);
79       Src = MaskBits;
80       for (i = 0; i < SizeY; i++, Video+=80, Src+=MaskPitch)
81         {
82           SrcValue = (*Src) >> (StartX % 8);
83           (VOID)READ_REGISTER_UCHAR(Video);
84           WRITE_REGISTER_UCHAR(Video, SrcValue);
85         }
86     }
87
88   /* Enable writes to all pixels. */
89   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x8);
90   WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0xFF);
91
92   /* Have we finished. */
93   if ((EndX - StartX) < (8 - (StartX % 8)))
94     {
95       return;
96     }
97
98   /* Fill any whole rows of eight pixels. */
99   Left = (StartX + 7) & ~0x7;
100   Length = (EndX >> 3) - (Left >> 3);
101   for (i = StartY; i < EndY; i++)
102     {
103       Video = (PUCHAR)vidmem + i * 80 + (Left >> 3);
104       Src = MaskBits + (i - StartY) * MaskPitch;
105       for (j = 0; j < Length; j++, Video++, Src++)
106         {
107           if ((StartX % 8) != 0)
108             {
109               SrcValue = (Src[0] << (8 - (StartX % 8)));
110               SrcValue |= (Src[1] >> (StartX % 8));
111             }
112           else
113             {
114               SrcValue = Src[0];
115             }
116           (VOID)READ_REGISTER_UCHAR(Video);
117           WRITE_REGISTER_UCHAR(Video, SrcValue);
118         }
119     }
120
121   /* Fill any pixels on the right which don't fall into a complete row. */
122   if ((EndX % 8) != 0)
123     {
124       /* Disable writes to pixels outside the destination rectangle. */
125       Mask = ~((1 << (8 - (EndX % 8))) - 1);
126       WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x8);
127       WRITE_PORT_UCHAR((PUCHAR)GRA_D, Mask);
128
129       Video = (PUCHAR)vidmem + StartY * 80 + (EndX >> 3);
130       Src = MaskBits + (SizeX >> 3) - 1;
131       for (i = StartY; i < EndY; i++, Video+=80, Src+=MaskPitch)
132         {
133           SrcValue = (Src[0] << (8 - (StartX % 8)));
134           (VOID)READ_REGISTER_UCHAR(Video);
135           WRITE_REGISTER_UCHAR(Video, SrcValue);
136         }
137
138       /* Restore the default write masks. */
139       WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x8);
140       WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0xFF);
141     }
142
143   /* Set write mode two. */
144   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 5);
145   WRITE_PORT_UCHAR((PUCHAR)GRA_D, 2);
146
147   /* Select raster op replace. */
148   WRITE_PORT_UCHAR((PUCHAR)GRA_I, 3);
149   WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0);
150 }
151
152 BOOL InitPointer(PPDEV ppdev)
153 {
154   ULONG CursorWidth = 32, CursorHeight = 32;
155   ULONG PointerAttributesSize;
156   ULONG SavedMemSize;
157
158   /* Determine the size of the pointer attributes */
159   PointerAttributesSize = sizeof(VIDEO_POINTER_ATTRIBUTES) +
160     ((CursorWidth * CursorHeight * 2) >> 3);
161
162   /* Allocate memory for pointer attributes */
163   ppdev->pPointerAttributes = EngAllocMem(0, PointerAttributesSize, ALLOC_TAG);
164
165   ppdev->pPointerAttributes->Flags = 0; /* FIXME: Do this right */
166   ppdev->pPointerAttributes->Width = CursorWidth;
167   ppdev->pPointerAttributes->Height = CursorHeight;
168   ppdev->pPointerAttributes->WidthInBytes = CursorWidth >> 3;
169   ppdev->pPointerAttributes->Enable = 0;
170   ppdev->pPointerAttributes->Column = 0;
171   ppdev->pPointerAttributes->Row = 0;
172
173   /* Allocate memory for the pixels behind the cursor */
174   SavedMemSize = ((((CursorWidth + 7) & ~0x7) + 16) * CursorHeight) >> 3;
175   ImageBehindCursor = VGADDI_AllocSavedScreenBits(SavedMemSize);
176
177   return(TRUE);
178 }
179
180
181 VOID STDCALL
182 DrvMovePointer(IN PSURFOBJ pso,
183                IN LONG x,
184                IN LONG y,
185                IN PRECTL prcl)
186 {
187   PPDEV ppdev = (PPDEV)pso->dhpdev;
188
189   if (x < 0 )
190     {
191       /* x < 0 and y < 0 indicates we must hide the cursor */
192       VGADDI_HideCursor(ppdev);
193       return;
194     }
195
196   ppdev->xyCursor.x = x;
197   ppdev->xyCursor.y = y;
198
199   VGADDI_ShowCursor(ppdev);
200
201   /* Give feedback on the new cursor rectangle */
202   /*if (prcl != NULL) ComputePointerRect(ppdev, prcl);*/
203 }
204
205
206 ULONG STDCALL
207 DrvSetPointerShape(PSURFOBJ pso,
208                    PSURFOBJ psoMask,
209                    PSURFOBJ psoColor,
210                    PXLATEOBJ pxlo,
211                    LONG xHot,
212                    LONG yHot,
213                    LONG x,
214                    LONG y,
215                    PRECTL prcl,
216                    ULONG fl)
217 {
218   PPDEV ppdev = (PPDEV)pso->dhpdev;
219   ULONG NewWidth, NewHeight;
220   PUCHAR Src, Dest;
221   ULONG i, j;
222
223   NewWidth = psoMask->lDelta << 3;
224   NewHeight = (psoMask->cjBits / psoMask->lDelta) / 2;
225
226   /* Hide the cursor */
227   if(ppdev->pPointerAttributes->Enable != 0)
228     {
229       VGADDI_HideCursor(ppdev);
230     }
231
232   /* Reallocate the space for the cursor if necessary. */
233   if (ppdev->pPointerAttributes->Width != NewWidth ||
234       ppdev->pPointerAttributes->Height != NewHeight)
235     {
236       ULONG PointerAttributesSize;
237       PVIDEO_POINTER_ATTRIBUTES NewPointerAttributes;
238       ULONG SavedMemSize;
239
240       /* Determine the size of the pointer attributes */
241       PointerAttributesSize = sizeof(VIDEO_POINTER_ATTRIBUTES) +
242         ((NewWidth * NewHeight * 2) >> 3);
243
244       /* Allocate memory for pointer attributes */
245       NewPointerAttributes = EngAllocMem(0, PointerAttributesSize, ALLOC_TAG);
246       *NewPointerAttributes = *ppdev->pPointerAttributes;
247       NewPointerAttributes->Width = NewWidth;
248       NewPointerAttributes->Height = NewHeight;
249       NewPointerAttributes->WidthInBytes = NewWidth >> 3;
250       EngFreeMem(ppdev->pPointerAttributes);
251       ppdev->pPointerAttributes = NewPointerAttributes;
252
253       /* Reallocate the space for the saved bits. */
254       VGADDI_FreeSavedScreenBits(ImageBehindCursor);
255       SavedMemSize = ((((NewWidth + 7) & ~0x7) + 16) * NewHeight) >> 3;
256       ImageBehindCursor = VGADDI_AllocSavedScreenBits(SavedMemSize);
257     }
258
259   /* Copy the new cursor in. */
260   for (i = 0; i < (NewHeight * 2); i++)
261     {
262       Src = (PUCHAR)psoMask->pvBits;
263       Src += (i * (NewWidth >> 3));
264       Dest = (PUCHAR)ppdev->pPointerAttributes->Pixels;
265       if (i >= NewHeight)
266         {
267           Dest += (((NewHeight * 3) - i - 1) * (NewWidth >> 3));
268         }
269       else
270         {
271           Dest += ((NewHeight - i - 1) * (NewWidth >> 3));
272         }
273       memcpy(Dest, Src, NewWidth >> 3);
274     }
275
276   /* Set the new cursor position */
277   ppdev->xyCursor.x = x;
278   ppdev->xyCursor.y = y;
279
280   /* Show the cursor */
281   VGADDI_ShowCursor(ppdev);
282 }
283
284 VOID
285 VGADDI_HideCursor(PPDEV ppdev)
286 {
287   ULONG i, j, cx, cy, bitpos;
288   ULONG SizeX;
289
290   /* Display what was behind cursor */
291   SizeX = ((oldx + ppdev->pPointerAttributes->Width) + 7) & ~0x7;
292   SizeX -= (oldx & ~0x7);
293   VGADDI_BltFromSavedScreenBits(oldx & ~0x7,
294                                 oldy,
295                                 ImageBehindCursor,
296                                 SizeX,
297                                 ppdev->pPointerAttributes->Height);
298
299   ppdev->pPointerAttributes->Enable = 0;
300 }
301
302 VOID
303 VGADDI_ShowCursor(PPDEV ppdev)
304 {
305   ULONG i, j, cx, cy;
306   PUCHAR AndMask;
307   ULONG SizeX;
308
309   if (ppdev->pPointerAttributes->Enable != 0)
310     {
311       VGADDI_HideCursor(ppdev);
312     }
313
314   /* Capture pixels behind the cursor */
315   cx = ppdev->xyCursor.x;
316   cy = ppdev->xyCursor.y;
317
318   /* Used to repaint background */
319   SizeX = ((cx + ppdev->pPointerAttributes->Width) + 7) & ~0x7;
320   SizeX -= (cx & ~0x7);
321
322   VGADDI_BltToSavedScreenBits(ImageBehindCursor,
323                               cx & ~0x7,
324                               cy,
325                               SizeX,
326                               ppdev->pPointerAttributes->Height);
327
328   /* Display the cursor. */
329   AndMask = ppdev->pPointerAttributes->Pixels +
330     ppdev->pPointerAttributes->WidthInBytes *
331     ppdev->pPointerAttributes->Height;
332   VGADDI_BltPointerToVGA(ppdev->xyCursor.x,
333                          ppdev->xyCursor.y,
334                          ppdev->pPointerAttributes->Width,
335                          ppdev->pPointerAttributes->Height,
336                          AndMask,
337                          VGA_AND);
338   VGADDI_BltPointerToVGA(ppdev->xyCursor.x,
339                          ppdev->xyCursor.y,
340                          ppdev->pPointerAttributes->Width,
341                          ppdev->pPointerAttributes->Height,
342                          ppdev->pPointerAttributes->Pixels,
343                          VGA_XOR);
344
345   /* Save the new cursor location. */
346   oldx = ppdev->xyCursor.x;
347   oldy = ppdev->xyCursor.y;
348
349   /* Mark the cursor as currently displayed. */
350   ppdev->pPointerAttributes->Enable = 1;
351 }