VirtualBox

Changeset 50265 in vbox


Ignore:
Timestamp:
Jan 29, 2014 11:12:44 AM (11 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
91898
Message:

DnD: First working implementation for Windows guest->host support; still work in progress. As for now only pure text data can be dragged over.

Location:
trunk
Files:
2 added
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/HostServices/DragAndDropSvc.h

    r49891 r50265  
    44
    55/*
    6  * Copyright (C) 2011-2013 Oracle Corporation
     6 * Copyright (C) 2011-2014 Oracle Corporation
    77 *
    88 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    6161/**
    6262 * The service functions which are callable by host.
     63 * Note: When adding new functions to this table, make sure that the actual ID
     64 *       does *not* overlap with the eGuestFn enumeration below!
    6365 */
    6466enum eHostFn
     
    8284
    8385    /* G->H */
    84     HOST_DND_GH_REQ_PENDING            = 300,
     86    /** The host asks the guest whether a DnD operation
     87     *  is in progress when the mouse leaves the guest window. */
     88    HOST_DND_GH_REQ_PENDING            = 600,
     89    /** The host informs the guest that a DnD drop operation
     90     *  has been started and that the host wants the data in
     91     *  a specific mime-type. */
    8592    HOST_DND_GH_EVT_DROPPED
    8693};
     
    8895/**
    8996 * The service functions which are called by guest.
     97 * Note: When adding new functions to this table, make sure that the actual ID
     98 *       does *not* overlap with the eGuestFn enumeration above!
    9099 */
    91100enum eGuestFn
    92101{
    93102    /**
    94      * Guest waits for a new message the host wants to process on the guest side.
    95      * This is a blocking call and can be deferred.
     103     * Guest waits for a new message the host wants to process
     104     * on the guest side. This can be a blocking call.
    96105     */
    97106    GUEST_DND_GET_NEXT_HOST_MSG        = 300,
     
    103112
    104113    /* G->H */
     114    /**
     115     * The guests acknowledges that it currently has a drag'n drop
     116     * operation in progress on the guest, which eventually could be
     117     * dragged over to the host.
     118     */
    105119    GUEST_DND_GH_ACK_PENDING           = 500,
    106120    GUEST_DND_GH_SND_DATA,
     
    416430    void     *pvData;
    417431    uint32_t  cbData;
    418     uint32_t  cbAllSize;
     432    uint32_t  cbAllSize; /** @todo Why is this transmitted every time? */
    419433} VBOXDNDCBSNDDATADATA;
    420434typedef VBOXDNDCBSNDDATADATA *PVBOXDNDCBSNDDATADATA;
  • trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.cpp

    r50179 r50265  
    229229        } while (RT_SUCCESS(rc));
    230230
     231        int rc2 = pThis->UnregisterAsDropTarget();
     232        if (RT_SUCCESS(rc))
     233            rc = rc2;
     234
    231235        OleUninitialize();
    232236    }
     
    405409                    reset();
    406410
    407                     Assert(mMode == Unknown);
    408411                    mMode = HG;
    409412
     
    464467
    465468                    rc = OnHgCancel();
    466 
    467                     reset();
    468469                    break;
    469470                }
     
    473474                    LogFlowThisFunc(("HOST_DND_GH_REQ_PENDING\n"));
    474475#ifdef VBOX_WITH_DRAG_AND_DROP_GH
    475                     Assert(   mMode == Unknown
    476                            || mMode == GH);
    477                     mMode = GH;
    478                     rc = OnGhIsDnDPending(pEvent->Event.uScreenId);
     476                    if (   mMode == Unknown
     477                        /* There can be more than one HOST_DND_GH_REQ_PENDING
     478                         * messages coming in. */
     479                        || mMode == GH)
     480                    {
     481                        mMode = GH;
     482                        rc = OnGhIsDnDPending(pEvent->Event.uScreenId);
     483                    }
     484                    else
     485                        rc = VERR_WRONG_ORDER;
    479486#else
    480487                    rc = VERR_NOT_SUPPORTED;
     
    487494                    LogFlowThisFunc(("HOST_DND_GH_EVT_DROPPED\n"));
    488495#ifdef VBOX_WITH_DRAG_AND_DROP_GH
    489                     Assert(mMode == GH);
    490                     rc = OnGhDropped(pEvent->Event.pszFormats,
    491                                      pEvent->Event.cbFormats,
    492                                      pEvent->Event.u.a.uDefAction);
    493                     mMode = Unknown;
     496                    if (mMode == GH)
     497                    {
     498                        rc = OnGhDropped(pEvent->Event.pszFormats,
     499                                         pEvent->Event.cbFormats,
     500                                         pEvent->Event.u.a.uDefAction);
     501                    }
     502                    else
     503                        rc = VERR_WRONG_ORDER;
    494504#else
    495505                    rc = VERR_NOT_SUPPORTED;
     
    585595        }
    586596        else
     597        {
    587598            rc = VINF_SUCCESS;
     599        }
    588600    }
    589601    catch (std::bad_alloc)
     
    598610int VBoxDnDWnd::UnregisterAsDropTarget(void)
    599611{
     612    LogFlowFuncEnter();
     613
    600614    if (!pDropTarget) /* No drop target? Bail out. */
    601615        return VINF_SUCCESS;
     
    606620                                  TRUE /* fLastUnlockReleases */);
    607621    if (SUCCEEDED(hr))
    608         pDropTarget->Release();
     622    {
     623        ULONG cRefs = pDropTarget->Release();
     624
     625        Assert(cRefs == 0);
     626        pDropTarget = NULL;
     627    }
    609628
    610629    int rc = SUCCEEDED(hr)
     
    652671     */
    653672    const RTCList<RTCString> lstAllowedMimeTypes = RTCList<RTCString>()
    654         /* Uri's */
     673        /* URI's */
    655674        << "text/uri-list"
    656675        /* Text */
     
    661680        << "TEXT"
    662681        << "STRING"
    663         /* OpenOffice formates */
     682        /* OpenOffice formats */
    664683        << "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\""
    665684        << "application/x-openoffice-drawing;windows_formatname=\"Drawing Format\"";
     
    855874    if (RT_SUCCESS(rc))
    856875        rc = rc2;
     876
     877    reset();
    857878
    858879    return rc;
     
    959980    if (RT_SUCCESS(rc))
    960981    {
     982        AssertPtr(pDropTarget);
     983
    961984        uint32_t uDefAction = DND_IGNORE_ACTION;
    962985        RTCString strFormat = "unknown";
    963         if (   pDropTarget
    964             && pDropTarget->HasData())
     986        if (pDropTarget->HasData())
    965987        {
    966988            uDefAction = DND_COPY_ACTION;
     
    970992             *        with \r\n. */
    971993            strFormat = "text/plain;charset=utf-8";
    972         }
    973 
    974         LogFlowFunc(("Acknowledging pDropTarget=0x%p, uDefAction=0x%x, uAllActions=0x%x, strFormat=%s\n",
    975                      pDropTarget, uDefAction, uAllActions, strFormat.c_str()));
    976         rc = VbglR3DnDGHAcknowledgePending(mClientID,
    977                                            uDefAction, uAllActions, strFormat.c_str());
     994
     995            LogFlowFunc(("Acknowledging pDropTarget=0x%p, uDefAction=0x%x, uAllActions=0x%x, strFormat=%s\n",
     996                         pDropTarget, uDefAction, uAllActions, strFormat.c_str()));
     997            rc = VbglR3DnDGHAcknowledgePending(mClientID,
     998                                               uDefAction, uAllActions, strFormat.c_str());
     999        }
    9781000    }
    9791001
     
    9851007                            uint32_t uDefAction)
    9861008{
    987     LogFlowThisFunc(("mMode=%ld, mState=%ld, cbFormats=%RU32, uDefAction=0x%x\n",
    988                      mMode, mState, cbFormats, uDefAction));
     1009    LogFlowThisFunc(("mMode=%ld, mState=%ld, pDropTarget=0x%p, cbFormats=%RU32, uDefAction=0x%x\n",
     1010                     mMode, mState, pDropTarget, cbFormats, uDefAction));
    9891011    int rc;
    9901012    if (mState == Dragging)
    9911013    {
    9921014        AssertPtr(pDropTarget);
     1015        rc = pDropTarget->WaitForDrop(30 * 1000 /* Timeout */);
     1016        if (RT_SUCCESS(rc))
     1017        {
     1018            /** @todo Respect uDefAction. */
     1019            /** @todo Do data checking / conversion based on pszFormats. */
     1020
     1021            void *pvData = pDropTarget->DataMutableRaw();
     1022            AssertPtr(pvData);
     1023            uint32_t cbData = pDropTarget->DataSize();
     1024            Assert(cbData);
     1025
     1026            rc = VbglR3DnDGHSendData(mClientID, pvData, cbData);
     1027            LogFlowFunc(("Sent pvData=0x%p, cbData=%RU32, rc=%Rrc\n",
     1028                         pvData, cbData, rc));
     1029        }
     1030
     1031        reset();
    9931032    }
    9941033    else
  • trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.h

    r50177 r50265  
    151151
    152152    static DWORD GetDropEffect(DWORD grfKeyState, DWORD dwAllowedEffects);
    153 
    154 public:
    155 
    156     const IDataObject *GetDataObject(void) { return mpDataObject; }
    157     bool HasData(void) { return mfHasDropData; }
     153    void reset(void);
     154
     155public:
     156
     157    bool HasData(void) { return RT_BOOL(mFormatEtc.cfFormat != 0); }
     158    void *DataMutableRaw(void) { return mpvData; }
     159    uint32_t DataSize(void) { return mcbData; }
     160    int WaitForDrop(RTMSINTERVAL msTimeout);
    158161
    159162protected:
     
    163166    uint32_t mClientID;
    164167    DWORD mdwCurEffect;
    165     IDataObject *mpDataObject;
    166     bool mfHasDropData;
     168    /** Copy of the data object's FORMATETC struct.
     169     *  Note: We don't keep the pointer of the
     170     *        DVTARGETDEVICE here! */
     171    FORMATETC mFormatEtc;
     172    void *mpvData;
     173    uint32_t mcbData;
     174    RTSEMEVENT hEventDrop;
    167175};
    168176
  • trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnDDropTarget.cpp

    r50177 r50265  
    3131      mClientID(UINT32_MAX),
    3232      mdwCurEffect(0),
    33       mpDataObject(NULL),
    34       mfHasDropData(false)
     33      mpvData(NULL),
     34      mcbData(0),
     35      hEventDrop(NIL_RTSEMEVENT)
    3536{
    3637    int rc = VbglR3DnDConnect(&mClientID);
     38    if (RT_SUCCESS(rc))
     39        rc = RTSemEventCreate(&hEventDrop);
    3740
    3841    LogFlowFunc(("clientID=%RU32, rc=%Rrc\n",
     
    4245VBoxDnDDropTarget::~VBoxDnDDropTarget(void)
    4346{
    44     int rc = VbglR3DnDDisconnect(mClientID);
    45 
    46     LogFlowFunc(("rc=%Rrc, mRefCount=%RI32\n", rc, mRefCount));
     47    reset();
     48
     49    int rc2 = VbglR3DnDDisconnect(mClientID);
     50    AssertRC(rc2);
     51    rc2 = RTSemEventDestroy(hEventDrop);
     52    AssertRC(rc2);
     53
     54    LogFlowFunc(("rc=%Rrc, mRefCount=%RI32\n", rc2, mRefCount));
    4755}
    4856
     
    94102    AssertPtrReturn(pdwEffect, E_INVALIDARG);
    95103
    96     LogFlowFunc(("mfHasDropData=%RTbool, pDataObject=0x%p, grfKeyState=0x%x, x=%ld, y=%ld, dwEffect=%RU32\n",
    97                  mfHasDropData, pDataObject, grfKeyState, pt.x, pt.y, *pdwEffect));
    98 
    99     FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
    100 
    101     /* We only handle CF_HDROP in an HGLOBAL medium at the moment. */
    102     HRESULT hr = pDataObject->QueryGetData(&fmtetc);
    103     mfHasDropData = hr == S_OK;
    104 
    105     if (mfHasDropData)
    106     {
     104    LogFlowFunc(("pDataObject=0x%p, grfKeyState=0x%x, x=%ld, y=%ld, dwEffect=%RU32\n",
     105                 pDataObject, grfKeyState, pt.x, pt.y, *pdwEffect));
     106
     107    reset();
     108
     109    /* Try different formats. CF_HDROP is the most common one, so start
     110     * with this. */
     111    /** @todo At the moment we only support TYMED_HGLOBAL. */
     112    FORMATETC fmtEtc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
     113    HRESULT hr = pDataObject->QueryGetData(&fmtEtc);
     114    if (hr != S_OK)
     115    {
     116        LogFlowFunc(("CF_HDROP not supported, hr=%Rhrc\n", hr));
     117
     118        /* So we couldn't retrieve the data in CF_HDROP format; try with
     119         * CF_TEXT format now. Rest stays the same. */
     120        fmtEtc.cfFormat = CF_TEXT;
     121        hr = pDataObject->QueryGetData(&fmtEtc);
     122        if (hr != S_OK)
     123        {
     124            LogFlowFunc(("CF_TEXT not supported, hr=%Rhrc\n", hr));
     125            fmtEtc.cfFormat = 0; /* Mark it to not supported. */
     126        }
     127    }
     128
     129    /* Did we find a format that we support? */
     130    if (fmtEtc.cfFormat)
     131    {
     132        LogFlowFunc(("Found supported format %RI16\n", fmtEtc.cfFormat));
     133
     134        /* Make a copy of the FORMATETC structure so that we later can
     135         * use this for comparrison and stuff. */
     136        /** Note: The DVTARGETDEVICE member only is a shallow copy! */
     137        memcpy(&mFormatEtc, &fmtEtc, sizeof(FORMATETC));
     138
    107139        /* Which drop effect we're going to use? */
    108140        /* Note: pt is not used since we don't need to differentiate within our
     
    114146        /* No or incompatible data -- so no drop effect required. */
    115147        *pdwEffect = DROPEFFECT_NONE;
    116     }
    117 
    118     LogFlowFunc(("Returning mfHasDropData=%RTbool, pdwEffect=%ld, hr=%Rhrc\n",
    119                  mfHasDropData, *pdwEffect, hr));
     148
     149        switch (hr)
     150        {
     151            case ERROR_INVALID_FUNCTION:
     152            {
     153                LogRel(("DnD: Drag'n drop format is not supported by VBoxTray\n"));
     154
     155                /* Enumerate supported source formats. This shouldn't happen too often
     156                 * on day to day use, but still keep it in here. */
     157                IEnumFORMATETC *pEnumFormats;
     158                HRESULT hr2 = pDataObject->EnumFormatEtc(DATADIR_GET, &pEnumFormats);
     159                if (SUCCEEDED(hr2))
     160                {
     161                    LogRel(("DnD: The following formats were offered to us:\n"));
     162
     163                    FORMATETC curFormatEtc;
     164                    while (pEnumFormats->Next(1, &curFormatEtc,
     165                                              NULL /* pceltFetched */) == S_OK)
     166                        {
     167                        WCHAR wszCfName[128]; /* 128 chars should be enough, rest will be truncated. */
     168                        hr2 = GetClipboardFormatNameW(curFormatEtc.cfFormat, wszCfName,
     169                                                      sizeof(wszCfName) / sizeof(WCHAR));
     170                        LogRel(("\tcfFormat=%RI16, tyMed=%RI32, dwAspect=%RI32, strCustomName=%ls, hr=%Rhrc\n",
     171                                curFormatEtc.cfFormat,
     172                                curFormatEtc.tymed,
     173                                curFormatEtc.dwAspect,
     174                                wszCfName, hr2));
     175                    }
     176
     177                    pEnumFormats->Release();
     178                }
     179
     180                break;
     181            }
     182
     183            default:
     184                break;
     185        }
     186    }
     187
     188    LogFlowFunc(("Returning cfFormat=%RI16, pdwEffect=%ld, hr=%Rhrc\n",
     189                 fmtEtc.cfFormat, *pdwEffect, hr));
    120190    return hr;
    121191}
     
    126196
    127197#ifdef DEBUG_andy
    128     LogFlowFunc(("mfHasDropData=%RTbool, grfKeyState=0x%x, x=%ld, y=%ld\n",
    129                  mfHasDropData, grfKeyState, pt.x, pt.y));
     198    LogFlowFunc(("cfFormat=%RI16, grfKeyState=0x%x, x=%ld, y=%ld\n",
     199                 mFormatEtc.cfFormat, grfKeyState, pt.x, pt.y));
    130200#endif
    131201
    132     if (mfHasDropData)
     202    if (mFormatEtc.cfFormat)
    133203    {
    134204        /* Note: pt is not used since we don't need to differentiate within our
     
    150220{
    151221#ifdef DEBUG_andy
    152     LogFlowFunc(("mfHasDropData=%RTbool\n", mfHasDropData));
     222    LogFlowFunc(("cfFormat=%RI16\n", mFormatEtc.cfFormat));
    153223#endif
    154224
    155     mpWndParent->hide();
     225    if (mpWndParent)
     226        mpWndParent->hide();
    156227
    157228    return S_OK;
     
    165236
    166237#ifdef DEBUG
    167     LogFlowFunc(("mfHasDropData=%RTbool, pDataObject=0x%p, grfKeyState=0x%x, x=%ld, y=%ld\n",
    168                  mfHasDropData, pDataObject, grfKeyState, pt.x, pt.y));
     238    LogFlowFunc(("mFormatEtc.cfFormat=%RI16, pDataObject=0x%p, grfKeyState=0x%x, x=%ld, y=%ld\n",
     239                 mFormatEtc.cfFormat, pDataObject, grfKeyState, pt.x, pt.y));
    169240#endif
     241    HRESULT hr = S_OK;
     242
    170243    bool fCanDrop = false;
    171     if (mfHasDropData)
    172     {
    173         FORMATETC fmtEtc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
     244    if (mFormatEtc.cfFormat) /* Did we get a supported format yet? */
     245    {
     246        /* Make sure the data object's data format is still the same
     247         * as we got it in DragEnter(). */
     248        hr = pDataObject->QueryGetData(&mFormatEtc);
     249        AssertMsg(SUCCEEDED(hr),
     250                  ("Data format changed between DragEnter() and Drop(), cfFormat=%RI16, hr=%Rhrc\n",
     251                  mFormatEtc.cfFormat, hr));
     252    }
     253
     254    if (SUCCEEDED(hr))
     255    {
    174256        STGMEDIUM stgMed;
    175 
    176         AssertPtr(pDataObject);
    177         if (   (pDataObject->QueryGetData(&fmtEtc)     == S_OK)
    178             && (pDataObject->GetData(&fmtEtc, &stgMed) == S_OK))
     257        hr = pDataObject->GetData(&mFormatEtc, &stgMed);
     258        if (SUCCEEDED(hr))
    179259        {
    180             PVOID pvData = GlobalLock(stgMed.hGlobal);
    181 #ifdef DEBUG
    182             if (fmtEtc.cfFormat == CF_TEXT)
    183                 LogFlowFunc(("pvData=%s\n", (char*)pvData));
    184 #endif
    185             GlobalUnlock(stgMed.hGlobal);
     260            /*
     261             * First stage: Prepare the access to the storage medium.
     262             *              For now we only support HGLOBAL stuff.
     263             */
     264            PVOID pvData = NULL; /** @todo Put this in an own union? */
     265
     266            switch (mFormatEtc.tymed)
     267            {
     268                case TYMED_HGLOBAL:
     269                    pvData = GlobalLock(stgMed.hGlobal);
     270                    if (!pvData)
     271                    {
     272                        LogFlowFunc(("Locking HGLOBAL storage failed with %Rrc\n",
     273                                     RTErrConvertFromWin32(GetLastError())));
     274                        hr = ERROR_INVALID_HANDLE;
     275                    }
     276                    break;
     277
     278                default:
     279                    AssertMsgFailed(("Storage medium type %RI32 supported\n",
     280                                     mFormatEtc.tymed));
     281                    hr = ERROR_NOT_SUPPORTED;
     282                    break;
     283            }
     284
     285            if (SUCCEEDED(hr))
     286            {
     287                /* Second stage: Do the actual copying of the data object's data,
     288                                 based on the storage medium type. */
     289                switch (mFormatEtc.cfFormat)
     290                {
     291                    case CF_TEXT:
     292                    {
     293                        LogFlowFunc(("pvData=%s\n", (char*)pvData));
     294
     295                        uint32_t cbSize = strlen((char*)pvData); /** @todo Evil hack, fix this! */
     296                        mpvData = RTMemDup(pvData, cbSize);
     297                        mcbData = cbSize;
     298                        break;
     299                    }
     300
     301                    case CF_HDROP:
     302                        break;
     303
     304                    default:
     305                        AssertMsgFailed(("Format of type %RI16 supported\n",
     306                                         mFormatEtc.cfFormat));
     307                        hr = ERROR_NOT_SUPPORTED;
     308                        break;
     309                }
     310            }
     311
     312            /*
     313             * Third stage: Release access to the storage medium again.
     314             */
     315            switch (mFormatEtc.tymed)
     316            {
     317                case TYMED_HGLOBAL:
     318                    GlobalUnlock(stgMed.hGlobal);
     319                    break;
     320
     321                default:
     322                    AssertMsgFailed(("Storage medium type %RI32 supported\n",
     323                                     mFormatEtc.tymed));
     324                    hr = ERROR_NOT_SUPPORTED;
     325                    break;
     326            }
    186327
    187328            /* Release storage medium again. */
    188329            ReleaseStgMedium(&stgMed);
    189330
    190             fCanDrop = true;
     331            if (SUCCEEDED(hr))
     332            {
     333                RTSemEventSignal(hEventDrop);
     334                fCanDrop = true;
     335            }
    191336        }
    192337    }
     
    201346        *pdwEffect = DROPEFFECT_NONE;
    202347
    203     LogFlowFunc(("Returning with mfHasDropData=%RTbool, fCanDrop=%RTbool, *pdwEffect=%RI32\n",
    204                  mfHasDropData, fCanDrop, *pdwEffect));
    205     return S_OK;
     348    if (mpWndParent)
     349        mpWndParent->hide();
     350
     351    LogFlowFunc(("Returning with mFormatEtc.cfFormat=%RI16, fCanDrop=%RTbool, *pdwEffect=%RI32\n",
     352                 mFormatEtc.cfFormat, fCanDrop, *pdwEffect));
     353    return hr;
    206354}
    207355
     
    235383}
    236384
     385void VBoxDnDDropTarget::reset(void)
     386{
     387    LogFlowFuncEnter();
     388
     389    if (mpvData)
     390    {
     391        RTMemFree(mpvData);
     392        mpvData = NULL;
     393    }
     394
     395    mcbData = 0;
     396    RT_ZERO(mFormatEtc);
     397}
     398
     399int VBoxDnDDropTarget::WaitForDrop(RTMSINTERVAL msTimeout)
     400{
     401    LogFlowFunc(("msTimeout=%RU32\n", msTimeout));
     402    int rc = RTSemEventWait(hEventDrop, msTimeout);
     403    LogFlowFuncLeaveRC(rc);
     404    return rc;
     405}
     406
  • trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDragAndDrop.cpp

    r49930 r50265  
    882882                break;
    883883            }
    884 #ifdef VBOX_WITH_DRAG_AND_DROP_GH
    885884            case DragAndDropSvc::HOST_DND_GH_REQ_PENDING:
    886885            {
     
    905904                break;
    906905            }
    907 #endif /* VBOX_WITH_DRAG_AND_DROP_GH */
    908906            default:
    909                 AssertMsgFailedReturn(("Message %u isn't expected in this context", uMsg),
    910                                       VERR_INVALID_PARAMETER);
     907                rc = VERR_NOT_SUPPORTED;
    911908                break;
    912909        }
     
    944941    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_REQ_DATA;
    945942    Msg.hdr.cParms      = 1;
     943    /* Initialize parameter */
     944    Msg.pFormat.SetPtr((void*)pcszFormat, (uint32_t)strlen(pcszFormat) + 1);
    946945    /* Do request */
    947     Msg.pFormat.SetPtr((void*)pcszFormat, (uint32_t)strlen(pcszFormat) + 1);
    948946    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
    949947    if (RT_SUCCESS(rc))
     
    968966    Msg.uDefAction.SetUInt32(uDefAction);
    969967    Msg.uAllActions.SetUInt32(uAllActions);
    970     Msg.pFormat.SetPtr((void*)pcszFormat, static_cast<uint32_t>(strlen(pcszFormat) + 1));
     968    Msg.pFormat.SetPtr((void*)pcszFormat, (uint32_t)strlen(pcszFormat) + 1);
    971969    /* Do request */
    972970    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     
    982980    AssertReturn(cbData,    VERR_INVALID_PARAMETER);
    983981
    984     /* Todo: URI support. Currently only data is send over to the host. For URI
    985      * support basically the same as in the H->G case (see
    986      * HostServices/DragAndDrop/dndmanager.h/cpp) has to be done:
    987      * 1. Parse the urilist
    988      * 2. Recursively send "create dir" and "transfer file" msg to the host
    989      * 3. Patch the urilist by removing all base dirnames
    990      * 4. On the host all needs to received and the urilist patched afterwards
    991      *    to point to the new location
     982    /** @todo Add URI support. Currently only data is send over to the host. For URI
     983     *        support basically the same as in the H->G case (see
     984     *        HostServices/DragAndDrop/dndmanager.h/cpp) has to be done:
     985     *        1. Parse the urilist
     986     *        2. Recursively send "create dir" and "transfer file" msg to the host
     987     *        3. Patch the urilist by removing all base dirnames
     988     *        4. On the host all needs to received and the urilist patched afterwards
     989     *           to point to the new location
    992990     */
    993991
     
    999997    Msg.hdr.cParms      = 2;
    1000998    Msg.uSize.SetUInt32(cbData);
     999
    10011000    int rc          = VINF_SUCCESS;
    1002     uint32_t cbMax  = _1M;
    1003     uint32_t cbSend = 0;
    1004     while(cbSend < cbData)
     1001    uint32_t cbMax  = _1M; /** @todo Remove 1 MB limit. */
     1002    uint32_t cbSent = 0;
     1003
     1004    while (cbSent < cbData)
    10051005    {
    10061006        /* Initialize parameter */
    1007         uint32_t cbToSend = RT_MIN(cbData - cbSend, cbMax);
    1008         Msg.pData.SetPtr(static_cast<uint8_t*>(pvData) + cbSend, cbToSend);
     1007        uint32_t cbToSend = RT_MIN(cbData - cbSent, cbMax);
     1008        Msg.pData.SetPtr(static_cast<uint8_t*>(pvData) + cbSent, cbToSend);
    10091009        /* Do request */
    10101010        rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     
    10181018        else
    10191019            break;
    1020         cbSend += cbToSend;
     1020        cbSent += cbToSend;
    10211021//        RTThreadSleep(500);
    10221022    }
  • trunk/src/VBox/Additions/x11/VBoxClient/draganddrop.cpp

    r49891 r50265  
    498498        XDestroyWindow(m_pDisplay, m_wndProxy);
    499499
    500     if (m_uClientID) 
     500    if (m_uClientID)
    501501    {
    502502        VbglR3DnDDisconnect(m_uClientID);
     
    16131613
    16141614        m_pCurDnD = new DragInstance(m_pDisplay, this);
    1615         if (!m_pCurDnD) 
     1615        if (!m_pCurDnD)
    16161616        {
    16171617            rc = VERR_NO_MEMORY;
     
    18291829    }
    18301830
     1831    /* Number of invalid messages skipped in a row. */
     1832    int cMsgSkippedInvalid = 0;
     1833
    18311834    do
    18321835    {
     
    18371840        if (RT_SUCCESS(rc))
    18381841        {
     1842            cMsgSkippedInvalid = 0; /* Reset skipped messages count. */
     1843
    18391844            pThis->m_eventQueue.append(e);
    18401845            rc = RTSemEventSignal(pThis->m_hEventSem);
     
    18421847                return rc;
    18431848        }
     1849        else
     1850        {
     1851            /* Old(er) hosts either are broken regarding DnD support or otherwise
     1852             * don't support the stuff we do on the guest side, so make sure we
     1853             * don't process invalid messages forever. */
     1854            if (rc == VERR_INVALID_PARAMETER)
     1855                cMsgSkippedInvalid++;
     1856            if (cMsgSkippedInvalid > 3)
     1857            {
     1858                LogFlowFunc(("Too many invalid/skipped messages from host, exiting ...\n"));
     1859                break;
     1860            }
     1861        }
     1862
    18441863    } while (!ASMAtomicReadBool(&pThis->m_fSrvStopping));
    18451864
  • trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk

    r50191 r50265  
    55
    66#
    7 # Copyright (C) 2006-2013 Oracle Corporation
     7# Copyright (C) 2006-2014 Oracle Corporation
    88#
    99# This file is part of VirtualBox Open Source Edition (OSE), as
     
    176176        ./src/net
    177177endif
    178        
     178
    179179VirtualBox_INCS = \
    180180        $(VBOX_GUI_INC_DIRS) \
     
    390390        src/widgets/VBoxOSTypeSelectorButton.h \
    391391        src/widgets/UINameAndSystemEditor.h \
    392     src/widgets/UIWarningPane.h \
     392        src/widgets/UIWarningPane.h \
    393393        src/widgets/UIFilmContainer.h \
    394394        src/widgets/graphics/UIGraphicsButton.h \
     
    433433
    434434ifdef VBOX_GUI_WITH_NETWORK_MANAGER
    435 VirtualBox_QT_MOCHDRS += \
     435 VirtualBox_QT_MOCHDRS += \
    436436        src/net/UINetworkManager.h \
    437437        src/net/UINetworkManagerDialog.h \
     
    448448        src/settings/global/UIGlobalSettingsProxy.h \
    449449        src/settings/global/UIGlobalSettingsUpdate.h
     450endif
     451
     452ifdef VBOX_WITH_DRAG_AND_DROP
     453 ifdef VBOX_WITH_DRAG_AND_DROP_GH
     454  VirtualBox_QT_MOCHDRS += \
     455        src/runtime/UIDnDMIMEData.h
     456 endif
    450457endif
    451458
     
    477484
    478485ifdef VBOX_GUI_WITH_NETWORK_MANAGER
    479 VirtualBox_QT_MOCSRCS += \
     486 VirtualBox_QT_MOCSRCS += \
    480487        src/net/UINetworkReply.cpp \
    481488        src/net/UIUpdateManager.cpp
     489endif
     490
     491ifdef VBOX_WITH_DRAG_AND_DROP
     492 ifdef VBOX_WITH_DRAG_AND_DROP_GH
     493  VirtualBox_QT_MOCSRCS += \
     494        src/runtime/UIDnDMIMEData.cpp
     495 endif
    482496endif
    483497
     
    763777 VirtualBox_QT_MOCSRCS += \
    764778        src/runtime/UIDnDHandler.cpp
     779 ifdef VBOX_WITH_DRAG_AND_DROP_GH
     780  VirtualBox_SOURCES += \
     781        src/runtime/UIDnDMIMEData.cpp
     782  VirtualBox_QT_MOCSRCS += \
     783        src/runtime/UIDnDMIMEData.cpp
     784 endif
    765785endif
    766786
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDHandler.cpp

    r49891 r50265  
    77
    88/*
    9  * Copyright (C) 2011-2013 Oracle Corporation
     9 * Copyright (C) 2011-2014 Oracle Corporation
    1010 *
    1111 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2121#include <QApplication>
    2222#include <QKeyEvent>
    23 #include <QMimeData>
    2423#include <QStringList>
    2524#include <QTimer>
     
    3332/* GUI includes: */
    3433#include "UIDnDHandler.h"
     34#ifdef VBOX_WITH_DRAG_AND_DROP_GH
     35# include "UIDnDMIMEData.h"
     36#endif
    3537#include "UIMessageCenter.h"
    3638
     
    4042#include "CGuest.h"
    4143
    42 UIDnDHandler *UIDnDHandler::m_pInstance = 0;
    43 
    44 UIDnDHandler::UIDnDHandler()
     44UIDnDHandler *UIDnDHandler::m_pInstance = NULL;
     45
     46UIDnDHandler::UIDnDHandler(void)
    4547{
    4648}
     
    5052 */
    5153
    52 Qt::DropAction UIDnDHandler::dragHGEnter(CGuest &guest, ulong screenId, int x, int y, Qt::DropAction proposedAction, Qt::DropActions possibleActions, const QMimeData *pMimeData, QWidget * /* pParent = 0 */)
     54Qt::DropAction UIDnDHandler::dragHGEnter(CGuest &guest, ulong screenId, int x, int y,
     55                                         Qt::DropAction proposedAction, Qt::DropActions possibleActions,
     56                                         const QMimeData *pMimeData, QWidget * /* pParent = NULL */)
    5357{
    5458    LogFlowFunc(("screenId=%RU32, x=%d, y=%d, action=%ld\n",
     
    6670}
    6771
    68 Qt::DropAction UIDnDHandler::dragHGMove(CGuest &guest, ulong screenId, int x, int y, Qt::DropAction proposedAction, Qt::DropActions possibleActions, const QMimeData *pMimeData, QWidget * /* pParent = 0 */)
     72Qt::DropAction UIDnDHandler::dragHGMove(CGuest &guest, ulong screenId, int x, int y,
     73                                        Qt::DropAction proposedAction, Qt::DropActions possibleActions,
     74                                        const QMimeData *pMimeData, QWidget * /* pParent = NULL */)
    6975{
    7076#ifdef DEBUG_andy
     
    8591}
    8692
    87 Qt::DropAction UIDnDHandler::dragHGDrop(CGuest &guest, ulong screenId, int x, int y, Qt::DropAction proposedAction, Qt::DropActions possibleActions, const QMimeData *pMimeData, QWidget *pParent /* = 0 */)
     93Qt::DropAction UIDnDHandler::dragHGDrop(CGuest &guest, ulong screenId, int x, int y,
     94                                        Qt::DropAction proposedAction, Qt::DropActions possibleActions,
     95                                        const QMimeData *pMimeData, QWidget *pParent /* = NULL */)
    8896{
    8997    LogFlowFunc(("screenId=%RU32, x=%d, y=%d, action=%ld\n",
     
    132140}
    133141
    134 void UIDnDHandler::dragHGLeave(CGuest &guest, ulong screenId, QWidget * /* pParent = 0 */)
     142void UIDnDHandler::dragHGLeave(CGuest &guest, ulong screenId, QWidget * /* pParent = NULL */)
    135143{
    136144    LogFlowFunc(("screenId=%RU32\n", screenId));
     
    138146}
    139147
    140 /*
    141  * Guest -> Host
    142  */
    143 
    144 class UIDnDMimeData: public QMimeData
    145 {
    146     Q_OBJECT;
    147 
    148     enum State
    149     {
    150         Dragging,
    151         Dropped,
    152         Finished,
    153         Canceled
    154     };
    155 
    156 public:
    157     UIDnDMimeData(CSession &session, QStringList formats, Qt::DropAction defAction, Qt::DropActions actions, QWidget *pParent)
    158       : m_pParent(pParent)
    159       , m_session(session)
    160       , m_formats(formats)
    161       , m_defAction(defAction)
    162       , m_actions(actions)
    163       , m_fState(Dragging)
    164     {
    165         /*
    166          * This is unbelievable hacky, but I didn't find another way. Stupid
    167          * Qt QDrag interface is so less verbose, that we in principle know
    168          * nothing about what happens when the user drag something around. It
    169          * is possible that the target request data (s. retrieveData) while the
    170          * mouse button is still pressed. This isn't something we can support,
    171          * cause it would mean transferring the data from the guest while the
    172          * mouse is still moving (thing of a 2GB file ...). So the idea is to
    173          * detect the mouse release event and only after this happened, allow
    174          * data to be retrieved. Unfortunately the QDrag object eats all events
    175          * while a drag is going on (see QDragManager in the Qt src's). So what
    176          * we do, is installing an event filter after the QDrag::exec is called
    177          * to be last in the event filter queue and therefore called before the
    178          * one installed by the QDrag object.
    179          *
    180          ** @todo: Test this on all supported platforms (X11 works).
    181          */
    182         QTimer::singleShot(0, this, SLOT(sltInstallEventFilter()));
    183     }
    184 
    185     virtual QStringList formats() const { return m_formats; }
    186     virtual bool hasFormat(const QString &mimeType) const { return m_formats.contains(mimeType); }
    187 
    188 public slots:
    189     void sltActionChanged(Qt::DropAction action) { m_defAction = action; }
    190 
    191 protected:
    192     virtual QVariant retrieveData(const QString &mimeType, QVariant::Type type) const
    193     {
    194         /* Mouse button released? */
    195         if (m_fState != Dropped)
    196             return m_data;
    197 
    198         /* Supported types. See below in the switch statement. */
    199         if (!(   type == QVariant::String
    200               || type == QVariant::ByteArray))
    201             return QVariant();
    202 
    203         CGuest guest = m_session.GetConsole().GetGuest();
    204         /* No, start getting the data from the guest. First inform the guest we
    205          * want the data in the specified mime-type. */
    206         CProgress progress = guest.DragGHDropped(mimeType, UIDnDHandler::toVBoxDnDAction(m_defAction));
    207         if (guest.isOk())
    208         {
    209             msgCenter().showModalProgressDialog(progress, tr("Dropping data ..."), ":/progress_dnd_gh_90px.png", m_pParent);
    210             if (!progress.GetCanceled())
    211             {
    212                 if (progress.isOk() && progress.GetResultCode() == 0)
    213                 {
    214                     /* After the data is successfully arrived from the guest, we query it from Main. */
    215                     QVector<uint8_t> data = guest.DragGHGetData();
    216                     if (!data.isEmpty())
    217                     {
    218                         /* Todo: not sure what to add here more: needs more testing. */
    219                         switch (type)
    220                         {
    221                             case QVariant::String:
    222                             {
    223                                 m_data = QVariant(QString(reinterpret_cast<const char*>(data.data())));
    224                                 break;
    225                             }
    226                             case QVariant::ByteArray:
    227                             {
    228                                 QByteArray ba(reinterpret_cast<const char*>(data.constData()), data.size());
    229                                 m_data = QVariant(ba);
    230                                 break;
    231                             }
    232                             default: break;
    233                         }
    234                     }
    235                     m_fState = Finished;
    236                 }
    237                 else
    238                     msgCenter().cannotDropData(progress, m_pParent);
    239             }
    240             else
    241                 m_fState = Canceled;
    242         }
    243         else
    244             msgCenter().cannotDropData(guest, m_pParent);
    245         return m_data;
    246     }
    247 
    248     bool eventFilter(QObject * /* pObject */, QEvent *pEvent)
    249     {
    250         switch (pEvent->type())
    251         {
    252             case QEvent::MouseButtonRelease: m_fState = Dropped; break;
    253             case QEvent::KeyPress:
    254             {
    255                 if (static_cast<QKeyEvent*>(pEvent)->key() == Qt::Key_Escape)
    256                     m_fState = Canceled;
    257                 break;
    258             }
    259         }
    260 
    261         /* Propagate the event further. */
    262         return false;
    263     }
    264 
    265 private slots:
    266     void sltInstallEventFilter() { qApp->installEventFilter(this); }
    267 
    268 private:
    269     /* Private members. */
    270     QWidget          *m_pParent;
    271     CSession          m_session;
    272     QStringList       m_formats;
    273     Qt::DropAction    m_defAction;
    274     Qt::DropActions   m_actions;
    275     mutable State     m_fState;
    276     mutable QVariant  m_data;
    277 };
    278 
    279 void UIDnDHandler::dragGHPending(CSession &session, ulong screenId, QWidget *pParent /* = 0 */)
    280 {
     148int UIDnDHandler::dragGHPending(CSession &session, ulong screenId, QWidget *pParent /* = NULL */)
     149{
     150    int rc;
     151#ifdef VBOX_WITH_DRAG_AND_DROP_GH
    281152    /*
    282153     * How this works: Host is asking the guest if there is any DnD
     
    289160     */
    290161    CGuest guest = session.GetConsole().GetGuest();
    291     QVector<QString> formats;
    292     QVector<KDragAndDropAction> actions;
    293     KDragAndDropAction defaultAction = guest.DragGHPending(screenId, formats, actions);
     162    QVector<QString> vecFmtGuest;
     163    QVector<KDragAndDropAction> vecActions;
     164    KDragAndDropAction defaultAction = guest.DragGHPending(screenId, vecFmtGuest, vecActions);
     165    LogFlowFunc(("defaultAction=%d, numFormats=%d\n", defaultAction, vecFmtGuest.size()));
     166
     167    /*
     168     * Do guest -> host format conversion, if needed.
     169     * On X11 this already maps to the Xdnd protocol.
     170     ** @todo What about MacOS X Carbon Drag Manager?
     171     *
     172     * See: https://www.iana.org/assignments/media-types/media-types.xhtml
     173     */
     174    LogFlowFunc(("Number of guest formats: %d\n", vecFmtGuest.size()));
     175    QStringList lstFmtNative;
     176    for (int i = 0; i < vecFmtGuest.size(); i++)
     177    {
     178        const QString &strFmt = vecFmtGuest.at(i);
     179        LogFlowFunc(("\tFormat %d: %s\n", i,
     180                     strFmt.toAscii().constData()));
     181#ifdef RT_OS_WINDOWS
     182        if (   strFmt.contains("text", Qt::CaseInsensitive)
     183            && !lstFmtNative.contains("text/plain"))
     184        {
     185            lstFmtNative << "text/plain";
     186        }
     187#else
     188        lstFmtNative << strFmt;
     189#endif
     190    }
     191
     192    LogFlowFunc(("Number of native formats: %d\n", lstFmtNative.size()));
     193#ifdef DEBUG
     194    for (int i = 0; i < lstFmtNative.size(); i++)
     195        LogFlowFunc(("\tFormat %d: %s\n", i, lstFmtNative.at(i).toAscii().constData()));
     196#endif
    294197
    295198    if (    defaultAction != KDragAndDropAction_Ignore
    296         && !formats.isEmpty())
     199        && !lstFmtNative.isEmpty())
    297200    {
    298         QDrag *pDrag = new QDrag(pParent);
    299         /* pMData is transfered to the QDrag object, so no need for deletion. */
    300         UIDnDMimeData *pMData = new UIDnDMimeData(session, formats.toList(), toQtDnDAction(defaultAction), toQtDnDActions(actions), pParent);
    301         /* Inform the mime data object of any changes in the current action. */
    302         connect(pDrag, SIGNAL(actionChanged(Qt::DropAction)),
    303                 pMData, SLOT(sltActionChanged(Qt::DropAction)));
    304         pDrag->setMimeData(pMData);
    305         /* Fire it up. */
    306         pDrag->exec(toQtDnDActions(actions), toQtDnDAction(defaultAction));
     201        try
     202        {
     203            QDrag *pDrag = new QDrag(pParent);
     204
     205            /* pMData is transfered to the QDrag object, so no need for deletion. */
     206            UIDnDMimeData *pMData = new UIDnDMimeData(session, lstFmtNative,
     207                                                      toQtDnDAction(defaultAction),
     208                                                      toQtDnDActions(vecActions), pParent);
     209
     210            /* Inform the MIME data object of any changes in the current action. */
     211            connect(pDrag, SIGNAL(actionChanged(Qt::DropAction)),
     212                    pMData, SLOT(sltDropActionChanged(Qt::DropAction)));
     213
     214            /* Fire it up.
     215             *
     216             * On Windows this will start a modal operation using OLE's
     217             * DoDragDrop() method, so this call will block until the DnD operation
     218             * is finished. */
     219            pDrag->setMimeData(pMData);
     220            pDrag->exec(toQtDnDActions(vecActions), toQtDnDAction(defaultAction));
     221
     222            rc = VINF_SUCCESS;
     223        }
     224        catch (std::bad_alloc)
     225        {
     226            rc = VERR_NO_MEMORY;
     227        }
    307228    }
     229    else
     230        rc = VINF_SUCCESS;
     231#else
     232    rc = VERR_NOT_SUPPORTED;
     233#endif /* VBOX_WITH_DRAG_AND_DROP_GH */
     234
     235    LogFlowFuncLeaveRC(rc);
     236    return rc;
    308237}
    309238
     
    341270Qt::DropAction UIDnDHandler::toQtDnDAction(KDragAndDropAction action)
    342271{
     272    Qt::DropAction dropAct = Qt::IgnoreAction;
    343273    if (action == KDragAndDropAction_Copy)
    344         return Qt::CopyAction;
     274        dropAct = Qt::CopyAction;
    345275    if (action == KDragAndDropAction_Move)
    346         return Qt::MoveAction;
     276        dropAct = Qt::MoveAction;
    347277    if (action == KDragAndDropAction_Link)
    348         return Qt::LinkAction;
    349 
    350     return Qt::IgnoreAction;
    351 }
    352 
    353 Qt::DropActions UIDnDHandler::toQtDnDActions(const QVector<KDragAndDropAction> &actions)
    354 {
    355     Qt::DropActions a = 0;
    356     for (int i = 0; i < actions.size(); ++i)
     278        dropAct = Qt::LinkAction;
     279
     280    LogFlowFunc(("dropAct=0x%x\n", dropAct));
     281    return dropAct;
     282}
     283
     284Qt::DropActions UIDnDHandler::toQtDnDActions(const QVector<KDragAndDropAction> &vecActions)
     285{
     286    Qt::DropActions dropActs = Qt::IgnoreAction;
     287    for (int i = 0; i < vecActions.size(); i++)
    357288    {
    358         switch (actions.at(i))
    359         {
    360             case KDragAndDropAction_Ignore: a |= Qt::IgnoreAction; break;
    361             case KDragAndDropAction_Copy:   a |= Qt::CopyAction; break;
    362             case KDragAndDropAction_Move:   a |= Qt::MoveAction; break;
    363             case KDragAndDropAction_Link:   a |= Qt::LinkAction; break;
     289        switch (vecActions.at(i))
     290        {
     291            case KDragAndDropAction_Ignore:
     292                dropActs |= Qt::IgnoreAction;
     293                break;
     294            case KDragAndDropAction_Copy:
     295                dropActs |= Qt::CopyAction;
     296                break;
     297            case KDragAndDropAction_Move:
     298                dropActs |= Qt::MoveAction;
     299                break;
     300            case KDragAndDropAction_Link:
     301                dropActs |= Qt::LinkAction;
     302                break;
     303            default:
     304                break;
    364305        }
    365306    }
    366     return a;
     307
     308    LogFlowFunc(("dropActions=0x%x\n", dropActs));
     309    return dropActs;
    367310}
    368311
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDHandler.h

    r44529 r50265  
     1/* $Id$ */
    12/** @file
    23 *
     
    67
    78/*
    8  * Copyright (C) 2011-2012 Oracle Corporation
     9 * Copyright (C) 2011-2014 Oracle Corporation
    910 *
    1011 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2324#include "COMEnums.h"
    2425
    25 /* Forward declarations: */
     26/* Forward declarations. */
    2627class QMimeData;
    2728class CSession;
    2829class CGuest;
    2930
    30 /* Todo: check for making this a full static class when possible. */
     31/** @todo Check for making this a full static class when possible. */
    3132class UIDnDHandler: public QObject
    3233{
    3334public:
    34     /* Singleton */
    35     static UIDnDHandler* instance()
     35    /* Singleton factory. */
     36    static UIDnDHandler* instance(void)
    3637    {
    3738        if (!m_pInstance)
     
    3940        return m_pInstance;
    4041    }
    41     static void destroy() { delete m_pInstance; m_pInstance = 0; }
     42    static void destroy(void)
     43    {
     44        if (m_pInstance)
     45        {
     46            delete m_pInstance;
     47            m_pInstance = NULL;
     48        }
     49    }
    4250
    43     /* Host -> Guest */
    44     Qt::DropAction dragHGEnter(CGuest &guest, ulong screenId, int x, int y, Qt::DropAction proposedAction, Qt::DropActions possibleActions, const QMimeData *pMimeData, QWidget *pParent = 0);
    45     Qt::DropAction dragHGMove (CGuest &guest, ulong screenId, int x, int y, Qt::DropAction proposedAction, Qt::DropActions possibleActions, const QMimeData *pMimeData, QWidget *pParent = 0);
    46     Qt::DropAction dragHGDrop (CGuest &guest, ulong screenId, int x, int y, Qt::DropAction proposedAction, Qt::DropActions possibleActions, const QMimeData *pMimeData, QWidget *pParent = 0);
    47     void           dragHGLeave(CGuest &guest, ulong screenId, QWidget *pParent = 0);
     51    /* Host -> Guest. */
     52    Qt::DropAction dragHGEnter(CGuest &guest, ulong screenId, int x, int y, Qt::DropAction proposedAction, Qt::DropActions possibleActions, const QMimeData *pMimeData, QWidget *pParent = NULL);
     53    Qt::DropAction dragHGMove (CGuest &guest, ulong screenId, int x, int y, Qt::DropAction proposedAction, Qt::DropActions possibleActions, const QMimeData *pMimeData, QWidget *pParent = NULL);
     54    Qt::DropAction dragHGDrop (CGuest &guest, ulong screenId, int x, int y, Qt::DropAction proposedAction, Qt::DropActions possibleActions, const QMimeData *pMimeData, QWidget *pParent = NULL);
     55    void           dragHGLeave(CGuest &guest, ulong screenId, QWidget *pParent = NULL);
    4856
    49     /* Guest -> Host */
    50     void           dragGHPending(CSession &session, ulong screenId, QWidget *pParent = 0);
     57    /* Guest -> Host. */
     58    int            dragGHPending(CSession &session, ulong screenId, QWidget *pParent = NULL);
    5159
    5260private:
    5361    static UIDnDHandler *m_pInstance;
    5462
    55     UIDnDHandler();
    56     ~UIDnDHandler() {}
     63    UIDnDHandler(void);
     64    virtual ~UIDnDHandler(void) {}
    5765
    58     /* Private helpers */
     66    /* Private helpers. */
    5967    static KDragAndDropAction          toVBoxDnDAction(Qt::DropAction action);
    6068    static QVector<KDragAndDropAction> toVBoxDnDActions(Qt::DropActions actions);
    6169    static Qt::DropAction              toQtDnDAction(KDragAndDropAction action);
    62     static Qt::DropActions             toQtDnDActions(const QVector<KDragAndDropAction> &actions);
     70    static Qt::DropActions             toQtDnDActions(const QVector<KDragAndDropAction> &vecActions);
    6371
    6472    friend class UIDnDMimeData;
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineView.cpp

    r50248 r50265  
    11691169}
    11701170
    1171 void UIMachineView::handleGHDnd()
     1171void UIMachineView::handleGHDnd(void)
    11721172{
    11731173    /* The guest object to talk to. */
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMouseHandler.cpp

    r48950 r50265  
    907907                || cpnt.y() > iCh - 1)
    908908            {
    909                 if ((mouseButtons.testFlag(Qt::LeftButton)))
     909                bool fHandledGHDnD
     910                    = RT_BOOL(mouseButtons.testFlag(Qt::LeftButton));
     911                if (fHandledGHDnD)
    910912                {
    911913                    m_views[uScreenId]->handleGHDnd();
    912 
    913                     return false;
     914                    return true;
    914915                }
    915916            }
  • trunk/src/VBox/HostServices/DragAndDrop/service.cpp

    r49891 r50265  
    55
    66/*
    7  * Copyright (C) 2011-2013 Oracle Corporation
     7 * Copyright (C) 2011-2014 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    177177    switch (u32Function)
    178178    {
     179        /* Note: Older VBox versions with enabled DnD guest->host support (< 4.4)
     180         *       used the same ID (300) for GUEST_DND_GET_NEXT_HOST_MSG and
     181         *       HOST_DND_GH_REQ_PENDING, which led this service returning
     182         *       VERR_INVALID_PARAMETER when the guest wanted to actually
     183         *       handle HOST_DND_GH_REQ_PENDING. */
    179184        case DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG:
    180185        {
  • trunk/src/VBox/Main/src-client/GuestDnDImpl.cpp

    r49891 r50265  
    55
    66/*
    7  * Copyright (C) 2011-2013 Oracle Corporation
     7 * Copyright (C) 2011-2014 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    167167class DnDGuestResponse
    168168{
     169
    169170public:
     171
    170172    DnDGuestResponse(const ComObjPtr<Guest>& pGuest);
    171     ~DnDGuestResponse();
    172 
    173     int notifyAboutGuestResponse();
    174     int waitForGuestResponse();
     173
     174    virtual ~DnDGuestResponse(void);
     175
     176public:
     177
     178    int notifyAboutGuestResponse(void);
     179    int waitForGuestResponse(RTMSINTERVAL msTimeout = 500);
    175180
    176181    void setDefAction(uint32_t a) { m_defAction = a; }
    177     uint32_t defAction() const { return m_defAction; }
     182    uint32_t defAction(void) const { return m_defAction; }
    178183
    179184    void setAllActions(uint32_t a) { m_allActions = a; }
     
    181186
    182187    void setFormat(const Utf8Str &strFormat) { m_strFormat = strFormat; }
    183     Utf8Str format() const { return m_strFormat; }
    184 
    185     int addData(void *pvData, uint32_t cbData, uint32_t *pcbCurSize);
    186     void resetData();
    187     void data(void **ppvData, uint32_t *pcbData) const { *ppvData = m_pvData; *pcbData = m_cbData; }
    188     bool hasData() const { return m_pvData != NULL; }
     188    Utf8Str format(void) const { return m_strFormat; }
     189
     190    int dataAdd(void *pvData, uint32_t cbData, uint32_t *pcbCurSize);
     191    void reset(void);
     192    const void *data(void) { return m_pvData; }
     193    size_t size(void) const { return m_cbData; }
    189194
    190195    int setProgress(unsigned uPercentage, uint32_t uState, int rcOp = VINF_SUCCESS);
     
    213218        , m_pDnDResponse(new DnDGuestResponse(pGuest))
    214219    {}
    215     ~GuestDnDPrivate() { delete m_pDnDResponse; }
    216 
    217     DnDGuestResponse *response() const { return m_pDnDResponse; }
     220    virtual ~GuestDnDPrivate(void) { delete m_pDnDResponse; }
     221
     222    DnDGuestResponse *response(void) const { return m_pDnDResponse; }
    218223
    219224    void adjustCoords(ULONG uScreenId, ULONG *puX, ULONG *puY) const;
     
    274279DnDGuestResponse::~DnDGuestResponse()
    275280{
    276     resetData();
     281    reset();
    277282    int rc = RTSemEventDestroy(m_EventSem);
    278283    AssertRC(rc);
     
    284289}
    285290
    286 int DnDGuestResponse::waitForGuestResponse()
    287 {
    288     int vrc = RTSemEventWait(m_EventSem, 300);
     291int DnDGuestResponse::waitForGuestResponse(RTMSINTERVAL msTimeout /*= 500 */)
     292{
     293    int vrc = RTSemEventWait(m_EventSem, msTimeout);
    289294#ifdef DEBUG_andy
    290     LogFlowFunc(("rc=%Rrc\n", vrc));
     295    LogFlowFunc(("msTimeout=%RU32, rc=%Rrc\n", msTimeout, vrc));
    291296#endif
    292297    return vrc;
    293298}
    294299
    295 int DnDGuestResponse::addData(void *pvData, uint32_t cbData, uint32_t *pcbCurSize)
     300int DnDGuestResponse::dataAdd(void *pvData, uint32_t cbData, uint32_t *pcbCurSize)
    296301{
    297302    int rc = VINF_SUCCESS;
     303
     304    /** @todo Make reallocation scheme a bit smarter here. */
    298305    m_pvData = RTMemRealloc(m_pvData, m_cbData + cbData);
    299306    if (m_pvData)
    300307    {
    301         memcpy(&static_cast<uint8_t*>(m_pvData)[m_cbData], pvData, cbData);
    302         m_cbData    += cbData;
    303         *pcbCurSize  = m_cbData;
     308        memcpy(&static_cast<uint8_t*>(m_pvData)[m_cbData],
     309               pvData, cbData);
     310        m_cbData += cbData;
     311
     312        if (pcbCurSize)
     313            *pcbCurSize = m_cbData;
    304314    }
    305315    else
     
    309319}
    310320
    311 void DnDGuestResponse::resetData()
     321void DnDGuestResponse::reset(void)
    312322{
    313323    if (m_pvData)
     
    316326        m_pvData = NULL;
    317327    }
     328
    318329    m_cbData = 0;
    319330}
     
    747758}
    748759
    749 HRESULT GuestDnD::dragHGPutData(ULONG uScreenId, IN_BSTR bstrFormat, ComSafeArrayIn(BYTE, data), IProgress **ppProgress)
     760HRESULT GuestDnD::dragHGPutData(ULONG uScreenId, IN_BSTR bstrFormat,
     761                                ComSafeArrayIn(BYTE, data), IProgress **ppProgress)
    750762{
    751763    DPTR(GuestDnD);
     
    786798}
    787799
    788 # ifdef VBOX_WITH_DRAG_AND_DROP_GH
    789 HRESULT GuestDnD::dragGHPending(ULONG uScreenId, ComSafeArrayOut(BSTR, formats), ComSafeArrayOut(DragAndDropAction_T, allowedActions), DragAndDropAction_T *pDefaultAction)
     800#ifdef VBOX_WITH_DRAG_AND_DROP_GH
     801HRESULT GuestDnD::dragGHPending(ULONG uScreenId,
     802                                ComSafeArrayOut(BSTR, formats),
     803                                ComSafeArrayOut(DragAndDropAction_T, allowedActions),
     804                                DragAndDropAction_T *pDefaultAction)
    790805{
    791806    DPTR(GuestDnD);
     
    821836        /* Convert the action bit field to a vector of actions. */
    822837        d->toMainActions(pDnD->allActions(), ComSafeArrayOutArg(allowedActions));
     838
     839        LogFlowFunc(("*pDefaultAction=0x%x\n", *pDefaultAction));
    823840    }
    824841    catch (HRESULT rc2)
     
    830847}
    831848
    832 HRESULT GuestDnD::dragGHDropped(IN_BSTR bstrFormat, DragAndDropAction_T action, IProgress **ppProgress)
     849HRESULT GuestDnD::dragGHDropped(IN_BSTR bstrFormat, DragAndDropAction_T action,
     850                                IProgress **ppProgress)
    833851{
    834852    DPTR(GuestDnD);
     
    845863    try
    846864    {
     865        LogFlowFunc(("strFormat=%s, uAction=0x%x\n", strFormat.c_str(), uAction));
     866
    847867        VBOXHGCMSVCPARM paParms[3];
    848868        int i = 0;
     
    853873        DnDGuestResponse *pDnD = d->response();
    854874        /* Reset any old data and the progress status. */
    855         pDnD->resetData();
     875        pDnD->reset();
    856876        pDnD->resetProgress(p);
    857877
     
    879899
    880900    DnDGuestResponse *pDnD = d->response();
    881     /* Is there data at all? */
    882     if (pDnD->hasData())
    883     {
    884         /* Copy the data into an safe array of bytes. */
    885         void     *pvData = 0;
    886         uint32_t  cbData = 0;
    887         pDnD->data(&pvData, &cbData);
    888         com::SafeArray<BYTE> sfaData(cbData);
    889         memcpy(sfaData.raw(), pvData, cbData);
     901    if (pDnD)
     902    {
     903        com::SafeArray<BYTE> sfaData;
     904
     905        uint32_t cbData = pDnD->size();
     906        if (cbData)
     907        {
     908            /* Copy the data into an safe array of bytes. */
     909            const void *pvData = pDnD->data();
     910            if (sfaData.resize(cbData))
     911                memcpy(sfaData.raw(), pvData, cbData);
     912            else
     913                rc = E_OUTOFMEMORY;
     914        }
     915
     916#ifdef DEBUG_andy
     917        LogFlowFunc(("Received %RU32 bytes\n", cbData));
     918#endif
     919        /* Detach in any case, regardless of data size. */
    890920        sfaData.detachTo(ComSafeArrayOutArg(data));
     921
    891922        /* Delete the data. */
    892         pDnD->resetData();
     923        pDnD->reset();
    893924    }
    894925    else
     
    897928    return rc;
    898929}
    899 
    900 # endif /* VBOX_WITH_DRAG_AND_DROP_GH */
     930#endif /* VBOX_WITH_DRAG_AND_DROP_GH */
    901931
    902932DECLCALLBACK(int) GuestDnD::notifyGuestDragAndDropEvent(void *pvExtension, uint32_t u32Function, void *pvParms, uint32_t cbParms)
     
    929959            break;
    930960        }
     961
    931962        case DragAndDropSvc::GUEST_DND_HG_REQ_DATA:
    932963        {
     
    939970            break;
    940971        }
     972
    941973        case DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS:
    942974        {
     
    948980            break;
    949981        }
     982
    950983#ifdef VBOX_WITH_DRAG_AND_DROP_GH
    951984        case DragAndDropSvc::GUEST_DND_GH_ACK_PENDING:
     
    961994            break;
    962995        }
     996
    963997        case DragAndDropSvc::GUEST_DND_GH_SND_DATA:
    964998        {
     
    9671001            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDDATADATA) == cbParms, VERR_INVALID_PARAMETER);
    9681002            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     1003
    9691004            uint32_t cbCurSize = 0;
    970             pResp->addData(pCBData->pvData, pCBData->cbData, &cbCurSize);
    971             rc = pResp->setProgress(100.0 / pCBData->cbAllSize * cbCurSize, (pCBData->cbAllSize == cbCurSize ? DragAndDropSvc::DND_PROGRESS_COMPLETE : DragAndDropSvc::DND_PROGRESS_RUNNING));
     1005            rc = pResp->dataAdd(pCBData->pvData, pCBData->cbData, &cbCurSize);
     1006            if (RT_SUCCESS(rc))
     1007            {
     1008                uint32_t cbTotalSize = pCBData->cbAllSize;
     1009                unsigned int cPercentage;
     1010                if (!cbTotalSize) /* Watch out for division by zero. */
     1011                    cPercentage = 100;
     1012                else
     1013                    cPercentage = cbCurSize * 100.0 / cbTotalSize;
     1014
     1015                /** @todo Don't use anonymous enums. */
     1016                uint32_t uState = DragAndDropSvc::DND_PROGRESS_RUNNING;
     1017                if (   pCBData->cbAllSize == cbCurSize
     1018                    /* Empty data? Should not happen, but anyway ... */
     1019                    || !pCBData->cbAllSize)
     1020                {
     1021                    uState = DragAndDropSvc::DND_PROGRESS_COMPLETE;
     1022                }
     1023
     1024                rc = pResp->setProgress(cPercentage, uState);
     1025            }
    9721026            /* Todo: for now we instantly confirm the cancel. Check if the
    9731027             * guest should first clean up stuff itself and than really confirm
     
    9771031            break;
    9781032        }
     1033
    9791034        case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR:
    9801035        {
     
    9831038            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBEVTERRORDATA) == cbParms, VERR_INVALID_PARAMETER);
    9841039            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_EVT_ERROR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     1040
    9851041            /* Cleanup */
    986             pResp->resetData();
     1042            pResp->reset();
    9871043            rc = pResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_ERROR, pCBData->rc);
    9881044            break;
     
    9901046#endif /* VBOX_WITH_DRAG_AND_DROP_GH */
    9911047        default:
    992             AssertMsgFailedReturn(("Function %RU32 not supported\n", u32Function), VERR_NOT_SUPPORTED);
     1048            rc = VERR_NOT_SUPPORTED; /* Tell the guest. */
    9931049            break;
    9941050    }
Note: See TracChangeset for help on using the changeset viewer.

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