~ubuntu-branches/ubuntu/raring/virtualbox-ose/raring

« back to all changes in this revision

Viewing changes to src/VBox/Main/src-client/MouseImpl.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2011-01-30 23:27:25 UTC
  • mfrom: (0.3.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20110130232725-2ouajjd2ggdet0zd
Tags: 4.0.2-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Drop ubuntu-01-fix-build-gcc45.patch, fixed upstream.
* Drop ubuntu-02-as-needed.patch, added to the Debian package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: MouseImpl.cpp 35368 2010-12-30 13:38:23Z vboxsync $ */
 
2
/** @file
 
3
 * VirtualBox COM class implementation
 
4
 */
 
5
 
 
6
/*
 
7
 * Copyright (C) 2006-2008 Oracle Corporation
 
8
 *
 
9
 * This file is part of VirtualBox Open Source Edition (OSE), as
 
10
 * available from http://www.virtualbox.org. This file is free software;
 
11
 * you can redistribute it and/or modify it under the terms of the GNU
 
12
 * General Public License (GPL) as published by the Free Software
 
13
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 
14
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 
15
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 
16
 */
 
17
 
 
18
#include <iprt/cpp/utils.h>
 
19
 
 
20
#include "MouseImpl.h"
 
21
#include "DisplayImpl.h"
 
22
#include "VMMDev.h"
 
23
 
 
24
#include "AutoCaller.h"
 
25
#include "Logging.h"
 
26
 
 
27
#include <VBox/vmm/pdmdrv.h>
 
28
#include <VBox/VMMDev.h>
 
29
 
 
30
#include <iprt/asm.h>
 
31
 
 
32
/** @name Mouse device capabilities bitfield
 
33
 * @{ */
 
34
enum
 
35
{
 
36
    /** The mouse device can do relative reporting */
 
37
    MOUSE_DEVCAP_RELATIVE = 1,
 
38
    /** The mouse device can do absolute reporting */
 
39
    MOUSE_DEVCAP_ABSOLUTE = 2
 
40
};
 
41
/** @} */
 
42
 
 
43
/**
 
44
 * Mouse driver instance data.
 
45
 */
 
46
struct DRVMAINMOUSE
 
47
{
 
48
    /** Pointer to the mouse object. */
 
49
    Mouse                      *pMouse;
 
50
    /** Pointer to the driver instance structure. */
 
51
    PPDMDRVINS                  pDrvIns;
 
52
    /** Pointer to the mouse port interface of the driver/device above us. */
 
53
    PPDMIMOUSEPORT              pUpPort;
 
54
    /** Our mouse connector interface. */
 
55
    PDMIMOUSECONNECTOR          IConnector;
 
56
    /** The capabilities of this device. */
 
57
    uint32_t                    u32DevCaps;
 
58
};
 
59
 
 
60
 
 
61
// constructor / destructor
 
62
/////////////////////////////////////////////////////////////////////////////
 
63
 
 
64
Mouse::Mouse()
 
65
    : mParent(NULL)
 
66
{
 
67
}
 
68
 
 
69
Mouse::~Mouse()
 
70
{
 
71
}
 
72
 
 
73
 
 
74
HRESULT Mouse::FinalConstruct()
 
75
{
 
76
    RT_ZERO(mpDrv);
 
77
    mcLastAbsX = 0x8000;
 
78
    mcLastAbsY = 0x8000;
 
79
    mfLastButtons = 0;
 
80
    mfVMMDevGuestCaps = 0;
 
81
    return S_OK;
 
82
}
 
83
 
 
84
void Mouse::FinalRelease()
 
85
{
 
86
    uninit();
 
87
}
 
88
 
 
89
// public methods only for internal purposes
 
90
/////////////////////////////////////////////////////////////////////////////
 
91
 
 
92
/**
 
93
 * Initializes the mouse object.
 
94
 *
 
95
 * @returns COM result indicator
 
96
 * @param parent handle of our parent object
 
97
 */
 
98
HRESULT Mouse::init (Console *parent)
 
99
{
 
100
    LogFlowThisFunc(("\n"));
 
101
 
 
102
    ComAssertRet(parent, E_INVALIDARG);
 
103
 
 
104
    /* Enclose the state transition NotReady->InInit->Ready */
 
105
    AutoInitSpan autoInitSpan(this);
 
106
    AssertReturn(autoInitSpan.isOk(), E_FAIL);
 
107
 
 
108
    unconst(mParent) = parent;
 
109
 
 
110
#ifndef VBOXBFE_WITHOUT_COM
 
111
    unconst(mEventSource).createObject();
 
112
    HRESULT rc = mEventSource->init(static_cast<IMouse*>(this));
 
113
    AssertComRCReturnRC(rc);
 
114
    mMouseEvent.init(mEventSource, VBoxEventType_OnGuestMouse,
 
115
                     0, 0, 0, 0, 0);
 
116
#endif
 
117
 
 
118
    /* Confirm a successful initialization */
 
119
    autoInitSpan.setSucceeded();
 
120
 
 
121
    return S_OK;
 
122
}
 
123
 
 
124
/**
 
125
 *  Uninitializes the instance and sets the ready flag to FALSE.
 
126
 *  Called either from FinalRelease() or by the parent when it gets destroyed.
 
127
 */
 
128
void Mouse::uninit()
 
129
{
 
130
    LogFlowThisFunc(("\n"));
 
131
 
 
132
    /* Enclose the state transition Ready->InUninit->NotReady */
 
133
    AutoUninitSpan autoUninitSpan(this);
 
134
    if (autoUninitSpan.uninitDone())
 
135
        return;
 
136
 
 
137
    for (unsigned i = 0; i < MOUSE_MAX_DEVICES; ++i)
 
138
    {
 
139
        if (mpDrv[i])
 
140
            mpDrv[i]->pMouse = NULL;
 
141
        mpDrv[i] = NULL;
 
142
    }
 
143
 
 
144
#ifdef VBOXBFE_WITHOUT_COM
 
145
    mParent = NULL;
 
146
#else
 
147
    mMouseEvent.uninit();
 
148
    unconst(mEventSource).setNull();
 
149
    unconst(mParent) = NULL;
 
150
#endif
 
151
}
 
152
 
 
153
 
 
154
// IMouse properties
 
155
/////////////////////////////////////////////////////////////////////////////
 
156
 
 
157
/** Report the front-end's mouse handling capabilities to the VMM device and
 
158
 * thus to the guest.
 
159
 * @note all calls out of this object are made with no locks held! */
 
160
HRESULT Mouse::updateVMMDevMouseCaps(uint32_t fCapsAdded,
 
161
                                     uint32_t fCapsRemoved)
 
162
{
 
163
    VMMDev *pVMMDev = mParent->getVMMDev();
 
164
    if (!pVMMDev)
 
165
        return E_FAIL;  /* No assertion, as the front-ends can send events
 
166
                         * at all sorts of inconvenient times. */
 
167
    PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
 
168
    ComAssertRet(pVMMDevPort, E_FAIL);
 
169
 
 
170
    int rc = pVMMDevPort->pfnUpdateMouseCapabilities(pVMMDevPort, fCapsAdded,
 
171
                                                     fCapsRemoved);
 
172
    return RT_SUCCESS(rc) ? S_OK : E_FAIL;
 
173
}
 
174
 
 
175
/**
 
176
 * Returns whether the current setup can accept absolute mouse events, either
 
177
 * because an emulated absolute pointing device is active or because the Guest
 
178
 * Additions are.
 
179
 *
 
180
 * @returns COM status code
 
181
 * @param absoluteSupported address of result variable
 
182
 */
 
183
STDMETHODIMP Mouse::COMGETTER(AbsoluteSupported) (BOOL *absoluteSupported)
 
184
{
 
185
    if (!absoluteSupported)
 
186
        return E_POINTER;
 
187
 
 
188
    AutoCaller autoCaller(this);
 
189
    if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
190
 
 
191
    *absoluteSupported = supportsAbs();
 
192
    return S_OK;
 
193
}
 
194
 
 
195
/**
 
196
 * Returns whether the current setup can accept relative mouse events, that is,
 
197
 * whether an emulated relative pointing device is active.
 
198
 *
 
199
 * @returns COM status code
 
200
 * @param relativeSupported address of result variable
 
201
 */
 
202
STDMETHODIMP Mouse::COMGETTER(RelativeSupported) (BOOL *relativeSupported)
 
203
{
 
204
    if (!relativeSupported)
 
205
        return E_POINTER;
 
206
 
 
207
    AutoCaller autoCaller(this);
 
208
    if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
209
 
 
210
    *relativeSupported = supportsRel();
 
211
    return S_OK;
 
212
}
 
213
 
 
214
/**
 
215
 * Returns whether the guest can currently switch to drawing the mouse cursor
 
216
 * itself if it is asked to by the front-end.
 
217
 *
 
218
 * @returns COM status code
 
219
 * @param pfNeedsHostCursor address of result variable
 
220
 */
 
221
STDMETHODIMP Mouse::COMGETTER(NeedsHostCursor) (BOOL *pfNeedsHostCursor)
 
222
{
 
223
    if (!pfNeedsHostCursor)
 
224
        return E_POINTER;
 
225
 
 
226
    AutoCaller autoCaller(this);
 
227
    if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
228
 
 
229
    *pfNeedsHostCursor = guestNeedsHostCursor();
 
230
    return S_OK;
 
231
}
 
232
 
 
233
// IMouse methods
 
234
/////////////////////////////////////////////////////////////////////////////
 
235
 
 
236
/** Converts a bitfield containing information about mouse buttons currently
 
237
 * held down from the format used by the front-end to the format used by PDM
 
238
 * and the emulated pointing devices. */
 
239
static uint32_t mouseButtonsToPDM(LONG buttonState)
 
240
{
 
241
    uint32_t fButtons = 0;
 
242
    if (buttonState & MouseButtonState_LeftButton)
 
243
        fButtons |= PDMIMOUSEPORT_BUTTON_LEFT;
 
244
    if (buttonState & MouseButtonState_RightButton)
 
245
        fButtons |= PDMIMOUSEPORT_BUTTON_RIGHT;
 
246
    if (buttonState & MouseButtonState_MiddleButton)
 
247
        fButtons |= PDMIMOUSEPORT_BUTTON_MIDDLE;
 
248
    if (buttonState & MouseButtonState_XButton1)
 
249
        fButtons |= PDMIMOUSEPORT_BUTTON_X1;
 
250
    if (buttonState & MouseButtonState_XButton2)
 
251
        fButtons |= PDMIMOUSEPORT_BUTTON_X2;
 
252
    return fButtons;
 
253
}
 
254
 
 
255
#ifndef VBOXBFE_WITHOUT_COM
 
256
STDMETHODIMP Mouse::COMGETTER(EventSource)(IEventSource ** aEventSource)
 
257
{
 
258
    CheckComArgOutPointerValid(aEventSource);
 
259
 
 
260
    AutoCaller autoCaller(this);
 
261
    if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
262
 
 
263
    // no need to lock - lifetime constant
 
264
    mEventSource.queryInterfaceTo(aEventSource);
 
265
 
 
266
    return S_OK;
 
267
}
 
268
#endif
 
269
 
 
270
/**
 
271
 * Send a relative pointer event to the relative device we deem most
 
272
 * appropriate.
 
273
 *
 
274
 * @returns   COM status code
 
275
 */
 
276
HRESULT Mouse::reportRelEventToMouseDev(int32_t dx, int32_t dy, int32_t dz,
 
277
                                        int32_t dw, uint32_t fButtons)
 
278
{
 
279
    if (dx || dy || dz || dw || fButtons != mfLastButtons)
 
280
    {
 
281
        PPDMIMOUSEPORT pUpPort = NULL;
 
282
        {
 
283
            AutoReadLock aLock(this COMMA_LOCKVAL_SRC_POS);
 
284
 
 
285
            for (unsigned i = 0; !pUpPort && i < MOUSE_MAX_DEVICES; ++i)
 
286
            {
 
287
                if (mpDrv[i] && (mpDrv[i]->u32DevCaps & MOUSE_DEVCAP_RELATIVE))
 
288
                    pUpPort = mpDrv[i]->pUpPort;
 
289
            }
 
290
        }
 
291
        if (!pUpPort)
 
292
            return S_OK;
 
293
 
 
294
        int vrc = pUpPort->pfnPutEvent(pUpPort, dx, dy, dz, dw, fButtons);
 
295
 
 
296
        if (RT_FAILURE(vrc))
 
297
            return setError(VBOX_E_IPRT_ERROR,
 
298
                            tr("Could not send the mouse event to the virtual mouse (%Rrc)"),
 
299
                            vrc);
 
300
        mfLastButtons = fButtons;
 
301
    }
 
302
    return S_OK;
 
303
}
 
304
 
 
305
 
 
306
/**
 
307
 * Send an absolute pointer event to the emulated absolute device we deem most
 
308
 * appropriate.
 
309
 *
 
310
 * @returns   COM status code
 
311
 */
 
312
HRESULT Mouse::reportAbsEventToMouseDev(uint32_t mouseXAbs, uint32_t mouseYAbs,
 
313
                                        int32_t dz, int32_t dw, uint32_t fButtons)
 
314
{
 
315
    if (   mouseXAbs != mcLastAbsX || mouseYAbs != mcLastAbsY
 
316
        || dz || dw || fButtons != mfLastButtons)
 
317
    {
 
318
        PPDMIMOUSEPORT pUpPort = NULL;
 
319
        {
 
320
            AutoReadLock aLock(this COMMA_LOCKVAL_SRC_POS);
 
321
 
 
322
            for (unsigned i = 0; !pUpPort && i < MOUSE_MAX_DEVICES; ++i)
 
323
            {
 
324
                if (mpDrv[i] && (mpDrv[i]->u32DevCaps & MOUSE_DEVCAP_ABSOLUTE))
 
325
                    pUpPort = mpDrv[i]->pUpPort;
 
326
            }
 
327
        }
 
328
        if (!pUpPort)
 
329
            return S_OK;
 
330
 
 
331
        int vrc = pUpPort->pfnPutEventAbs(pUpPort, mouseXAbs, mouseYAbs, dz,
 
332
                                          dw, fButtons);
 
333
        if (RT_FAILURE(vrc))
 
334
            return setError(VBOX_E_IPRT_ERROR,
 
335
                            tr("Could not send the mouse event to the virtual mouse (%Rrc)"),
 
336
                            vrc);
 
337
        mfLastButtons = fButtons;
 
338
 
 
339
    }
 
340
    return S_OK;
 
341
}
 
342
 
 
343
 
 
344
/**
 
345
 * Send an absolute position event to the VMM device.
 
346
 * @note all calls out of this object are made with no locks held!
 
347
 *
 
348
 * @returns   COM status code
 
349
 */
 
350
HRESULT Mouse::reportAbsEventToVMMDev(uint32_t mouseXAbs, uint32_t mouseYAbs)
 
351
{
 
352
    VMMDev *pVMMDev = mParent->getVMMDev();
 
353
    ComAssertRet(pVMMDev, E_FAIL);
 
354
    PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
 
355
    ComAssertRet(pVMMDevPort, E_FAIL);
 
356
 
 
357
    if (mouseXAbs != mcLastAbsX || mouseYAbs != mcLastAbsY)
 
358
    {
 
359
        int vrc = pVMMDevPort->pfnSetAbsoluteMouse(pVMMDevPort,
 
360
                                                   mouseXAbs, mouseYAbs);
 
361
        if (RT_FAILURE(vrc))
 
362
            return setError(VBOX_E_IPRT_ERROR,
 
363
                            tr("Could not send the mouse event to the virtual mouse (%Rrc)"),
 
364
                            vrc);
 
365
    }
 
366
    return S_OK;
 
367
}
 
368
 
 
369
 
 
370
/**
 
371
 * Send an absolute pointer event to a pointing device (the VMM device if
 
372
 * possible or whatever emulated absolute device seems best to us if not).
 
373
 *
 
374
 * @returns   COM status code
 
375
 */
 
376
HRESULT Mouse::reportAbsEvent(uint32_t mouseXAbs, uint32_t mouseYAbs,
 
377
                              int32_t dz, int32_t dw, uint32_t fButtons,
 
378
                              bool fUsesVMMDevEvent)
 
379
{
 
380
    HRESULT rc;
 
381
    /** If we are using the VMMDev to report absolute position but without
 
382
     * VMMDev IRQ support then we need to send a small "jiggle" to the emulated
 
383
     * relative mouse device to alert the guest to changes. */
 
384
    LONG cJiggle = 0;
 
385
 
 
386
    if (vmmdevCanAbs())
 
387
    {
 
388
        /*
 
389
         * Send the absolute mouse position to the VMM device.
 
390
         */
 
391
        if (mouseXAbs != mcLastAbsX || mouseYAbs != mcLastAbsY)
 
392
        {
 
393
            rc = reportAbsEventToVMMDev(mouseXAbs, mouseYAbs);
 
394
            cJiggle = !fUsesVMMDevEvent;
 
395
        }
 
396
        rc = reportRelEventToMouseDev(cJiggle, 0, dz, dw, fButtons);
 
397
    }
 
398
    else
 
399
        rc = reportAbsEventToMouseDev(mouseXAbs, mouseYAbs, dz, dw, fButtons);
 
400
 
 
401
    mcLastAbsX = mouseXAbs;
 
402
    mcLastAbsY = mouseYAbs;
 
403
    return rc;
 
404
}
 
405
 
 
406
/**
 
407
 * Send a relative mouse event to the guest.
 
408
 * @note the VMMDev capability change is so that the guest knows we are sending
 
409
 *       real events over the PS/2 device and not dummy events to signal the
 
410
 *       arrival of new absolute pointer data
 
411
 *
 
412
 * @returns COM status code
 
413
 * @param dx          X movement
 
414
 * @param dy          Y movement
 
415
 * @param dz          Z movement
 
416
 * @param buttonState The mouse button state
 
417
 */
 
418
STDMETHODIMP Mouse::PutMouseEvent(LONG dx, LONG dy, LONG dz, LONG dw, LONG buttonState)
 
419
{
 
420
    HRESULT rc;
 
421
    uint32_t fButtons;
 
422
 
 
423
    AutoCaller autoCaller(this);
 
424
    if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
425
    LogRel3(("%s: dx=%d, dy=%d, dz=%d, dw=%d\n", __PRETTY_FUNCTION__,
 
426
                 dx, dy, dz, dw));
 
427
 
 
428
    fButtons = mouseButtonsToPDM(buttonState);
 
429
    /* Make sure that the guest knows that we are sending real movement
 
430
     * events to the PS/2 device and not just dummy wake-up ones. */
 
431
    updateVMMDevMouseCaps(0, VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE);
 
432
    rc = reportRelEventToMouseDev(dx, dy, dz, dw, fButtons);
 
433
 
 
434
#ifndef VBOXBFE_WITHOUT_COM
 
435
    mMouseEvent.reinit(VBoxEventType_OnGuestMouse, false, dx, dy, dz, dw, fButtons);
 
436
    mMouseEvent.fire(0);
 
437
#endif
 
438
 
 
439
    return rc;
 
440
}
 
441
 
 
442
/**
 
443
 * Convert an (X, Y) value pair in screen co-ordinates (starting from 1) to a
 
444
 * value from 0 to 0xffff.  Sets the optional validity value to false if the
 
445
 * pair is not on an active screen and to true otherwise.
 
446
 *
 
447
 * @returns   COM status value
 
448
 */
 
449
HRESULT Mouse::convertDisplayRes(LONG x, LONG y, int32_t *pcX, int32_t *pcY,
 
450
                                 bool *pfValid)
 
451
{
 
452
    AssertPtrReturn(pcX, E_POINTER);
 
453
    AssertPtrReturn(pcY, E_POINTER);
 
454
    AssertPtrNullReturn(pfValid, E_POINTER);
 
455
    Display *pDisplay = mParent->getDisplay();
 
456
    ComAssertRet(pDisplay, E_FAIL);
 
457
 
 
458
    if (pfValid)
 
459
        *pfValid = true;
 
460
    if (!(mfVMMDevGuestCaps & VMMDEV_MOUSE_NEW_PROTOCOL))
 
461
    {
 
462
        ULONG displayWidth, displayHeight;
 
463
        /* Takes the display lock */
 
464
        HRESULT rc = pDisplay->GetScreenResolution(0, &displayWidth, &displayHeight,
 
465
                                                   NULL);
 
466
        if (FAILED(rc))
 
467
            return rc;
 
468
 
 
469
        *pcX = displayWidth ? ((x - 1) * 0xFFFF) / displayWidth: 0;
 
470
        *pcY = displayHeight ? ((y - 1) * 0xFFFF) / displayHeight: 0;
 
471
    }
 
472
    else
 
473
    {
 
474
        int32_t x1, y1, x2, y2;
 
475
        /* Takes the display lock */
 
476
        pDisplay->getFramebufferDimensions(&x1, &y1, &x2, &y2);
 
477
        *pcX = x1 != x2 ? (x - 1 - x1) * 0xFFFF / (x2 - x1) : 0;
 
478
        *pcY = y1 != y2 ? (y - 1 - y1) * 0xFFFF / (y2 - y1) : 0;
 
479
        if (*pcX < 0 || *pcX > 0xFFFF || *pcY < 0 || *pcY > 0xFFFF)
 
480
            if (pfValid)
 
481
                *pfValid = false;
 
482
    }
 
483
    return S_OK;
 
484
}
 
485
 
 
486
 
 
487
/**
 
488
 * Send an absolute mouse event to the VM. This requires either VirtualBox-
 
489
 * specific drivers installed in the guest or absolute pointing device
 
490
 * emulation.
 
491
 * @note the VMMDev capability change is so that the guest knows we are sending
 
492
 *       dummy events over the PS/2 device to signal the arrival of new
 
493
 *       absolute pointer data, and not pointer real movement data
 
494
 * @note all calls out of this object are made with no locks held!
 
495
 *
 
496
 * @returns COM status code
 
497
 * @param x          X position (pixel), starting from 1
 
498
 * @param y          Y position (pixel), starting from 1
 
499
 * @param dz         Z movement
 
500
 * @param buttonState The mouse button state
 
501
 */
 
502
STDMETHODIMP Mouse::PutMouseEventAbsolute(LONG x, LONG y, LONG dz, LONG dw,
 
503
                                          LONG buttonState)
 
504
{
 
505
    AutoCaller autoCaller(this);
 
506
    if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
507
 
 
508
    LogRel3(("%s: x=%d, y=%d, dz=%d, dw=%d, buttonState=0x%x\n",
 
509
             __PRETTY_FUNCTION__, x, y, dz, dw, buttonState));
 
510
 
 
511
    int32_t mouseXAbs, mouseYAbs;
 
512
    uint32_t fButtons;
 
513
    bool fValid;
 
514
 
 
515
    /** @todo the front end should do this conversion to avoid races */
 
516
    /** @note Or maybe not... races are pretty inherent in everything done in
 
517
     *        this object and not really bad as far as I can see. */
 
518
    HRESULT rc = convertDisplayRes(x, y, &mouseXAbs, &mouseYAbs, &fValid);
 
519
    if (FAILED(rc)) return rc;
 
520
 
 
521
    /** @todo multi-monitor Windows guests expect this to be unbounded.
 
522
     * Understand the issues involved and fix for the rest. */
 
523
    /* if (mouseXAbs > 0xffff)
 
524
        mouseXAbs = mcLastAbsX;
 
525
    if (mouseYAbs > 0xffff)
 
526
        mouseYAbs = mcLastAbsY; */
 
527
 
 
528
    fButtons = mouseButtonsToPDM(buttonState);
 
529
    /* If we are doing old-style (IRQ-less) absolute reporting to the VMM
 
530
     * device then make sure the guest is aware of it, so that it knows to
 
531
     * ignore relative movement on the PS/2 device. */
 
532
    updateVMMDevMouseCaps(VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE, 0);
 
533
    if (fValid)
 
534
    {
 
535
        rc = reportAbsEvent(mouseXAbs, mouseYAbs, dz, dw, fButtons,
 
536
                            RT_BOOL(  mfVMMDevGuestCaps
 
537
                                    & VMMDEV_MOUSE_NEW_PROTOCOL));
 
538
 
 
539
#ifndef VBOXBFE_WITHOUT_COM
 
540
        mMouseEvent.reinit(VBoxEventType_OnGuestMouse, true, x, y, dz, dw,
 
541
                           fButtons);
 
542
        mMouseEvent.fire(0);
 
543
#endif
 
544
    }
 
545
 
 
546
    return rc;
 
547
}
 
548
 
 
549
// private methods
 
550
/////////////////////////////////////////////////////////////////////////////
 
551
 
 
552
 
 
553
/** Does the guest currently rely on the host to draw the mouse cursor or
 
554
 * can it switch to doing it itself in software? */
 
555
bool Mouse::guestNeedsHostCursor(void)
 
556
{
 
557
    return RT_BOOL(mfVMMDevGuestCaps & VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR);
 
558
}
 
559
 
 
560
 
 
561
/** Check what sort of reporting can be done using the devices currently
 
562
 * enabled.  Does not consider the VMM device. */
 
563
void Mouse::getDeviceCaps(bool *pfAbs, bool *pfRel)
 
564
{
 
565
    bool fAbsDev = false;
 
566
    bool fRelDev = false;
 
567
 
 
568
    AutoReadLock aLock(this COMMA_LOCKVAL_SRC_POS);
 
569
 
 
570
    for (unsigned i = 0; i < MOUSE_MAX_DEVICES; ++i)
 
571
        if (mpDrv[i])
 
572
        {
 
573
           if (mpDrv[i]->u32DevCaps & MOUSE_DEVCAP_ABSOLUTE)
 
574
               fAbsDev = true;
 
575
           if (mpDrv[i]->u32DevCaps & MOUSE_DEVCAP_RELATIVE)
 
576
               fRelDev = true;
 
577
        }
 
578
    if (pfAbs)
 
579
        *pfAbs = fAbsDev;
 
580
    if (pfRel)
 
581
        *pfRel = fRelDev;
 
582
}
 
583
 
 
584
 
 
585
/** Does the VMM device currently support absolute reporting? */
 
586
bool Mouse::vmmdevCanAbs(void)
 
587
{
 
588
    bool fRelDev;
 
589
 
 
590
    getDeviceCaps(NULL, &fRelDev);
 
591
    return    (mfVMMDevGuestCaps & VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE)
 
592
           && fRelDev;
 
593
}
 
594
 
 
595
 
 
596
/** Does the VMM device currently support absolute reporting? */
 
597
bool Mouse::deviceCanAbs(void)
 
598
{
 
599
    bool fAbsDev;
 
600
 
 
601
    getDeviceCaps(&fAbsDev, NULL);
 
602
    return fAbsDev;
 
603
}
 
604
 
 
605
 
 
606
/** Can we currently send relative events to the guest? */
 
607
bool Mouse::supportsRel(void)
 
608
{
 
609
    bool fRelDev;
 
610
 
 
611
    getDeviceCaps(NULL, &fRelDev);
 
612
    return fRelDev;
 
613
}
 
614
 
 
615
 
 
616
/** Can we currently send absolute events to the guest? */
 
617
bool Mouse::supportsAbs(void)
 
618
{
 
619
    bool fAbsDev;
 
620
 
 
621
    getDeviceCaps(&fAbsDev, NULL);
 
622
    return fAbsDev || vmmdevCanAbs();
 
623
}
 
624
 
 
625
 
 
626
/** Check what sort of reporting can be done using the devices currently
 
627
 * enabled (including the VMM device) and notify the guest and the front-end.
 
628
 */
 
629
void Mouse::sendMouseCapsNotifications(void)
 
630
{
 
631
    bool fAbsDev, fRelDev, fCanAbs, fNeedsHostCursor;
 
632
 
 
633
    {
 
634
        AutoReadLock aLock(this COMMA_LOCKVAL_SRC_POS);
 
635
 
 
636
        getDeviceCaps(&fAbsDev, &fRelDev);
 
637
        fCanAbs = supportsAbs();
 
638
        fNeedsHostCursor = guestNeedsHostCursor();
 
639
    }
 
640
    if (fAbsDev)
 
641
        updateVMMDevMouseCaps(VMMDEV_MOUSE_HOST_HAS_ABS_DEV, 0);
 
642
    else
 
643
        updateVMMDevMouseCaps(0, VMMDEV_MOUSE_HOST_HAS_ABS_DEV);
 
644
    /** @todo this call takes the Console lock in order to update the cached
 
645
     * callback data atomically.  However I can't see any sign that the cached
 
646
     * data is ever used again. */
 
647
    mParent->onMouseCapabilityChange(fCanAbs, fRelDev, fNeedsHostCursor);
 
648
}
 
649
 
 
650
 
 
651
/**
 
652
 * @interface_method_impl{PDMIMOUSECONNECTOR,pfnReportModes}
 
653
 * A virtual device is notifying us about its current state and capabilities
 
654
 */
 
655
DECLCALLBACK(void) Mouse::mouseReportModes(PPDMIMOUSECONNECTOR pInterface, bool fRel, bool fAbs)
 
656
{
 
657
    PDRVMAINMOUSE pDrv = RT_FROM_MEMBER(pInterface, DRVMAINMOUSE, IConnector);
 
658
    if (fRel)
 
659
        pDrv->u32DevCaps |= MOUSE_DEVCAP_RELATIVE;
 
660
    else
 
661
        pDrv->u32DevCaps &= ~MOUSE_DEVCAP_RELATIVE;
 
662
    if (fAbs)
 
663
        pDrv->u32DevCaps |= MOUSE_DEVCAP_ABSOLUTE;
 
664
    else
 
665
        pDrv->u32DevCaps &= ~MOUSE_DEVCAP_ABSOLUTE;
 
666
 
 
667
    pDrv->pMouse->sendMouseCapsNotifications();
 
668
}
 
669
 
 
670
 
 
671
/**
 
672
 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
 
673
 */
 
674
DECLCALLBACK(void *)  Mouse::drvQueryInterface(PPDMIBASE pInterface, const char *pszIID)
 
675
{
 
676
    PPDMDRVINS      pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
 
677
    PDRVMAINMOUSE   pDrv    = PDMINS_2_DATA(pDrvIns, PDRVMAINMOUSE);
 
678
 
 
679
    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
 
680
    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUSECONNECTOR, &pDrv->IConnector);
 
681
    return NULL;
 
682
}
 
