VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Video/disp/xpdm/VBoxDispMouse.cpp@ 38506

Last change on this file since 38506 was 38506, checked in by vboxsync, 13 years ago

Windows Additions: fix swapped coordinates for mouse pointer hotspot

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.3 KB
Line 
1/* $Id: VBoxDispMouse.cpp 38506 2011-08-23 11:46:43Z vboxsync $ */
2
3/** @file
4 * VBox XPDM Display driver, mouse pointer related functions
5 */
6
7/*
8 * Copyright (C) 2011 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#include "VBoxDisp.h"
20#include "VBoxDispMini.h"
21
22static BOOL VBoxDispFillMonoShape(PVBOXDISPDEV pDev, SURFOBJ *psoMask)
23{
24 ULONG srcMaskW, srcMaskH;
25 ULONG dstBytesPerLine;
26 ULONG x, y;
27 BYTE *pSrc, *pDst, bit;
28 PVIDEO_POINTER_ATTRIBUTES pAttrs = pDev->pointer.pAttrs;
29
30 LOGF_ENTER();
31 Assert(pAttrs);
32
33 srcMaskW = psoMask->sizlBitmap.cx;
34 srcMaskH = psoMask->sizlBitmap.cy/2; /* psoMask contains both AND and XOR masks */
35
36 /* truncate masks if we exceed size supported by miniport */
37 pAttrs->Width = min(srcMaskW, pDev->pointer.caps.MaxWidth);
38 pAttrs->Height = min(srcMaskH, pDev->pointer.caps.MaxHeight);
39 pAttrs->WidthInBytes = pAttrs->Width * 4;
40
41 /* copy AND mask */
42 pSrc = (BYTE*)psoMask->pvScan0;
43 pDst = pAttrs->Pixels;
44 dstBytesPerLine = (pAttrs->Width+7)/8;
45
46 for (y=0; y<pAttrs->Height; ++y)
47 {
48 memcpy(pDst+y*dstBytesPerLine, pSrc+y*psoMask->lDelta, dstBytesPerLine);
49 }
50
51 /* convert XOR mask to RGB0 DIB, it start in pAttrs->Pixels should be 4bytes aligned */
52 pSrc = (BYTE*)psoMask->pvScan0 + srcMaskH*psoMask->lDelta;
53 pDst = pAttrs->Pixels + RT_ALIGN_T(dstBytesPerLine*pAttrs->Height, 4, ULONG);
54 dstBytesPerLine = pAttrs->Width * 4;
55
56 for (y=0; y<pAttrs->Height; ++y)
57 {
58 for (x=0, bit=7; x<pAttrs->Width; ++x, --bit)
59 {
60 if (0xFF==bit) bit=7;
61
62 *(ULONG*)&pDst[y*dstBytesPerLine+x*4] = (pSrc[y*psoMask->lDelta+x/8] & RT_BIT(bit)) ? 0x00FFFFFF : 0;
63 }
64 }
65
66 LOGF_LEAVE();
67 return TRUE;
68}
69
70static SURFOBJ *VBoxDispConvSurfTo32BPP(PVBOXDISPDEV pDev, SURFOBJ *psoScreen, SURFOBJ *psoSrc, XLATEOBJ *pxlo, HSURF *phDstSurf)
71{
72 *phDstSurf = NULL;
73
74 if (psoSrc->iType==STYPE_BITMAP && psoSrc->iBitmapFormat==BMF_32BPP)
75 {
76 LOG(("no convertion needed"));
77 return psoSrc;
78 }
79
80 HSURF hSurfBitmap=NULL, hSurfRes=NULL;
81 SURFOBJ *psoBitmap=NULL, *psoRes=NULL;
82
83 /* Convert src surface */
84 if (psoSrc->iType!=STYPE_BITMAP || (pxlo && pxlo->flXlate!=XO_TRIVIAL))
85 {
86 LOG(("Converting color surface to bitmap"));
87
88 /* Convert unknown format surface to screen format bitmap */
89 hSurfBitmap = (HSURF) EngCreateBitmap(psoSrc->sizlBitmap, 0, psoScreen->iBitmapFormat, BMF_TOPDOWN, NULL);
90 if (!hSurfBitmap)
91 {
92 WARN(("EngCreateBitmap for tmp surface failed"));
93 return NULL;
94 }
95
96 psoBitmap = EngLockSurface(hSurfBitmap);
97 if (!psoBitmap)
98 {
99 WARN(("EngLockSurface for tmp surface failed"));
100 EngDeleteSurface(hSurfBitmap);
101 return NULL;
102 }
103
104 RECTL rclDst;
105 POINTL ptlSrc;
106
107 rclDst.left = 0;
108 rclDst.top = 0;
109 rclDst.right = psoSrc->sizlBitmap.cx;
110 rclDst.bottom = psoSrc->sizlBitmap.cy;
111
112 ptlSrc.x = 0;
113 ptlSrc.y = 0;
114
115 if (!EngCopyBits(psoBitmap, psoSrc, NULL, pxlo, &rclDst, &ptlSrc))
116 {
117 WARN(("EngCopyBits failed"));
118 EngUnlockSurface(psoBitmap);
119 EngDeleteSurface(hSurfBitmap);
120 return NULL;
121 }
122 }
123 else
124 {
125 psoBitmap = psoSrc;
126 }
127
128 /* Allocate result surface */
129 hSurfRes = (HSURF) EngCreateBitmap(psoSrc->sizlBitmap, 0, BMF_32BPP, BMF_TOPDOWN, NULL);
130 if (!hSurfRes)
131 {
132 WARN(("EngCreateBitmap for res surface failed"));
133 if (hSurfBitmap)
134 {
135 EngUnlockSurface(psoBitmap);
136 EngDeleteSurface(hSurfBitmap);
137 }
138 return NULL;
139 }
140
141 psoRes = EngLockSurface(hSurfRes);
142 if (!psoRes)
143 {
144 WARN(("EngLockSurface for res surface failed"));
145 EngDeleteSurface(hSurfRes);
146 if (hSurfBitmap)
147 {
148 EngUnlockSurface(psoBitmap);
149 EngDeleteSurface(hSurfBitmap);
150 }
151 return NULL;
152 }
153
154 /* Convert known fromats src surface to 32bpp */
155 PBYTE pSrc = (PBYTE) psoBitmap->pvScan0;
156 PBYTE pDst = (PBYTE) psoRes->pvScan0;
157 ULONG x, y;
158
159 if (psoBitmap->iBitmapFormat==BMF_8BPP && pDev->pPalette)
160 {
161 LOG(("BMF_8BPP"));
162 for (y=0; y<(ULONG)psoSrc->sizlBitmap.cy; ++y)
163 {
164 for (x=0; x<(ULONG)psoSrc->sizlBitmap.cx; ++x)
165 {
166 BYTE bSrc = pSrc[y*psoBitmap->lDelta+x*1];
167
168 pDst[y*psoRes->lDelta+x*4+0] = pDev->pPalette[bSrc].peBlue;
169 pDst[y*psoRes->lDelta+x*4+1] = pDev->pPalette[bSrc].peGreen;
170 pDst[y*psoRes->lDelta+x*4+2] = pDev->pPalette[bSrc].peRed;
171 pDst[y*psoRes->lDelta+x*4+3] = 0;
172 }
173 }
174 }
175 else if (psoBitmap->iBitmapFormat == BMF_16BPP)
176 {
177 LOG(("BMF_16BPP"));
178 for (y=0; y<(ULONG)psoSrc->sizlBitmap.cy; ++y)
179 {
180 for (x=0; x<(ULONG)psoSrc->sizlBitmap.cx; ++x)
181 {
182 USHORT usSrc = *(USHORT*)&pSrc[y*psoBitmap->lDelta+x*2];
183
184 pDst[y*psoRes->lDelta+x*4+0] = (BYTE) (usSrc<<3);
185 pDst[y*psoRes->lDelta+x*4+1] = (BYTE) ((usSrc>>5)<<2);
186 pDst[y*psoRes->lDelta+x*4+2] = (BYTE) ((usSrc>>11)<<3);
187 pDst[y*psoRes->lDelta+x*4+3] = 0;
188 }
189 }
190 }
191 else if (psoBitmap->iBitmapFormat == BMF_24BPP)
192 {
193 LOG(("BMF_24BPP"));
194 for (y=0; y<(ULONG)psoSrc->sizlBitmap.cy; ++y)
195 {
196 for (x=0; x<(ULONG)psoSrc->sizlBitmap.cx; ++x)
197 {
198 pDst[y*psoRes->lDelta+x*4+0] = pSrc[y*psoBitmap->lDelta+x*3+0];
199 pDst[y*psoRes->lDelta+x*4+1] = pSrc[y*psoBitmap->lDelta+x*3+1];
200 pDst[y*psoRes->lDelta+x*4+2] = pSrc[y*psoBitmap->lDelta+x*3+2];
201 pDst[y*psoRes->lDelta+x*4+3] = 0;
202 }
203 }
204 }
205 else if (psoBitmap->iBitmapFormat == BMF_32BPP)
206 {
207 LOG(("BMF_32BPP"));
208 memcpy(psoRes->pvBits, psoBitmap->pvBits, min(psoRes->cjBits, psoBitmap->cjBits));
209 }
210 else
211 {
212 WARN(("unsupported bpp"));
213 EngUnlockSurface(psoRes);
214 EngDeleteSurface(hSurfRes);
215 if (hSurfBitmap)
216 {
217 EngUnlockSurface(psoBitmap);
218 EngDeleteSurface(hSurfBitmap);
219 }
220 return NULL;
221 }
222
223 /* cleanup tmp surface */
224 if (hSurfBitmap)
225 {
226 EngUnlockSurface(psoBitmap);
227 EngDeleteSurface(hSurfBitmap);
228 }
229
230 *phDstSurf = hSurfRes;
231 return psoRes;
232}
233
234static BOOL VBoxDispFillColorShape(PVBOXDISPDEV pDev, SURFOBJ *psoScreen, SURFOBJ *psoMask, SURFOBJ *psoColor,
235 XLATEOBJ *pxlo, FLONG fl)
236{
237 ULONG srcMaskW, srcMaskH;
238 ULONG dstBytesPerLine;
239 ULONG x, y;
240 BYTE *pSrc, *pDst, bit;
241 PVIDEO_POINTER_ATTRIBUTES pAttrs = pDev->pointer.pAttrs;
242 SURFOBJ *pso32bpp = NULL;
243 HSURF hSurf32bpp = NULL;
244
245 LOGF_ENTER();
246 Assert(pAttrs);
247
248 srcMaskW = psoColor->sizlBitmap.cx;
249 srcMaskH = psoColor->sizlBitmap.cy;
250
251 /* truncate masks if we exceed size supported by miniport */
252 pAttrs->Width = min(srcMaskW, pDev->pointer.caps.MaxWidth);
253 pAttrs->Height = min(srcMaskH, pDev->pointer.caps.MaxHeight);
254 pAttrs->WidthInBytes = pAttrs->Width * 4;
255
256 if (fl & SPS_ALPHA)
257 {
258 LOG(("SPS_ALPHA"));
259 /* Construct AND mask from alpha color channel */
260 pSrc = (PBYTE) psoColor->pvScan0;
261 pDst = pAttrs->Pixels;
262 dstBytesPerLine = (pAttrs->Width+7)/8;
263
264 memset(pDst, 0xFF, dstBytesPerLine*pAttrs->Height);
265
266 for (y=0; y<pAttrs->Height; ++y)
267 {
268 for (x=0, bit=7; x<pAttrs->Width; ++x, --bit)
269 {
270 if (0xFF==bit) bit=7;
271
272 if (pSrc[y*psoColor->lDelta + x*4 + 3] > 0x7F)
273 {
274 pDst[y*dstBytesPerLine + x/8] &= ~RT_BIT(bit);
275 }
276 }
277 }
278
279 pso32bpp = psoColor;
280 }
281 else
282 {
283 LOG(("Surface mask"));
284 if (!psoMask)
285 {
286 WARN(("!psoMask"));
287 return FALSE;
288 }
289
290 /* copy AND mask */
291 pSrc = (BYTE*)psoMask->pvScan0;
292 pDst = pAttrs->Pixels;
293 dstBytesPerLine = (pAttrs->Width+7)/8;
294
295 for (y=0; y<pAttrs->Height; ++y)
296 {
297 memcpy(pDst+y*dstBytesPerLine, pSrc+y*psoMask->lDelta, dstBytesPerLine);
298 }
299
300 pso32bpp = VBoxDispConvSurfTo32BPP(pDev, psoScreen, psoColor, pxlo, &hSurf32bpp);
301 if (!pso32bpp)
302 {
303 WARN(("failed to convert to 32bpp"));
304 return FALSE;
305 }
306 }
307
308 Assert(pso32bpp->iType==STYPE_BITMAP && pso32bpp->iBitmapFormat==BMF_32BPP);
309
310 /* copy 32bit bitmap to XOR DIB in pAttrs->pixels, it start there should be 4bytes aligned */
311 pSrc = (PBYTE) pso32bpp->pvScan0;
312 pDst = pAttrs->Pixels + RT_ALIGN_T(dstBytesPerLine*pAttrs->Height, 4, ULONG);
313 dstBytesPerLine = pAttrs->Width * 4;
314
315 for (y=0; y<pAttrs->Height; ++y)
316 {
317 memcpy(pDst+y*dstBytesPerLine, pSrc+y*pso32bpp->lDelta, dstBytesPerLine);
318 }
319
320 /* deallocate temp surface */
321 if (hSurf32bpp)
322 {
323 EngUnlockSurface(pso32bpp);
324 EngDeleteSurface(hSurf32bpp);
325 }
326
327 LOGF_LEAVE();
328 return TRUE;
329}
330
331int VBoxDispInitPointerCaps(PVBOXDISPDEV pDev, DEVINFO *pDevInfo)
332{
333 int rc;
334
335 rc = VBoxDispMPGetPointerCaps(pDev->hDriver, &pDev->pointer.caps);
336 VBOX_WARNRC_RETRC(rc);
337
338 if (pDev->pointer.caps.Flags & VIDEO_MODE_ASYNC_POINTER)
339 {
340 pDevInfo->flGraphicsCaps |= GCAPS_ASYNCMOVE;
341 }
342
343 pDevInfo->flGraphicsCaps2 |= GCAPS2_ALPHACURSOR;
344
345 return VINF_SUCCESS;
346}
347
348
349int VBoxDispInitPointerAttrs(PVBOXDISPDEV pDev)
350{
351 DWORD bytesPerLine;
352
353 /* We have no idea what bpp would have pointer glyph DIBs,
354 * so make sure it's enough to fit largest one.
355 */
356 if (pDev->pointer.caps.Flags & VIDEO_MODE_COLOR_POINTER)
357 {
358 bytesPerLine = pDev->pointer.caps.MaxWidth*4;
359 }
360 else
361 {
362 bytesPerLine = (pDev->pointer.caps.MaxWidth + 7)/8;
363 }
364
365 /* VIDEO_POINTER_ATTRIBUTES followed by data and mask DIBs.*/
366 pDev->pointer.cbAttrs = sizeof(VIDEO_POINTER_ATTRIBUTES) + 2*(pDev->pointer.caps.MaxHeight*bytesPerLine);
367
368 pDev->pointer.pAttrs = (PVIDEO_POINTER_ATTRIBUTES) EngAllocMem(0, pDev->pointer.cbAttrs, MEM_ALLOC_TAG);
369 if (!pDev->pointer.pAttrs)
370 {
371 WARN(("can't allocate %d bytes pDev->pPointerAttrs buffer", pDev->pointer.cbAttrs));
372 return VERR_NO_MEMORY;
373 }
374
375 pDev->pointer.pAttrs->Flags = pDev->pointer.caps.Flags;
376 pDev->pointer.pAttrs->Width = pDev->pointer.caps.MaxWidth;
377 pDev->pointer.pAttrs->Height = pDev->pointer.caps.MaxHeight;
378 pDev->pointer.pAttrs->WidthInBytes = bytesPerLine;
379 pDev->pointer.pAttrs->Enable = 0;
380 pDev->pointer.pAttrs->Column = 0;
381 pDev->pointer.pAttrs->Row = 0;
382
383 return VINF_SUCCESS;
384}
385
386/*
387 * Display driver callbacks.
388 */
389
390VOID APIENTRY VBoxDispDrvMovePointer(SURFOBJ *pso, LONG x, LONG y, RECTL *prcl)
391{
392 PVBOXDISPDEV pDev = (PVBOXDISPDEV)pso->dhpdev;
393 int rc;
394 NOREF(prcl);
395 LOGF_ENTER();
396
397 /* For NT4 offset pointer position by display origin in virtual desktop */
398 x -= pDev->orgDisp.x;
399 y -= pDev->orgDisp.y;
400
401 if (-1==x) /* hide pointer */
402 {
403 rc = VBoxDispMPDisablePointer(pDev->hDriver);
404 VBOX_WARNRC(rc);
405 }
406 else
407 {
408 VIDEO_POINTER_POSITION pos;
409
410 pos.Column = (SHORT) (x - pDev->pointer.orgHotSpot.x);
411 pos.Row = (SHORT) (y - pDev->pointer.orgHotSpot.y);
412
413 rc = VBoxDispMPSetPointerPosition(pDev->hDriver, &pos);
414 VBOX_WARNRC(rc);
415 }
416
417 LOGF_LEAVE();
418 return;
419}
420
421ULONG APIENTRY
422VBoxDispDrvSetPointerShape(SURFOBJ *pso, SURFOBJ *psoMask, SURFOBJ *psoColor, XLATEOBJ *pxlo,
423 LONG xHot, LONG yHot, LONG x, LONG y, RECTL *prcl, FLONG fl)
424{
425 PVBOXDISPDEV pDev = (PVBOXDISPDEV)pso->dhpdev;
426 int rc;
427 NOREF(prcl);
428 LOGF_ENTER();
429
430 /* sanity check */
431 if (!pDev->pointer.pAttrs)
432 {
433 WARN(("pDev->pointer.pAttrs == NULL"));
434 return SPS_ERROR;
435 }
436
437 /* Check if we've been requested to make pointer transparent */
438 if (!psoMask && !(fl & SPS_ALPHA))
439 {
440 LOG(("SPS_ALPHA"));
441 rc = VBoxDispMPDisablePointer(pDev->hDriver);
442 VBOX_WARNRC(rc);
443 return SPS_ACCEPT_NOEXCLUDE;
444 }
445
446 /* Fill data and mask DIBs to pass to miniport driver */
447 LOG(("pso=%p, psoMask=%p, psoColor=%p, pxlo=%p, hot=%i,%i xy=%i,%i fl=%#x",
448 pso, psoMask, psoColor, pxlo, xHot, yHot, x, y, fl));
449 if (psoMask)
450 {
451 LOG(("psoMask.size = %d,%d", psoMask->sizlBitmap.cx, psoMask->sizlBitmap.cy));
452 }
453 if (psoColor)
454 {
455 LOG(("psoColor.size = %d,%d", psoColor->sizlBitmap.cx, psoColor->sizlBitmap.cy));
456 }
457
458 if (!psoColor) /* Monochrome pointer */
459 {
460 if (!(pDev->pointer.caps.Flags & VIDEO_MODE_MONO_POINTER)
461 || !VBoxDispFillMonoShape(pDev, psoMask))
462 {
463 rc = VBoxDispMPDisablePointer(pDev->hDriver);
464 VBOX_WARNRC(rc);
465 return SPS_DECLINE;
466 }
467 pDev->pointer.pAttrs->Flags = VIDEO_MODE_MONO_POINTER;
468 }
469 else /* Color pointer */
470 {
471 if (!(pDev->pointer.caps.Flags & VIDEO_MODE_COLOR_POINTER)
472 || !VBoxDispFillColorShape(pDev, pso, psoMask, psoColor, pxlo, fl))
473 {
474 rc = VBoxDispMPDisablePointer(pDev->hDriver);
475 VBOX_WARNRC(rc);
476 return SPS_DECLINE;
477 }
478 pDev->pointer.pAttrs->Flags = VIDEO_MODE_COLOR_POINTER;
479
480 }
481
482 /* Fill position and enable bits to pass to miniport driver.
483 * Note: pDev->pointer.pAttrs->Enable is also used to pass hotspot coordinates in it's high word
484 * to miniport driver.
485 */
486 pDev->pointer.pAttrs->Column = (SHORT) (x - xHot);
487 pDev->pointer.pAttrs->Row = (SHORT) (y - yHot);
488
489 pDev->pointer.pAttrs->Enable = VBOX_MOUSE_POINTER_SHAPE;
490 pDev->pointer.pAttrs->Enable |= (yHot & 0xFF) << 24;
491 pDev->pointer.pAttrs->Enable |= (xHot & 0xFF) << 16;
492
493 if (x!=-1)
494 {
495 pDev->pointer.pAttrs->Enable |= VBOX_MOUSE_POINTER_VISIBLE;
496 }
497
498 if (fl & SPS_ALPHA)
499 {
500 pDev->pointer.pAttrs->Enable |= VBOX_MOUSE_POINTER_ALPHA;
501 }
502
503 /* Update Flags */
504 if (fl & SPS_ANIMATESTART)
505 {
506 pDev->pointer.pAttrs->Flags |= VIDEO_MODE_ANIMATE_START;
507 }
508 else if (fl & SPS_ANIMATEUPDATE)
509 {
510 pDev->pointer.pAttrs->Flags |= VIDEO_MODE_ANIMATE_UPDATE;
511 }
512
513 if ((fl & SPS_FREQMASK) || (fl & SPS_LENGTHMASK))
514 {
515 WARN(("asked for mousetrail without GCAPS2_MOUSETRAILS"));
516 }
517
518 /* Pass attributes to miniport */
519 rc = VBoxDispMPSetPointerAttrs(pDev);
520 if (RT_FAILURE(rc))
521 {
522 VBOX_WARNRC(rc);
523 rc = VBoxDispMPDisablePointer(pDev->hDriver);
524 VBOX_WARNRC(rc);
525 return SPS_DECLINE;
526 }
527
528 pDev->pointer.orgHotSpot.x = xHot;
529 pDev->pointer.orgHotSpot.y = yHot;
530
531 /* Move pointer to requested position */
532 if (x!=-1)
533 {
534 VBoxDispDrvMovePointer(pso, x, y, NULL);
535 }
536
537 LOGF_LEAVE();
538 return SPS_ACCEPT_NOEXCLUDE;
539}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette