[FRAMEBUF_NEW]
[reactos.git] / reactos / win32ss / drivers / displays / framebuf_new / pointer.c
1 /*
2 * PROJECT: ReactOS Framebuffer Display Driver
3 * LICENSE: Microsoft NT4 DDK Sample Code License
4 * FILE: boot/drivers/video/displays/framebuf/pointer.c
5 * PURPOSE: Hardware Pointer Support
6 * PROGRAMMERS: Copyright (c) 1992-1995 Microsoft Corporation
7 */
8
9 #include "driver.h"
10
11 BOOL NTAPI bCopyColorPointer(
12 PPDEV ppdev,
13 SURFOBJ *psoMask,
14 SURFOBJ *psoColor,
15 XLATEOBJ *pxlo);
16
17 BOOL NTAPI bCopyMonoPointer(
18 PPDEV ppdev,
19 SURFOBJ *psoMask);
20
21 BOOL NTAPI bSetHardwarePointerShape(
22 SURFOBJ *pso,
23 SURFOBJ *psoMask,
24 SURFOBJ *psoColor,
25 XLATEOBJ *pxlo,
26 LONG x,
27 LONG y,
28 FLONG fl);
29
30 /******************************Public*Routine******************************\
31 * DrvMovePointer
32 *
33 * Moves the hardware pointer to a new position.
34 *
35 \**************************************************************************/
36
37 VOID NTAPI DrvMovePointer
38 (
39 SURFOBJ *pso,
40 LONG x,
41 LONG y,
42 RECTL *prcl
43 )
44 {
45 PPDEV ppdev = (PPDEV) pso->dhpdev;
46 DWORD returnedDataLength;
47 VIDEO_POINTER_POSITION NewPointerPosition;
48
49 // We don't use the exclusion rectangle because we only support
50 // hardware Pointers. If we were doing our own Pointer simulations
51 // we would want to update prcl so that the engine would call us
52 // to exclude out pointer before drawing to the pixels in prcl.
53
54 UNREFERENCED_PARAMETER(prcl);
55
56 if (x == -1)
57 {
58 //
59 // A new position of (-1,-1) means hide the pointer.
60 //
61
62 if (EngDeviceIoControl(ppdev->hDriver,
63 IOCTL_VIDEO_DISABLE_POINTER,
64 NULL,
65 0,
66 NULL,
67 0,
68 &returnedDataLength))
69 {
70 //
71 // Not the end of the world, print warning in checked build.
72 //
73
74 DISPDBG((1, "DISP vMoveHardwarePointer failed IOCTL_VIDEO_DISABLE_POINTER\n"));
75 }
76 }
77 else
78 {
79 NewPointerPosition.Column = (SHORT) x - (SHORT) (ppdev->ptlHotSpot.x);
80 NewPointerPosition.Row = (SHORT) y - (SHORT) (ppdev->ptlHotSpot.y);
81
82 //
83 // Call miniport driver to move Pointer.
84 //
85
86 if (EngDeviceIoControl(ppdev->hDriver,
87 IOCTL_VIDEO_SET_POINTER_POSITION,
88 &NewPointerPosition,
89 sizeof(VIDEO_POINTER_POSITION),
90 NULL,
91 0,
92 &returnedDataLength))
93 {
94 //
95 // Not the end of the world, print warning in checked build.
96 //
97
98 DISPDBG((1, "DISP vMoveHardwarePointer failed IOCTL_VIDEO_SET_POINTER_POSITION\n"));
99 }
100 }
101 }
102
103 /******************************Public*Routine******************************\
104 * DrvSetPointerShape
105 *
106 * Sets the new pointer shape.
107 *
108 \**************************************************************************/
109
110 ULONG NTAPI DrvSetPointerShape
111 (
112 SURFOBJ *pso,
113 SURFOBJ *psoMask,
114 SURFOBJ *psoColor,
115 XLATEOBJ *pxlo,
116 LONG xHot,
117 LONG yHot,
118 LONG x,
119 LONG y,
120 RECTL *prcl,
121 FLONG fl
122 )
123 {
124 PPDEV ppdev = (PPDEV) pso->dhpdev;
125 DWORD returnedDataLength;
126
127 // We don't use the exclusion rectangle because we only support
128 // hardware Pointers. If we were doing our own Pointer simulations
129 // we would want to update prcl so that the engine would call us
130 // to exclude out pointer before drawing to the pixels in prcl.
131 UNREFERENCED_PARAMETER(prcl);
132
133 if (ppdev->pPointerAttributes == (PVIDEO_POINTER_ATTRIBUTES) NULL)
134 {
135 // Mini-port has no hardware Pointer support.
136 return(SPS_ERROR);
137 }
138
139 // See if we are being asked to hide the pointer
140
141 if (psoMask == (SURFOBJ *) NULL)
142 {
143 if (EngDeviceIoControl(ppdev->hDriver,
144 IOCTL_VIDEO_DISABLE_POINTER,
145 NULL,
146 0,
147 NULL,
148 0,
149 &returnedDataLength))
150 {
151 //
152 // It should never be possible to fail.
153 // Message supplied for debugging.
154 //
155
156 DISPDBG((1, "DISP bSetHardwarePointerShape failed IOCTL_VIDEO_DISABLE_POINTER\n"));
157 }
158
159 return(TRUE);
160 }
161
162 ppdev->ptlHotSpot.x = xHot;
163 ppdev->ptlHotSpot.y = yHot;
164
165 if (!bSetHardwarePointerShape(pso,psoMask,psoColor,pxlo,x,y,fl))
166 {
167 if (ppdev->fHwCursorActive) {
168 ppdev->fHwCursorActive = FALSE;
169
170 if (EngDeviceIoControl(ppdev->hDriver,
171 IOCTL_VIDEO_DISABLE_POINTER,
172 NULL,
173 0,
174 NULL,
175 0,
176 &returnedDataLength)) {
177
178 DISPDBG((1, "DISP bSetHardwarePointerShape failed IOCTL_VIDEO_DISABLE_POINTER\n"));
179 }
180 }
181
182 //
183 // Mini-port declines to realize this Pointer
184 //
185
186 return(SPS_DECLINE);
187 }
188 else
189 {
190 ppdev->fHwCursorActive = TRUE;
191 }
192
193 return(SPS_ACCEPT_NOEXCLUDE);
194 }
195
196 /******************************Public*Routine******************************\
197 * bSetHardwarePointerShape
198 *
199 * Changes the shape of the Hardware Pointer.
200 *
201 * Returns: True if successful, False if Pointer shape can't be hardware.
202 *
203 \**************************************************************************/
204
205 BOOL NTAPI bSetHardwarePointerShape(
206 SURFOBJ *pso,
207 SURFOBJ *psoMask,
208 SURFOBJ *psoColor,
209 XLATEOBJ *pxlo,
210 LONG x,
211 LONG y,
212 FLONG fl)
213 {
214 PPDEV ppdev = (PPDEV) pso->dhpdev;
215 PVIDEO_POINTER_ATTRIBUTES pPointerAttributes = ppdev->pPointerAttributes;
216 DWORD returnedDataLength;
217
218 if (psoColor != (SURFOBJ *) NULL)
219 {
220 if ((ppdev->PointerCapabilities.Flags & VIDEO_MODE_COLOR_POINTER) &&
221 bCopyColorPointer(ppdev, psoMask, psoColor, pxlo))
222 {
223 pPointerAttributes->Flags |= VIDEO_MODE_COLOR_POINTER;
224 } else {
225 return(FALSE);
226 }
227
228 } else {
229
230 if ((ppdev->PointerCapabilities.Flags & VIDEO_MODE_MONO_POINTER) &&
231 bCopyMonoPointer(ppdev, psoMask))
232 {
233 pPointerAttributes->Flags |= VIDEO_MODE_MONO_POINTER;
234 } else {
235 return(FALSE);
236 }
237 }
238
239 //
240 // Initialize Pointer attributes and position
241 //
242
243 pPointerAttributes->Enable = 1;
244
245 //
246 // if x,y = -1,-1 then pass them directly to the miniport so that
247 // the cursor will be disabled
248
249 pPointerAttributes->Column = (SHORT)(x);
250 pPointerAttributes->Row = (SHORT)(y);
251
252 if ((x != -1) || (y != -1)) {
253 pPointerAttributes->Column -= (SHORT)(ppdev->ptlHotSpot.x);
254 pPointerAttributes->Row -= (SHORT)(ppdev->ptlHotSpot.y);
255 }
256
257 //
258 // set animate flags
259 //
260
261 if (fl & SPS_ANIMATESTART) {
262 pPointerAttributes->Flags |= VIDEO_MODE_ANIMATE_START;
263 } else if (fl & SPS_ANIMATEUPDATE) {
264 pPointerAttributes->Flags |= VIDEO_MODE_ANIMATE_UPDATE;
265 }
266
267 //
268 // Set the new Pointer shape.
269 //
270
271 if (EngDeviceIoControl(ppdev->hDriver,
272 IOCTL_VIDEO_SET_POINTER_ATTR,
273 pPointerAttributes,
274 ppdev->cjPointerAttributes,
275 NULL,
276 0,
277 &returnedDataLength)) {
278
279 DISPDBG((1, "DISP:Failed IOCTL_VIDEO_SET_POINTER_ATTR call\n"));
280 return(FALSE);
281 }
282
283 return(TRUE);
284 }
285
286 /******************************Public*Routine******************************\
287 * bCopyMonoPointer
288 *
289 * Copies two monochrome masks into a buffer of the maximum size handled by the
290 * miniport, with any extra bits set to 0. The masks are converted to topdown
291 * form if they aren't already. Returns TRUE if we can handle this pointer in
292 * hardware, FALSE if not.
293 *
294 \**************************************************************************/
295
296 BOOL NTAPI bCopyMonoPointer(
297 PPDEV ppdev,
298 SURFOBJ *pso)
299 {
300 ULONG cy;
301 PBYTE pjSrcAnd, pjSrcXor;
302 LONG lDeltaSrc, lDeltaDst;
303 LONG lSrcWidthInBytes;
304 ULONG cxSrc = pso->sizlBitmap.cx;
305 ULONG cySrc = pso->sizlBitmap.cy;
306 ULONG cxSrcBytes;
307 PVIDEO_POINTER_ATTRIBUTES pPointerAttributes = ppdev->pPointerAttributes;
308 PBYTE pjDstAnd = pPointerAttributes->Pixels;
309 PBYTE pjDstXor = pPointerAttributes->Pixels;
310
311 // Make sure the new pointer isn't too big to handle
312 // (*2 because both masks are in there)
313 if ((cxSrc > ppdev->PointerCapabilities.MaxWidth) ||
314 (cySrc > (ppdev->PointerCapabilities.MaxHeight * 2)))
315 {
316 return(FALSE);
317 }
318
319 pjDstXor += ((ppdev->PointerCapabilities.MaxWidth + 7) / 8) *
320 ppdev->pPointerAttributes->Height;
321
322 // set the desk and mask to 0xff
323 RtlFillMemory(pjDstAnd, ppdev->pPointerAttributes->WidthInBytes *
324 ppdev->pPointerAttributes->Height, 0xFF);
325
326 // Zero the dest XOR mask
327 RtlZeroMemory(pjDstXor, ppdev->pPointerAttributes->WidthInBytes *
328 ppdev->pPointerAttributes->Height);
329
330 cxSrcBytes = (cxSrc + 7) / 8;
331
332 if ((lDeltaSrc = pso->lDelta) < 0)
333 {
334 lSrcWidthInBytes = -lDeltaSrc;
335 } else {
336 lSrcWidthInBytes = lDeltaSrc;
337 }
338
339 pjSrcAnd = (PBYTE) pso->pvBits;
340
341 // If the incoming pointer bitmap is bottomup, we'll flip it to topdown to
342 // save the miniport some work
343 if (!(pso->fjBitmap & BMF_TOPDOWN))
344 {
345 // Copy from the bottom
346 pjSrcAnd += lSrcWidthInBytes * (cySrc - 1);
347 }
348
349 // Height of just AND mask
350 cySrc = cySrc / 2;
351
352 // Point to XOR mask
353 pjSrcXor = pjSrcAnd + (cySrc * lDeltaSrc);
354
355 // Offset from end of one dest scan to start of next
356 lDeltaDst = ppdev->pPointerAttributes->WidthInBytes;
357
358 for (cy = 0; cy < cySrc; ++cy)
359 {
360 RtlCopyMemory(pjDstAnd, pjSrcAnd, cxSrcBytes);
361 RtlCopyMemory(pjDstXor, pjSrcXor, cxSrcBytes);
362
363 // Point to next source and dest scans
364 pjSrcAnd += lDeltaSrc;
365 pjSrcXor += lDeltaSrc;
366 pjDstAnd += lDeltaDst;
367 pjDstXor += lDeltaDst;
368 }
369
370 return(TRUE);
371 }
372
373 /******************************Public*Routine******************************\
374 * bCopyColorPointer
375 *
376 * Copies the mono and color masks into the buffer of maximum size
377 * handled by the miniport with any extra bits set to 0. Color translation
378 * is handled at this time. The masks are converted to topdown form if they
379 * aren't already. Returns TRUE if we can handle this pointer in hardware,
380 * FALSE if not.
381 *
382 \**************************************************************************/
383 BOOL NTAPI bCopyColorPointer(
384 PPDEV ppdev,
385 SURFOBJ *psoMask,
386 SURFOBJ *psoColor,
387 XLATEOBJ *pxlo)
388 {
389 return(FALSE);
390 }
391
392
393 /******************************Public*Routine******************************\
394 * bInitPointer
395 *
396 * Initialize the Pointer attributes.
397 *
398 \**************************************************************************/
399
400 BOOL NTAPI bInitPointer(PPDEV ppdev, DEVINFO *pdevinfo)
401 {
402 DWORD returnedDataLength;
403
404 ppdev->pPointerAttributes = (PVIDEO_POINTER_ATTRIBUTES) NULL;
405 ppdev->cjPointerAttributes = 0; // initialized in screen.c
406
407 //
408 // Ask the miniport whether it provides pointer support.
409 //
410
411 if (EngDeviceIoControl(ppdev->hDriver,
412 IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES,
413 NULL,
414 0,
415 &ppdev->PointerCapabilities,
416 sizeof(ppdev->PointerCapabilities),
417 &returnedDataLength))
418 {
419 return(FALSE);
420 }
421
422 //
423 // If neither mono nor color hardware pointer is supported, there's no
424 // hardware pointer support and we're done.
425 //
426
427 if ((!(ppdev->PointerCapabilities.Flags & VIDEO_MODE_MONO_POINTER)) &&
428 (!(ppdev->PointerCapabilities.Flags & VIDEO_MODE_COLOR_POINTER)))
429 {
430 return(TRUE);
431 }
432
433 //
434 // Note: The buffer itself is allocated after we set the
435 // mode. At that time we know the pixel depth and we can
436 // allocate the correct size for the color pointer if supported.
437 //
438
439 //
440 // Set the asynchronous support status (async means miniport is capable of
441 // drawing the Pointer at any time, with no interference with any ongoing
442 // drawing operation)
443 //
444
445 if (ppdev->PointerCapabilities.Flags & VIDEO_MODE_ASYNC_POINTER)
446 {
447 pdevinfo->flGraphicsCaps |= GCAPS_ASYNCMOVE;
448 }
449 else
450 {
451 pdevinfo->flGraphicsCaps &= ~GCAPS_ASYNCMOVE;
452 }
453
454 return(TRUE);
455 }