683
 
 
684
 
 
685
/**
 
686
 * Destruct a mouse driver instance.
 
687
 *
 
688
 * @returns VBox status.
 
689
 * @param   pDrvIns     The driver instance data.
 
690
 */
 
691
DECLCALLBACK(void) Mouse::drvDestruct(PPDMDRVINS pDrvIns)
 
692
{
 
693
    PDRVMAINMOUSE pData = PDMINS_2_DATA(pDrvIns, PDRVMAINMOUSE);
 
694
    LogFlow(("Mouse::drvDestruct: iInstance=%d\n", pDrvIns->iInstance));
 
695
    PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
 
696
 
 
697
    if (pData->pMouse)
 
698
    {
 
699
        AutoWriteLock mouseLock(pData->pMouse COMMA_LOCKVAL_SRC_POS);
 
700
        for (unsigned cDev = 0; cDev < MOUSE_MAX_DEVICES; ++cDev)
 
701
            if (pData->pMouse->mpDrv[cDev] == pData)
 
702
            {
 
703
                pData->pMouse->mpDrv[cDev] = NULL;
 
704
                break;
 
705
            }
 
706
    }
 
707
}
 
708
 
 
709
 
 
710
/**
 
711
 * Construct a mouse driver instance.
 
712
 *
 
713
 * @copydoc FNPDMDRVCONSTRUCT
 
714
 */
 
715
DECLCALLBACK(int) Mouse::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
 
716
{
 
717
    PDRVMAINMOUSE pData = PDMINS_2_DATA(pDrvIns, PDRVMAINMOUSE);
 
718
    LogFlow(("drvMainMouse_Construct: iInstance=%d\n", pDrvIns->iInstance));
 
719
    PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
 
720
 
 
721
    /*
 
722
     * Validate configuration.
 
723
     */
 
724
    if (!CFGMR3AreValuesValid(pCfg, "Object\0"))
 
725
        return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
 
726
    AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
 
727
                    ("Configuration error: Not possible to attach anything to this driver!\n"),
 
728
                    VERR_PDM_DRVINS_NO_ATTACH);
 
729
 
 
730
    /*
 
731
     * IBase.
 
732
     */
 
733
    pDrvIns->IBase.pfnQueryInterface        = Mouse::drvQueryInterface;
 
734
 
 
735
    pData->IConnector.pfnReportModes        = Mouse::mouseReportModes;
 
736
 
 
737
    /*
 
738
     * Get the IMousePort interface of the above driver/device.
 
739
     */
 
740
    pData->pUpPort = (PPDMIMOUSEPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMIMOUSEPORT_IID);
 
741
    if (!pData->pUpPort)
 
742
    {
 
743
        AssertMsgFailed(("Configuration error: No mouse port interface above!\n"));
 
744
        return VERR_PDM_MISSING_INTERFACE_ABOVE;
 
745
    }
 
746
 
 
747
    /*
 
748
     * Get the Mouse object pointer and update the mpDrv member.
 
749
     */
 
750
    void *pv;
 
751
    int rc = CFGMR3QueryPtr(pCfg, "Object", &pv);
 
752
    if (RT_FAILURE(rc))
 
753
    {
 
754
        AssertMsgFailed(("Configuration error: No/bad \"Object\" value! rc=%Rrc\n", rc));
 
755
        return rc;
 
756
    }
 
757
    pData->pMouse = (Mouse *)pv;        /** @todo Check this cast! */
 
758
    unsigned cDev;
 
759
    {
 
760
        AutoReadLock mouseLock(pData->pMouse COMMA_LOCKVAL_SRC_POS);
 
761
 
 
762
        for (cDev = 0; cDev < MOUSE_MAX_DEVICES; ++cDev)
 
763
            if (!pData->pMouse->mpDrv[cDev])
 
764
            {
 
765
                pData->pMouse->mpDrv[cDev] = pData;
 
766
                break;
 
767
            }
 
768
    }
 
769
    if (cDev == MOUSE_MAX_DEVICES)
 
770
        return VERR_NO_MORE_HANDLES;
 
771
 
 
772
    return VINF_SUCCESS;
 
773
}
 
774
 
 
775
 
 
776
/**
 
777
 * Main mouse driver registration record.
 
778
 */
 
