|
|
1.1 root 1: /******************************Module*Header*******************************\
2: * Module Name: cursor.c *
3: * *
4: * Cursor management. *
5: * *
6: * Copyright (c) 1992 Microsoft Corporation *
7: \**************************************************************************/
8:
9:
10: #include "driver.h"
11:
12:
13: VOID vShowCursor(PPDEV ppdev);
14: VOID vHideCursor(PPDEV ppdev);
15: VOID vComputePointerRect(PPDEV ppdev,RECTL *prcl);
16:
17: VOID vYankPointer(PPDEV,BOOL); // POINTER.ASM
18: VOID vDrawPointer(PPDEV,LONG,LONG,BOOL); // POINTER.ASM
19:
20: ULONG xyCreateMasks // POINTER.ASM
21: (
22: PPDEV ppdev,
23: PVOID pvMask,
24: PVOID pvColor,
25: LONG cy,
26: ULONG *pulXlate,
27: FSHORT fs
28: );
29:
30: BOOL bSetHardwarePointerShape
31: (
32: SURFOBJ *pso,
33: SURFOBJ *psoMask,
34: SURFOBJ *psoColor,
35: FLONG fl);
36:
37: BOOL bCopyInNewCursor(
38: PPDEV ppdev,
39: SURFOBJ *pso);
40:
41: /******************************Public*Routine******************************\
42: * DrvMovePointer (pso,x,y,prcl) *
43: * *
44: * Move the cursor to the specified location. *
45: * *
46: \**************************************************************************/
47:
48: VOID DrvMovePointer(SURFOBJ *pso,LONG x,LONG y,RECTL *prcl)
49: {
50: PPDEV ppdev = (PPDEV) pso->dhpdev;
51:
52: // (-1,-1) indicates that the cursor should be torn down.
53:
54: if (x == -1)
55: {
56: vHideCursor(ppdev);
57: return;
58: }
59:
60: // Note where we want it to be drawn and do it.
61:
62: ppdev->xyCursor.x = (USHORT) x;
63: ppdev->xyCursor.y = (USHORT) y;
64: vShowCursor(ppdev);
65:
66: // Return the new rectangle occupied by the pointer.
67:
68: if (prcl != (RECTL *) NULL)
69: vComputePointerRect(ppdev,prcl);
70: return;
71: }
72:
73: /******************************Public*Routine******************************\
74: * DrvSetPointerShape (pso,psoMask,psoColor,pxlo,xHot,yHot,x,y,prcl,fl) *
75: * *
76: * Set a new pointer shape. *
77: * *
78: \**************************************************************************/
79:
80: ULONG DrvSetPointerShape
81: (
82: SURFOBJ *pso,
83: SURFOBJ *psoMask,
84: SURFOBJ *psoColor,
85: XLATEOBJ *pxlo,
86: LONG xHot,
87: LONG yHot,
88: LONG x,
89: LONG y,
90: RECTL *prcl,
91: FLONG fl
92: )
93: {
94: PPDEV ppdev = (PPDEV) pso->dhpdev;
95: PDEVSURF pdsurf = (PDEVSURF) ppdev->pdsurf;
96: XYPAIR xy;
97: PVOID pvMask;
98: PVOID pvColor;
99: FSHORT fsFlags;
100: ULONG ulTmp;
101: ULONG *pulXlate = (PULONG) NULL; // Assume no color translation.
102: LONG cy;
103:
104: // Set the new cursor position
105: ppdev->xyCursor.x = (USHORT) x;
106: ppdev->xyCursor.y = (USHORT) y;
107:
108: // Set the hot spot information
109: ppdev->xyHotSpot.x = (USHORT) xHot;
110: ppdev->xyHotSpot.y = (USHORT) yHot;
111:
112: if (x == -1)
113: vHideCursor(ppdev);
114:
115: // If we have a hardware cursor, let the miniport try to realize it
116: if (ppdev->flCursor & CURSOR_HW)
117: {
118: if (bSetHardwarePointerShape(pso,psoMask,psoColor,fl))
119: {
120: // We are using the HW cursor and it is enabled.
121: // Mark out state flag and leave.
122: ppdev->flCursor |= CURSOR_HW_ACTIVE;
123: ppdev->flCursor &= ~(CURSOR_DOWN|CURSOR_ANIMATE);
124:
125: if (fl & SPS_ANIMATEUPDATE)
126: ppdev->flCursor |= CURSOR_ANIMATE;
127:
128: return(SPS_ACCEPT_NOEXCLUDE);
129: }
130: }
131:
132: // If we are not in an animation sequence, hide the pointer. Also,
133: // if we are coming from a hw pointer to a sw pointer, hide the
134: // hw pointer regardless of animation state.
135:
136: if ((!(ppdev->flCursor & CURSOR_ANIMATE)) ||
137: (ppdev->flCursor & CURSOR_HW_ACTIVE)) {
138: vHideCursor(ppdev);
139: }
140:
141: fsFlags = 0;
142:
143: if (fl & SPS_ANIMATEUPDATE) {
144: fsFlags |= PTRI_ANIMATE;
145: ppdev->flCursor |= CURSOR_ANIMATE;
146: } else {
147: ppdev->flCursor &= ~CURSOR_ANIMATE;
148:
149: // Hide the pointer again just in case we are ending an
150: // animation sequence.
151:
152: vHideCursor(ppdev);
153: }
154:
155: ppdev->flCursor &= ~CURSOR_HW_ACTIVE;
156:
157: // We can't handle software pointers on 1 R/W adapters.
158: if (pdsurf->vbtBankingType == VideoBanked1RW) {
159: goto DeclineCursor;
160: }
161:
162: // If the VGA doesn't support usable offscreen memory, we can't use our
163: // nifty cursor code, which uses offscreen memory for saving under the
164: // cursor, so we'll have to let the engine handle it.
165:
166: if (!(ppdev->fl & DRIVER_USE_OFFSCREEN)) {
167: goto DeclineCursor;
168: }
169:
170: // If the mask is too big, we just can't handle it on the VGA.
171:
172: if ((psoMask->sizlBitmap.cx > 32) || (psoMask->sizlBitmap.cy > 64)) {
173: vHideCursor(ppdev); // get the old software cursor off the screen, if
174: // there is one
175: goto DeclineCursor;
176: }
177:
178: // Since there is a mask, get its data for xyCreateMasks().
179:
180: pvMask = psoMask->pvBits;
181: cy = psoMask->sizlBitmap.cy / 2;
182: if (!(psoMask->fjBitmap & BMF_TOPDOWN))
183: fsFlags |= PTRI_INVERT;
184:
185: // There may be some color. Get the pointer or NULL and set the
186: // color cursor flag in the PDEV accordingly.
187:
188: if (psoColor == (SURFOBJ *) NULL)
189: {
190: pvColor = (PVOID) NULL;
191: ppdev->flCursor &= ~CURSOR_COLOR;
192: }
193: else
194: {
195: pvColor = psoColor->pvBits;
196: ppdev->flCursor |= CURSOR_COLOR;
197: cy = psoColor->sizlBitmap.cy;
198:
199: // flag for both pointers coming in TOP_DOWN.
200:
201: if ((psoMask->fjBitmap & BMF_TOPDOWN) &&
202: (psoColor->fjBitmap & BMF_TOPDOWN))
203: fsFlags |= 0x80;
204:
205: // flag for mask coming in TOP_DOWN, but color coming in
206: // BOTTOM_UP
207:
208: if ((psoMask->fjBitmap & BMF_TOPDOWN) &&
209: !(psoColor->fjBitmap & BMF_TOPDOWN))
210: fsFlags |= 0x40;
211:
212: // bitmaps currently may come in 2x high, so we might have to
213: // compute where the AND mask really starts in an inverted
214: // bitmap.
215:
216: if (fsFlags & PTRI_INVERT)
217: pvMask = (BYTE *)psoMask->pvScan0 + (psoMask->lDelta * (cy - 1));
218:
219: if (pxlo->flXlate & XO_TABLE)
220: pulXlate = pxlo->pulXlate;
221: }
222:
223: // Create the masks for the cursor
224:
225: ulTmp = xyCreateMasks(ppdev,pvMask,pvColor,cy,pulXlate,fsFlags);
226:
227: // It is valid for ulTmp to be zero. Some applications set the
228: // pointer shape to be blank and our pointer code optimizes this
229: // down to the smallest possible drawing area which in this case
230: // is an empty rect. But this is still a valid pointer.
231:
232: if (ulTmp == 0) {
233: xy.x = 32;
234: xy.y = 32;
235: } else
236: xy = *((XYPAIR *)&ulTmp);
237:
238: // Set up hit testing information in the PDEV
239:
240: ppdev->ptlExtent.x = xy.x;
241: ppdev->ptlExtent.y = xy.y;
242:
243: // This tells us how many aligned pels we need to exclude.
244: // If POINTER_ROUNDING_SIZE is 8, then a common extent of xy.x=16 will
245: // give cExtent=24, i.e. we always have to protect 3 bytes.
246:
247: ppdev->cExtent = (xy.x + 2 * POINTER_ROUNDING_SIZE - 2) & POINTER_MASK;
248:
249:
250: // Enable drawing functions and mark cursor as down
251:
252: ppdev->flCursor |= CURSOR_DOWN;
253:
254: // Draw the cursor.
255: if (x != -1)
256: vShowCursor(ppdev);
257:
258: // Set the new rectangle occupied by the pointer, and return the exclusion
259: // status
260:
261: vComputePointerRect(ppdev,prcl);
262: return(SPS_ACCEPT_EXCLUDE);
263:
264: //
265: // We choose not to handle this particular cursor bitmap.
266: //
267:
268: DeclineCursor:
269: return(SPS_DECLINE);
270:
271: }
272:
273: /******************************Public*Routine******************************\
274: * vComputePointerRect (ppdev,prcl) *
275: * *
276: * Computes the boundary around the pointer that GDI should avoid writing *
277: * on. *
278: * *
279: \**************************************************************************/
280:
281: VOID vComputePointerRect(PPDEV ppdev,RECTL *prcl)
282: {
283: XYPAIR xy;
284: XYPAIR xyHotSpot;
285:
286: xy = ppdev->xyCursor;
287: xyHotSpot = ppdev->xyHotSpot;
288:
289: prcl->left = (xy.x - xyHotSpot.x) & POINTER_MASK;
290: prcl->right = prcl->left + ppdev->cExtent;
291: prcl->top = xy.y - xyHotSpot.y;
292: prcl->bottom = prcl->top + ppdev->ptlExtent.y;
293: }
294:
295: /*****************************Private*Routine******************************\
296: * VOID vShowCursor(ppdev) *
297: * *
298: * Try to draw the cursor. *
299: * *
300: \**************************************************************************/
301:
302: VOID vShowCursor(PPDEV ppdev)
303: {
304: XYPAIR xy;
305: XYPAIR xyHotSpot;
306:
307: xy = ppdev->xyCursor;
308: xyHotSpot = ppdev->xyHotSpot;
309:
310: if (ppdev->flCursor & CURSOR_HW_ACTIVE)
311: {
312: DWORD returnedDataLength;
313: VIDEO_POINTER_POSITION PointerPosition;
314:
315: PointerPosition.Column = ppdev->pPointerAttributes->Column =
316: (SHORT)(xy.x - xyHotSpot.x);
317: PointerPosition.Row = ppdev->pPointerAttributes->Row =
318: (SHORT)(xy.y - xyHotSpot.y);
319:
320: //
321: // Call miniport to move pointer.
322: //
323: if (!DeviceIoControl(ppdev->hDriver,
324: IOCTL_VIDEO_SET_POINTER_POSITION,
325: &PointerPosition,
326: sizeof(VIDEO_POINTER_POSITION),
327: NULL,
328: 0,
329: &returnedDataLength,
330: NULL))
331:
332: {
333: DISPDBG((0, "VGA:vShowCursor fail IOCTL_VIDEO_SET_POINTER_POSITION\n"));
334: }
335: }
336: else
337: {
338: vDrawPointer(ppdev, (LONG) (xy.x - xyHotSpot.x),
339: (LONG) (xy.y - xyHotSpot.y),
340: ppdev->flCursor & CURSOR_COLOR);
341: }
342:
343: ppdev->flCursor &= ~CURSOR_DOWN;
344: }
345:
346: /*****************************Private*Routine******************************\
347: * VOID vHideCursor(ppdev) *
348: * *
349: * Try to hide the cursor *
350: * *
351: \**************************************************************************/
352:
353: VOID vHideCursor(PPDEV ppdev)
354: {
355: if (ppdev->flCursor & CURSOR_DOWN)
356: return;
357:
358: //
359: // if this is a hardware cursor, hide it by moving it off the
360: // screen.
361: //
362: if (ppdev->flCursor & CURSOR_HW_ACTIVE)
363: {
364: DWORD returnedDataLength;
365:
366: if (!DeviceIoControl(ppdev->hDriver,
367: IOCTL_VIDEO_DISABLE_POINTER,
368: NULL,
369: 0,
370: NULL,
371: 0,
372: &returnedDataLength,
373: NULL))
374:
375: {
376: //
377: // It should never be possible to fail.
378: //
379:
380: DISPDBG((0, "VGA vHideCursor failed IOCTL_VIDEO_DISABLE_POINTER\n"));
381: }
382: }
383: else
384: {
385: vYankPointer(ppdev, ppdev->flCursor & CURSOR_COLOR);
386: }
387:
388: ppdev->flCursor |= CURSOR_DOWN;
389: }
390:
391: /******************************Public*Routine******************************\
392: * bSetHardwarePointerShape
393: *
394: * Changes the shape of the Hardware Pointer.
395: *
396: * Returns: True if successful, False if Pointer shape can't be hardware.
397: *
398: \**************************************************************************/
399:
400: BOOL bSetHardwarePointerShape(
401: SURFOBJ *pso,
402: SURFOBJ *psoMask,
403: SURFOBJ *psoColor,
404: FLONG fl)
405: {
406: PPDEV ppdev = (PPDEV) pso->dhpdev;
407: PVIDEO_POINTER_ATTRIBUTES pPointerAttributes = ppdev->pPointerAttributes;
408: DWORD returnedDataLength;
409:
410: pPointerAttributes->Flags = 0;
411:
412: // BUGBUG only supports monochrome cursor for now
413: if (psoColor != (SURFOBJ *) NULL)
414: {
415: return(FALSE);
416: } else {
417: pPointerAttributes->Flags |= VIDEO_MODE_MONO_POINTER;
418: }
419:
420: if (fl & SPS_ANIMATESTART) {
421: pPointerAttributes->Flags |= VIDEO_MODE_ANIMATE_START;
422: } else if (fl & SPS_ANIMATEUPDATE) {
423: pPointerAttributes->Flags |= VIDEO_MODE_ANIMATE_UPDATE;
424: }
425:
426: // Copy the pixels into the buffer.
427:
428: if (!bCopyInNewCursor(ppdev, psoMask))
429: {
430: return(FALSE);
431: }
432:
433: // Initialize cursor attributes and position
434:
435: pPointerAttributes->Column = ppdev->xyCursor.x - ppdev->xyHotSpot.x;
436: pPointerAttributes->Row = ppdev->xyCursor.y - ppdev->xyHotSpot.y;
437: pPointerAttributes->Enable = 1;
438:
439:
440: if (!(ppdev->flCursor & CURSOR_HW_ACTIVE)) {
441: vHideCursor(ppdev);
442: }
443:
444:
445: // Set the new cursor shape.
446:
447: if (!DeviceIoControl(ppdev->hDriver,
448: IOCTL_VIDEO_SET_POINTER_ATTR,
449: pPointerAttributes,
450: ppdev->cjPointerAttributes,
451: NULL,
452: 0,
453: &returnedDataLength,
454: NULL)) {
455:
456: return(FALSE);
457: }
458:
459: return(TRUE);
460: }
461:
462: /******************************Public*Routine******************************\
463: * bCopyInNewCursor
464: *
465: * Copies two monochrome masks into a buffer of the maximum size handled by the
466: * miniport, with any extra bits set to 0. The masks are converted to topdown
467: * form if they aren't already. Returns TRUE if we can handle this pointer in
468: * hardware, FALSE if not.
469: *
470: \**************************************************************************/
471:
472: BOOL bCopyInNewCursor(
473: PPDEV ppdev,
474: SURFOBJ *pso)
475: {
476: ULONG cx;
477: ULONG cy;
478: PBYTE pjSrcAnd, pjSrcXor;
479: LONG lDeltaSrc, lDeltaDst;
480: LONG lSrcWidthInBytes;
481: ULONG cxSrc = pso->sizlBitmap.cx;
482: ULONG cySrc = pso->sizlBitmap.cy;
483: ULONG cxSrcBytes;
484: PVIDEO_POINTER_ATTRIBUTES pPointerAttributes = ppdev->pPointerAttributes;
485: PBYTE pjDstAnd = pPointerAttributes->Pixels;
486: PBYTE pjDstXor = pPointerAttributes->Pixels + ppdev->XorMaskStartOffset;
487:
488: // Make sure the new pointer isn't too big to handle
489: // (*2 because both masks are in there)
490: if ((cxSrc > ppdev->PointerCapabilities.MaxWidth) ||
491: (cySrc > (ppdev->PointerCapabilities.MaxHeight * 2)))
492: {
493: return(FALSE);
494: }
495:
496: // Pad the XOR mask with -1's
497: memset(pjDstXor, 0xFFFFFFFF, ppdev->pPointerAttributes->WidthInBytes *
498: ppdev->pPointerAttributes->Height);
499:
500: // Pad the AND mask with 0's
501: memset(pjDstAnd, 0, ppdev->pPointerAttributes->WidthInBytes *
502: ppdev->pPointerAttributes->Height);
503:
504: cxSrcBytes = (cxSrc + 7) / 8;
505:
506: if ((lDeltaSrc = pso->lDelta) < 0)
507: {
508: lSrcWidthInBytes = -lDeltaSrc;
509: }
510: else
511: {
512: lSrcWidthInBytes = lDeltaSrc;
513: }
514:
515: pjSrcAnd = (PBYTE) pso->pvBits;
516:
517: // If the incoming pointer bitmap is bottomup, we'll flip it to topdown to
518: // save the miniport some work
519: if (!(pso->fjBitmap & BMF_TOPDOWN))
520: {
521: // Copy from the bottom
522: pjSrcAnd += lSrcWidthInBytes * (cySrc - 1);
523: }
524:
525: // Height of just AND mask
526: cySrc = cySrc / 2;
527:
528: // Point to XOR mask
529: pjSrcXor = pjSrcAnd + (cySrc * lDeltaSrc);
530:
531: // Offset to next source scan line
532: lDeltaSrc -= cxSrcBytes;
533:
534: // Offset from end of one dest scan to start of next
535: lDeltaDst = ppdev->pPointerAttributes->WidthInBytes - cxSrcBytes;
536:
537: for (cy = 0; cy < cySrc; ++cy)
538: {
539: // Copy however many mask bytes are on this scan line
540: for (cx = 0; cx < cxSrcBytes; ++cx)
541: {
542: *pjDstAnd++ = *pjSrcAnd++;
543: *pjDstXor++ = *pjSrcXor++;
544: }
545:
546: // Point to next source and dest scans
547: pjSrcAnd += lDeltaSrc;
548: pjSrcXor += lDeltaSrc;
549: pjDstAnd += lDeltaDst;
550: pjDstXor += lDeltaDst;
551: }
552:
553: return(TRUE);
554: }
555:
556: /******************************Public*Routine******************************\
557: * bInitPointer
558: *
559: * Initialize the Cursor attributes.
560: *
561: \**************************************************************************/
562:
563: BOOL bInitPointer(PPDEV ppdev)
564: {
565: DWORD returnedDataLength;
566: ULONG MaxWidthB, MaxHeight;
567:
568: ppdev->flCursor &= ~CURSOR_HW; // assume there's no hardware pointer
569:
570: ppdev->pPointerAttributes = (PVIDEO_POINTER_ATTRIBUTES) NULL;
571:
572: // Ask the miniport whether it provides pointer support.
573: // If it fails assume there is no hardware pointer.
574:
575: if (!DeviceIoControl(ppdev->hDriver,
576: IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES,
577: NULL,
578: 0,
579: &ppdev->PointerCapabilities,
580: sizeof(ppdev->PointerCapabilities),
581: &returnedDataLength,
582: NULL))
583: {
584: // miniport does not support a hardware pointer.
585:
586: ppdev->PointerCapabilities.Flags = 0;
587: ppdev->PointerCapabilities.MaxWidth = 0;
588: ppdev->PointerCapabilities.MaxHeight = 0;
589: ppdev->PointerCapabilities.HWPtrBitmapStart = 0;
590: ppdev->PointerCapabilities.HWPtrBitmapEnd = 0;
591:
592: }
593:
594: // If neither mono nor color hardware pointer is supported, there's no
595: // hardware pointer support and we're done.
596:
597: if ((!(ppdev->PointerCapabilities.Flags & VIDEO_MODE_MONO_POINTER)) &&
598: (!(ppdev->PointerCapabilities.Flags & VIDEO_MODE_COLOR_POINTER)))
599: {
600: return(TRUE);
601: }
602:
603: // It's a hardware pointer; set up pointer attributes.
604:
605: MaxHeight = ppdev->PointerCapabilities.MaxHeight;
606:
607: if (ppdev->PointerCapabilities.Flags & VIDEO_MODE_COLOR_POINTER)
608: {
609: // If color supported, allocate space for two 4-bpp DIBs (data/mask;
610: // mask is actually 1-bpp, but it has the same width in bytes as the
611: // data for convenience)
612:
613: // Width rounded up to nearest byte multiple
614: MaxWidthB = (ppdev->PointerCapabilities.MaxWidth + 1) / 2;
615: }
616: else
617: {
618: // If color not supported, must be mono, allocate space for two 1-bpp
619: // DIBs (data/mask).
620:
621: // Width rounded up to nearest byte multiple
622: MaxWidthB = (ppdev->PointerCapabilities.MaxWidth + 7) / 8;
623: }
624:
625: ppdev->cjPointerAttributes =
626: sizeof(VIDEO_POINTER_ATTRIBUTES) +
627: ((sizeof(UCHAR) * MaxWidthB * MaxHeight) * 2);
628:
629: ppdev->pPointerAttributes = (PVIDEO_POINTER_ATTRIBUTES)
630: LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, ppdev->cjPointerAttributes);
631:
632: if (ppdev->pPointerAttributes == NULL) {
633: DISPDBG((0, "VGA bInitPointer LocalAlloc failed\n"));
634: return(FALSE);
635: }
636:
637: ppdev->XorMaskStartOffset = MaxWidthB * MaxHeight;
638: ppdev->pPointerAttributes->WidthInBytes = MaxWidthB;
639: ppdev->pPointerAttributes->Width = ppdev->PointerCapabilities.MaxWidth;
640: ppdev->pPointerAttributes->Height = MaxHeight;
641: ppdev->pPointerAttributes->Column = 0;
642: ppdev->pPointerAttributes->Row = 0;
643: ppdev->pPointerAttributes->Enable = 0;
644:
645:
646: // Set the asynchronous support status (async means miniport is capable of
647: // drawing the cursor at any time, with no interference with any ongoing
648: // drawing operation)
649:
650: if (ppdev->PointerCapabilities.Flags & VIDEO_MODE_ASYNC_POINTER)
651: {
652: ppdev->devinfo.flGraphicsCaps |= GCAPS_ASYNCMOVE;
653: }
654: else
655: {
656: ppdev->devinfo.flGraphicsCaps &= ~GCAPS_ASYNCMOVE;
657: }
658:
659: ppdev->flCursor |= CURSOR_HW;
660:
661: return(TRUE);
662:
663: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.