/* static */
void GuestDnD::toHGCMActions(DnDAction_T                    enmDefAction,
                             uint32_t                      *puDefAction,
                             const std::vector<DnDAction_T> vecAllowedActions,
                             uint32_t                      *puAllowedActions)
{
    uint32_t uAllowedActions = DND_IGNORE_ACTION;
    uint32_t uDefAction      = toHGCMAction(enmDefAction);

    if (!vecAllowedActions.empty())
    {
        /* First convert the allowed actions to a bit array. */
        for (size_t i = 0; i < vecAllowedActions.size(); i++)
            uAllowedActions |= toHGCMAction(vecAllowedActions[i]);

        /*
         * If no default action is set (ignoring), try one of the
         * set allowed actions, preferring copy, move (in that order).
         */
        if (isDnDIgnoreAction(uDefAction))
        {
            if (hasDnDCopyAction(uAllowedActions))
                uDefAction = DND_COPY_ACTION;
            else if (hasDnDMoveAction(uAllowedActions))
                uDefAction = DND_MOVE_ACTION;
        }
    }

    if (puDefAction)
        *puDefAction      = uDefAction;
    if (puAllowedActions)
        *puAllowedActions = uAllowedActions;
}
HRESULT GuestDnDSource::dragIsPending(ULONG uScreenId,
                                      std::vector<com::Utf8Str> &aFormats,
                                      std::vector<DnDAction_T> &aAllowedActions,
                                      DnDAction_T *aDefaultAction)
{
#if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
    ReturnComNotImplemented();
#else /* VBOX_WITH_DRAG_AND_DROP */

    AutoCaller autoCaller(this);
    if (FAILED(autoCaller.rc())) return autoCaller.rc();

    /* Default is ignoring the action. */
    DnDAction_T defaultAction = DnDAction_Ignore;

    HRESULT hr = S_OK;

    VBOXHGCMSVCPARM paParms[1];
    int i = 0;
    paParms[i++].setUInt32(uScreenId);

    int rc = GuestDnDInst()->hostCall(DragAndDropSvc::HOST_DND_GH_REQ_PENDING,
                                      i, paParms);
    if (RT_SUCCESS(rc))
    {
        bool fFetchResult = true;
        GuestDnDResponse *pResp = GuestDnDInst()->response();
        if (pResp)
        {
            if (pResp->waitForGuestResponse() == VERR_TIMEOUT)
                fFetchResult = false;

            if (isDnDIgnoreAction(pResp->defAction()))
                fFetchResult = false;

            /* Fetch the default action to use. */
            if (fFetchResult)
            {
                defaultAction = GuestDnD::toMainAction(pResp->defAction());

                GuestDnD::toFormatVector(m_strFormats, pResp->format(), aFormats);
                GuestDnD::toMainActions(pResp->allActions(), aAllowedActions);
            }
        }

        if (aDefaultAction)
            *aDefaultAction = defaultAction;
    }

    if (RT_FAILURE(rc))
        hr = setError(VBOX_E_IPRT_ERROR,
                      tr("Unable to retrieve pending status (%Rrc)\n"), rc);

    LogFlowFunc(("hr=%Rhrc, defaultAction=0x%x\n", hr, defaultAction));
    return hr;
#endif /* VBOX_WITH_DRAG_AND_DROP */
}
HRESULT GuestDnDSource::drop(const com::Utf8Str &aFormat,
                             DnDAction_T aAction, ComPtr<IProgress> &aProgress)
{
#if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
    ReturnComNotImplemented();
#else /* VBOX_WITH_DRAG_AND_DROP */

    /* Input validation. */
    if (RT_UNLIKELY((aFormat.c_str()) == NULL || *(aFormat.c_str()) == '\0'))
        return setError(E_INVALIDARG, tr("No drop format specified"));

    AutoCaller autoCaller(this);
    if (FAILED(autoCaller.rc())) return autoCaller.rc();

    uint32_t uAction = GuestDnD::toHGCMAction(aAction);
    /* If there is no usable action, ignore this request. */
    if (isDnDIgnoreAction(uAction))
        return S_OK;

    HRESULT hr = S_OK;

    const char *pcszFormat = aFormat.c_str();
    bool fNeedsDropDir = DnDMIMENeedsDropDir(pcszFormat, strlen(pcszFormat));
    LogFlowFunc(("strFormat=%s, uAction=0x%x, fNeedsDropDir=%RTbool\n",
                 pcszFormat, uAction, fNeedsDropDir));

    GuestDnDResponse *pResp = GuestDnDInst()->response();
    if (pResp)
    {
        /* Reset any old data. */
        pResp->reset();
        pResp->resetProgress(m_pGuest);

        /* Set the format we are going to retrieve to have it around
         * when retrieving the data later. */
        pResp->setFormat(aFormat);

        if (fNeedsDropDir)
        {
            char szDropDir[RTPATH_MAX];
            int rc = DnDDirCreateDroppedFiles(szDropDir, sizeof(szDropDir));
            LogFlowFunc(("rc=%Rrc, szDropDir=%s\n", rc, szDropDir));
            if (RT_FAILURE(rc))
                return setError(VBOX_E_IPRT_ERROR,
                                tr("Unable to create the temporary drag and drop directory \"%s\" (%Rrc)\n"),
                                szDropDir, rc);

            pResp->setDropDir(szDropDir);
        }

        VBOXHGCMSVCPARM paParms[4];
        int i = 0;
        paParms[i++].setPointer((void*)aFormat.c_str(), (uint32_t)aFormat.length() + 1);
        paParms[i++].setUInt32((uint32_t)aFormat.length() + 1);
        paParms[i++].setUInt32(uAction);

        int rc = GuestDnDInst()->hostCall(DragAndDropSvc::HOST_DND_GH_EVT_DROPPED,
                                          i, paParms);
        if (RT_SUCCESS(rc))
        {
            /* Query the progress object to the caller. */
            pResp->queryProgressTo(aProgress.asOutParam());
        }
        else
            hr = setError(VBOX_E_IPRT_ERROR,
                          tr("Error signalling to drop data (%Rrc)\n"), rc);
    }

    LogFlowFunc(("Returning hr=%Rhrc\n", hr));
    return hr;
#endif /* VBOX_WITH_DRAG_AND_DROP */
}