779
const PDMDRVREG Mouse::DrvReg =
 
780
{
 
781
    /* u32Version */
 
782
    PDM_DRVREG_VERSION,
 
783
    /* szName */
 
784
    "MainMouse",
 
785
    /* szRCMod */
 
786
    "",
 
787
    /* szR0Mod */
 
788
    "",
 
789
    /* pszDescription */
 
790
    "Main mouse driver (Main as in the API).",
 
791
    /* fFlags */
 
792
    PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
 
793
    /* fClass. */
 
794
    PDM_DRVREG_CLASS_MOUSE,
 
795
    /* cMaxInstances */
 
796
    ~0,
 
797
    /* cbInstance */
 
798
    sizeof(DRVMAINMOUSE),
 
799
    /* pfnConstruct */
 
800
    Mouse::drvConstruct,
 
801
    /* pfnDestruct */
 
802
    Mouse::drvDestruct,
 
803
    /* pfnRelocate */
 
804
    NULL,
 
805
    /* pfnIOCtl */
 
806
    NULL,
 
807
    /* pfnPowerOn */
 
808
    NULL,
 
809
    /* pfnReset */
 
810
    NULL,
 
811
    /* pfnSuspend */
 
812
    NULL,
 
813
    /* pfnResume */
 
814
    NULL,
 
815
    /* pfnAttach */
 
816
    NULL,
 
817
    /* pfnDetach */
 
818
    NULL,
 
819
    /* pfnPowerOff */
 
820
    NULL,
 
821
    /* pfnSoftReset */
 
822
    NULL,
 
823
    /* u32EndVersion */
 
824
    PDM_DRVREG_VERSION
 
825
};
 
826
/* vi: set tabstop=4 shiftwidth=4 expandtab: */