VirtualBox

Changeset 50305 in vbox


Ignore:
Timestamp:
Feb 3, 2014 10:47:45 AM (11 years ago)
Author:
vboxsync
Message:

DnD: Update.

Location:
trunk
Files:
11 edited

Legend:

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

    r50265 r50305  
    6868    HOST_DND_SET_MODE                  = 100,
    6969
    70     /* H->G */
     70    /*
     71     * Host -> Guest messages
     72     */
     73
    7174    HOST_DND_HG_EVT_ENTER              = 200,
    7275    HOST_DND_HG_EVT_MOVE,
     
    7881    HOST_DND_HG_SND_DATA,
    7982    /** Sent when the actual buffer for HOST_DND_HG_SND_DATA
    80      *  was too small. */
     83     *  was too small, issued by the DnD host service. */
    8184    HOST_DND_HG_SND_MORE_DATA,
     85    /** Directory entry to be handled on the guest. */
    8286    HOST_DND_HG_SND_DIR,
     87    /** File entry to be handled on the guest. */
    8388    HOST_DND_HG_SND_FILE,
    8489
    85     /* G->H */
     90    /*
     91     * Guest -> Host messages
     92     */
     93
    8694    /** The host asks the guest whether a DnD operation
    8795     *  is in progress when the mouse leaves the guest window. */
     
    9098     *  has been started and that the host wants the data in
    9199     *  a specific mime-type. */
    92     HOST_DND_GH_EVT_DROPPED
     100    HOST_DND_GH_EVT_DROPPED,
     101
     102    HOST_DND_GH_RECV_DIR               = 650,
     103    HOST_DND_GH_RECV_FILE
    93104};
    94105
     
    107118
    108119    /* H->G */
     120    /** The guest acknowledges that the pending DnD data from
     121     *  the host can be dropped on the currently selected source
     122     *  on the guest. */
    109123    GUEST_DND_HG_ACK_OP                = 400,
     124    /** The guest requests the actual DnD data to be sent
     125     *  from the host. */
    110126    GUEST_DND_HG_REQ_DATA,
    111127    GUEST_DND_HG_EVT_PROGRESS,
     
    119135    GUEST_DND_GH_ACK_PENDING           = 500,
    120136    GUEST_DND_GH_SND_DATA,
    121     GUEST_DND_GH_EVT_ERROR
     137    GUEST_DND_GH_EVT_ERROR,
     138
     139    GUEST_DND_GH_SND_DIR               = 700,
     140    GUEST_DND_GH_SND_FILE
    122141};
    123142
  • trunk/include/VBox/VBoxGuestLib.h

    r49891 r50305  
    44
    55/*
    6  * Copyright (C) 2006-2013 Oracle Corporation
     6 * Copyright (C) 2006-2014 Oracle Corporation
    77 *
    88 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    722722VBGLR3DECL(int)     VbglR3DnDHGRequestData(uint32_t u32ClientId, const char* pcszFormat);
    723723#  ifdef VBOX_WITH_DRAG_AND_DROP_GH
    724 VBGLR3DECL(int)     VbglR3DnDGHAcknowledgePending(uint32_t u32ClientId, uint32_t uDefAction, uint32_t uAllActions, const char* pcszFormat);
     724VBGLR3DECL(int)     VbglR3DnDGHAcknowledgePending(uint32_t u32ClientId, uint32_t uDefAction, uint32_t uAllActions, const char* pcszFormats);
    725725VBGLR3DECL(int)     VbglR3DnDGHSendData(uint32_t u32ClientId, void *pvData, uint32_t cbData);
    726726VBGLR3DECL(int)     VbglR3DnDGHErrorEvent(uint32_t u32ClientId, int rcOp);
  • trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.cpp

    r50266 r50305  
    515515                    reset();
    516516                    rc = VINF_SUCCESS; /** @todo GUEST_DND_GH_EVT_ERROR */
     517#else
     518                    rc = VERR_NOT_SUPPORTED;
     519#endif
     520                    break;
     521                }
     522
     523                case DragAndDropSvc::HOST_DND_GH_RECV_DIR:
     524                {
     525                    LogFlowThisFunc(("HOST_DND_GH_RECV_DIR\n"));
     526#ifdef VBOX_WITH_DRAG_AND_DROP_GH
     527                    if (mMode == GH)
     528                    {
     529                        rc = OnGhSendDir(pEvent->Event.pszFormats,
     530                                         pEvent->Event.cbFormats,
     531                                         pEvent->Event.u.a.uDefAction);
     532                    }
     533                    else
     534                        rc = VERR_WRONG_ORDER;
     535#else
     536                    rc = VERR_NOT_SUPPORTED;
     537#endif
     538                    break;
     539                }
     540
     541                case DragAndDropSvc::HOST_DND_GH_RECV_FILE:
     542                {
     543                    LogFlowThisFunc(("HOST_DND_GH_RECV_FILE\n"));
     544#ifdef VBOX_WITH_DRAG_AND_DROP_GH
     545                    if (mMode == GH)
     546                    {
     547                        rc = OnGhSendFile(pEvent->Event.pszFormats,
     548                                          pEvent->Event.cbFormats,
     549                                          pEvent->Event.u.a.uDefAction);
     550                    }
     551                    else
     552                        rc = VERR_WRONG_ORDER;
    517553#else
    518554                    rc = VERR_NOT_SUPPORTED;
     
    934970#endif
    935971
    936 #if 1
    937972        /** @todo Multi-monitor setups? */
    938973        int iScreenX = GetSystemMetrics(SM_CXSCREEN) - 1;
     
    963998        else
    964999            LogFlowFunc(("Unable to send input, error=0x%x\n", GetLastError()));
    965 #else
    966         SetCursorPos(p.x, p.y);
    967 #endif
    9681000
    9691001#ifdef DEBUG_andy
     
    9811013    if (RT_SUCCESS(rc))
    9821014    {
     1015        uint32_t uDefAction = DND_IGNORE_ACTION;
     1016
    9831017        AssertPtr(pDropTarget);
    984 
    985         uint32_t uDefAction = DND_IGNORE_ACTION;
    986         RTCString strFormat = "unknown";
    987         if (pDropTarget->HasData())
     1018        RTCString strFormats = pDropTarget->Formats();
     1019        if (!strFormats.isEmpty())
    9881020        {
    9891021            uDefAction = DND_COPY_ACTION;
    9901022            uAllActions = uDefAction;
    9911023
    992             /** @todo There can be more than one format, separated
    993              *        with \r\n. */
    994             strFormat = "text/plain;charset=utf-8";
    995 
    996             LogFlowFunc(("Acknowledging pDropTarget=0x%p, uDefAction=0x%x, uAllActions=0x%x, strFormat=%s\n",
    997                          pDropTarget, uDefAction, uAllActions, strFormat.c_str()));
     1024            LogFlowFunc(("Acknowledging pDropTarget=0x%p, uDefAction=0x%x, uAllActions=0x%x, strFormats=%s\n",
     1025                         pDropTarget, uDefAction, uAllActions, strFormats.c_str()));
    9981026            rc = VbglR3DnDGHAcknowledgePending(mClientID,
    999                                                uDefAction, uAllActions, strFormat.c_str());
    1000         }
     1027                                               uDefAction, uAllActions, strFormats.c_str());
     1028        }
     1029        else
     1030            LogFlowFunc(("No format data available yet\n"));
    10011031    }
    10021032
     
    10081038                            uint32_t uDefAction)
    10091039{
    1010     LogFlowThisFunc(("mMode=%ld, mState=%ld, pDropTarget=0x%p, cbFormats=%RU32, uDefAction=0x%x\n",
    1011                      mMode, mState, pDropTarget, cbFormats, uDefAction));
     1040    AssertPtrReturn(pszFormats, VERR_INVALID_POINTER);
     1041    AssertReturn(cbFormats, VERR_INVALID_PARAMETER);
     1042
     1043    LogFlowThisFunc(("mMode=%ld, mState=%ld, pDropTarget=0x%p, uDefAction=0x%x\n",
     1044                     mMode, mState, pDropTarget, uDefAction));
     1045#ifdef DEBUG
     1046    RTCList<RTCString> lstFormats =
     1047        RTCString(pszFormats, cbFormats - 1).split("\r\n");
     1048
     1049    LogFlow(("cbFormats=%RU32: ", cbFormats));
     1050    for (size_t i = 0; i < lstFormats.size(); i++)
     1051        LogFlow(("'%s' ", lstFormats.at(i).c_str()));
     1052    LogFlow(("\n"));
     1053#endif
     1054
    10121055    int rc;
    10131056    if (mState == Dragging)
    10141057    {
    10151058        AssertPtr(pDropTarget);
    1016         rc = pDropTarget->WaitForDrop(30 * 1000 /* Timeout */);
     1059        rc = pDropTarget->WaitForDrop(30 * 1000 /* Timeout in ms */);
    10171060        if (RT_SUCCESS(rc))
    10181061        {
     
    10351078        rc = VERR_WRONG_ORDER;
    10361079
     1080    LogFlowFuncLeaveRC(rc);
     1081    return rc;
     1082}
     1083
     1084int VBoxDnDWnd::OnGhSendDir(const char *pszFormats, uint32_t cbFormats,
     1085                            uint32_t uDefAction)
     1086{
     1087    int rc = 0;
     1088    LogFlowFuncLeaveRC(rc);
     1089    return rc;
     1090}
     1091
     1092int VBoxDnDWnd::OnGhSendFile(const char *pszFormats, uint32_t cbFormats,
     1093                             uint32_t uDefAction)
     1094{
     1095    int rc = 0;
    10371096    LogFlowFuncLeaveRC(rc);
    10381097    return rc;
  • trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.h

    r50265 r50305  
    155155public:
    156156
    157     bool HasData(void) { return RT_BOOL(mFormatEtc.cfFormat != 0); }
    158157    void *DataMutableRaw(void) { return mpvData; }
    159158    uint32_t DataSize(void) { return mcbData; }
     159    RTCString Formats(void);
    160160    int WaitForDrop(RTMSINTERVAL msTimeout);
    161161
     
    170170     *        DVTARGETDEVICE here! */
    171171    FORMATETC mFormatEtc;
     172    RTCString mFormats;
    172173    void *mpvData;
    173174    uint32_t mcbData;
     
    338339    int OnGhIsDnDPending(uint32_t uScreenID);
    339340    int OnGhDropped(const char *pszFormats, uint32_t cbFormats, uint32_t uDefAction);
     341    int OnGhSendDir(const char *pszFormats, uint32_t cbFormats, uint32_t uDefAction);
     342    int OnGhSendFile(const char *pszFormats, uint32_t cbFormats, uint32_t uDefAction);
    340343#endif
    341344
  • trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnDDropTarget.cpp

    r50265 r50305  
    1717#include <windows.h>
    1818#include <new> /* For bad_alloc. */
     19#include <Shlobj.h> /* For DROPFILES and friends. */
    1920
    2021#include "VBoxTray.h"
     
    107108    reset();
    108109
     110    /** @todo At the moment we only support one DnD format at a time. */
     111
    109112    /* Try different formats. CF_HDROP is the most common one, so start
    110113     * with this. */
    111     /** @todo At the moment we only support TYMED_HGLOBAL. */
    112114    FORMATETC fmtEtc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
    113115    HRESULT hr = pDataObject->QueryGetData(&fmtEtc);
    114     if (hr != S_OK)
     116    if (hr == S_OK)
     117    {
     118        mFormats = "text/uri-list";
     119    }
     120    else
    115121    {
    116122        LogFlowFunc(("CF_HDROP not supported, hr=%Rhrc\n", hr));
     
    125131            fmtEtc.cfFormat = 0; /* Mark it to not supported. */
    126132        }
     133        else
     134        {
     135            mFormats = "text/plain;charset=utf-8";
     136        }
    127137    }
    128138
     
    130140    if (fmtEtc.cfFormat)
    131141    {
    132         LogFlowFunc(("Found supported format %RI16\n", fmtEtc.cfFormat));
     142        LogFlowFunc(("Found supported format %RI16 (%s)\n",
     143                     fmtEtc.cfFormat, VBoxDnDDataObject::ClipboardFormatToString(fmtEtc.cfFormat)));
    133144
    134145        /* Make a copy of the FORMATETC structure so that we later can
    135146         * use this for comparrison and stuff. */
    136         /** Note: The DVTARGETDEVICE member only is a shallow copy! */
     147        /** Note: The DVTARGETDEVICE member only is a shallow copy for now! */
    137148        memcpy(&mFormatEtc, &fmtEtc, sizeof(FORMATETC));
    138149
     
    164175                    while (pEnumFormats->Next(1, &curFormatEtc,
    165176                                              NULL /* pceltFetched */) == S_OK)
    166                         {
     177                    {
    167178                        WCHAR wszCfName[128]; /* 128 chars should be enough, rest will be truncated. */
    168179                        hr2 = GetClipboardFormatNameW(curFormatEtc.cfFormat, wszCfName,
    169180                                                      sizeof(wszCfName) / sizeof(WCHAR));
    170                         LogRel(("\tcfFormat=%RI16, tyMed=%RI32, dwAspect=%RI32, strCustomName=%ls, hr=%Rhrc\n",
     181                        LogRel(("\tcfFormat=%RI16 (%s), tyMed=%RI32, dwAspect=%RI32, strCustomName=%ls, hr=%Rhrc\n",
    171182                                curFormatEtc.cfFormat,
     183                                VBoxDnDDataObject::ClipboardFormatToString(curFormatEtc.cfFormat),
    172184                                curFormatEtc.tymed,
    173185                                curFormatEtc.dwAspect,
     
    176188
    177189                    pEnumFormats->Release();
    178                 }
     190                }
    179191
    180192                break;
     
    236248
    237249#ifdef DEBUG
    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));
     250    LogFlowFunc(("mFormatEtc.cfFormat=%RI16 (%s), pDataObject=0x%p, grfKeyState=0x%x, x=%ld, y=%ld\n",
     251                 mFormatEtc.cfFormat, VBoxDnDDataObject::ClipboardFormatToString(mFormatEtc.cfFormat),
     252                 pDataObject, grfKeyState, pt.x, pt.y));
    240253#endif
    241254    HRESULT hr = S_OK;
     
    248261        hr = pDataObject->QueryGetData(&mFormatEtc);
    249262        AssertMsg(SUCCEEDED(hr),
    250                   ("Data format changed between DragEnter() and Drop(), cfFormat=%RI16, hr=%Rhrc\n",
    251                   mFormatEtc.cfFormat, hr));
    252     }
     263                  ("Data format changed between DragEnter() and Drop(), cfFormat=%RI16 (%s), hr=%Rhrc\n",
     264                  mFormatEtc.cfFormat, VBoxDnDDataObject::ClipboardFormatToString(mFormatEtc.cfFormat),
     265                  hr));
     266    }
     267
     268    int rc = VINF_SUCCESS;
    253269
    254270    if (SUCCEEDED(hr))
     
    272288                        LogFlowFunc(("Locking HGLOBAL storage failed with %Rrc\n",
    273289                                     RTErrConvertFromWin32(GetLastError())));
    274                         hr = ERROR_INVALID_HANDLE;
     290                        rc = VERR_INVALID_HANDLE;
     291                        hr = E_INVALIDARG; /* Set special hr for OLE. */
    275292                    }
    276293                    break;
     
    279296                    AssertMsgFailed(("Storage medium type %RI32 supported\n",
    280297                                     mFormatEtc.tymed));
    281                     hr = ERROR_NOT_SUPPORTED;
     298                    rc = VERR_NOT_SUPPORTED;
     299                    hr = DV_E_TYMED; /* Set special hr for OLE. */
    282300                    break;
    283301            }
    284302
    285             if (SUCCEEDED(hr))
     303            if (RT_SUCCESS(rc))
    286304            {
    287305                /* Second stage: Do the actual copying of the data object's data,
     
    289307                switch (mFormatEtc.cfFormat)
    290308                {
     309                    /* Handling CF_TEXT means that the system already did some marshalling
     310                     * to convert RTF or unicode text to plain ANSI text. */
    291311                    case CF_TEXT:
    292312                    {
    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;
     313                        AssertPtr(pvData);
     314                        size_t cbSize = GlobalSize(pvData);
     315                        LogFlowFunc(("CF_TEXT 0x%p got %zu bytes\n", pvData, cbSize));
     316                        if (cbSize)
     317                        {
     318                            char *pszText = NULL;
     319                            rc = RTStrCurrentCPToUtf8(&pszText, (char *)pvData);
     320                            if (RT_SUCCESS(rc))
     321                            {
     322                                mpvData = (void *)pszText;
     323                                mcbData = strlen(pszText) + 1;
     324                            }
     325                        }
     326
    298327                        break;
    299328                    }
    300329
    301330                    case CF_HDROP:
     331                    {
     332                        AssertPtr(pvData);
     333
     334                        /* Convert to a string list, separated by \r\n. */
     335                        DROPFILES *pDropFiles = (DROPFILES *)pvData;
     336                        AssertPtr(pDropFiles);
     337                        bool fUnicode = RT_BOOL(pDropFiles->fWide);
     338
     339                        /* Get the offset of the file list. */
     340                        Assert(pDropFiles->pFiles >= sizeof(DROPFILES));
     341                        /* Note: This is *not* pDropFiles->pFiles! DragQueryFile only
     342                         *       will work with the plain storage medium pointer! */
     343                        HDROP hDrop = (HDROP)(pvData);
     344
     345                        /* First, get the file count. */
     346                        /** @todo Does this work on Windows 2000 / NT4? */
     347                        char *pszFiles = NULL;
     348                        uint32_t cchFiles = 0;
     349                        UINT cFiles = DragQueryFile(hDrop, UINT32_MAX /* iFile */,
     350                                                    NULL /* lpszFile */, 0 /* cchFile */);
     351                        LogFlowFunc(("CF_HDROP got %RU16 file(s)\n", cFiles));
     352
     353                        for (UINT i = 0; i < cFiles; i++)
     354                        {
     355                            UINT cch = DragQueryFile(hDrop, i /* File index */,
     356                                                     NULL /* Query size first */,
     357                                                     0 /* cchFile */);
     358                            Assert(cch);
     359
     360                            /* Add separation between filenames. */
     361                            if (i > 0)
     362                            {
     363                                rc = RTStrAAppendExN(&pszFiles, 1 /* cPairs */,
     364                                                     "\r\n", 2 /* Bytes */);
     365                                if (RT_SUCCESS(rc))
     366                                    cchFiles += 2; /* Include \r\n */
     367                            }
     368
     369                            if (RT_FAILURE(rc))
     370                                return rc;
     371
     372                            char *pszFile = NULL; /* UTF-8 version. */
     373                            UINT cchFile = 0;
     374                            if (fUnicode)
     375                            {
     376                                /* Allocate enough space (including terminator). */
     377                                WCHAR *pwszFile = (WCHAR *)RTMemAlloc((cch + 1) * sizeof(WCHAR));
     378                                if (pwszFile)
     379                                {
     380                                    cchFile = DragQueryFileW(hDrop, i /* File index */,
     381                                                             pwszFile, cch + 1 /* Include terminator */);
     382                                    AssertMsg(cchFile == cch, ("cchCopied (%RU16) does not match cchFile (%RU16)\n",
     383                                                               cchFile, cch));
     384                                    int rc2 = RTUtf16ToUtf8(pwszFile, &pszFile);
     385                                    AssertRC(rc2);
     386                                }
     387                                else
     388                                    rc = VERR_NO_MEMORY;
     389                            }
     390                            else /* ANSI */
     391                            {
     392                                /* Allocate enough space (including terminator). */
     393                                pszFile = (char *)RTMemAlloc((cch + 1) * sizeof(char));
     394                                if (pszFile)
     395                                {
     396                                    cchFile = DragQueryFileA(hDrop, i /* File index */,
     397                                                             pszFile, cchFile + 1 /* Include terminator */);
     398                                    AssertMsg(cchFile == cch, ("cchCopied (%RU16) does not match cchFile (%RU16)\n",
     399                                                               cchFile, cch));
     400                                }
     401                                else
     402                                    rc = VERR_NO_MEMORY;
     403                            }
     404
     405                            if (RT_SUCCESS(rc))
     406                            {
     407                                LogFlowFunc(("\tFile: %s (%RU32 characters)\n",
     408                                             pszFile, cchFile));
     409
     410                                rc = RTStrAAppendExN(&pszFiles, 1 /* cPairs */,
     411                                                     pszFile, cchFile);
     412                            }
     413
     414                            /* Termination. */
     415                            pszFiles[cchFiles] = '\0';
     416
     417                            if (pszFile)
     418                                RTMemFree(pszFile);
     419
     420                            if (RT_FAILURE(rc))
     421                                break;
     422                        }
     423
     424                        if (RT_SUCCESS(rc))
     425                        {
     426                            uint32_t cbSize = cchFiles * sizeof(char);
     427                            Assert(cbSize);
     428
     429                            mpvData = RTMemDup(pszFiles, cbSize);
     430                            mcbData = cbSize;
     431                        }
     432
     433                        LogFlowFunc(("Building CF_HDROP list rc=%Rrc, pszFiles=0x%p, cFiles=%RU16, cchFiles=%RU32\n",
     434                                     rc, pszFiles, cFiles, cchFiles));
     435
     436                        if (pszFiles)
     437                            RTStrFree(pszFiles);
    302438                        break;
     439                    }
    303440
    304441                    default:
    305                         AssertMsgFailed(("Format of type %RI16 supported\n",
    306                                          mFormatEtc.cfFormat));
     442                        AssertMsgFailed(("Format of type %RI16 (%s) not supported\n",
     443                                         mFormatEtc.cfFormat,
     444                                         VBoxDnDDataObject::ClipboardFormatToString(mFormatEtc.cfFormat)));
    307445                        hr = ERROR_NOT_SUPPORTED;
     446                        hr = DV_E_CLIPFORMAT; /* Set special hr for OLE. */
    308447                        break;
    309448                }
     
    320459
    321460                default:
    322                     AssertMsgFailed(("Storage medium type %RI32 supported\n",
    323                                      mFormatEtc.tymed));
    324                     hr = ERROR_NOT_SUPPORTED;
     461                    AssertMsgFailed(("Really should not happen -- see init stage!\n"));
    325462                    break;
    326463            }
     
    329466            ReleaseStgMedium(&stgMed);
    330467
    331             if (SUCCEEDED(hr))
     468            /** @todo Signal in any case to avoid hangs/timeouts? */
     469            if (RT_SUCCESS(rc))
    332470            {
    333471                RTSemEventSignal(hEventDrop);
     
    349487        mpWndParent->hide();
    350488
    351     LogFlowFunc(("Returning with mFormatEtc.cfFormat=%RI16, fCanDrop=%RTbool, *pdwEffect=%RI32\n",
    352                  mFormatEtc.cfFormat, fCanDrop, *pdwEffect));
     489    LogFlowFunc(("Returning with rc=%Rrc, mFormatEtc.cfFormat=%RI16 (%s), fCanDrop=%RTbool, *pdwEffect=%RI32\n",
     490                 rc, mFormatEtc.cfFormat, VBoxDnDDataObject::ClipboardFormatToString(mFormatEtc.cfFormat),
     491                 fCanDrop, *pdwEffect));
     492
    353493    return hr;
    354494}
     
    395535    mcbData = 0;
    396536    RT_ZERO(mFormatEtc);
     537    mFormats = "";
     538}
     539
     540RTCString VBoxDnDDropTarget::Formats(void)
     541{
     542    return mFormats;
    397543}
    398544
  • trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDragAndDrop.cpp

    r50265 r50305  
    329329        return VERR_NO_MEMORY;
    330330
    331     /* Create and query the drop target directory. */
     331    /* Create and query the (unique) drop target directory. */
    332332    char pszDropDir[RTPATH_MAX];
    333333    int rc = vbglR3DnDCreateDropDir(pszDropDir, sizeof(pszDropDir));
     
    486486    } /* while */
    487487
    488     RTMemFree(pvTmpData);
     488    if (pvTmpData)
     489        RTMemFree(pvTmpData);
    489490
    490491    /* Cleanup on failure or if the user has canceled. */
     
    509510                                                 void     *pvData,
    510511                                                 uint32_t  cbData,
    511                                                  uint32_t *pcbDataRecv)
     512                                                 uint32_t *pcbDataTotal)
    512513{
    513514    AssertPtrReturn(puScreenId,    VERR_INVALID_POINTER);
     
    517518    AssertPtrReturn(pvData,        VERR_INVALID_POINTER);
    518519    AssertReturn(cbData,           VERR_INVALID_PARAMETER);
    519     AssertPtrReturn(pcbDataRecv,   VERR_INVALID_POINTER);
     520    AssertPtrReturn(pcbDataTotal,  VERR_INVALID_POINTER);
    520521
    521522    DragAndDropSvc::VBOXDNDHGSENDDATAMSG Msg;
     
    535536    {
    536537        rc = Msg.hdr.result;
    537         if (RT_SUCCESS(rc)
     538        if (   RT_SUCCESS(rc)
    538539            || rc == VERR_BUFFER_OVERFLOW)
    539540        {
     
    541542            rc = Msg.uScreenId.GetUInt32(puScreenId);  AssertRC(rc);
    542543            rc = Msg.cFormat.GetUInt32(pcbFormatRecv); AssertRC(rc);
    543             rc = Msg.cData.GetUInt32(pcbDataRecv);     AssertRC(rc);
     544            rc = Msg.cData.GetUInt32(pcbDataTotal);     AssertRC(rc);
    544545            /* A little bit paranoia */
    545546            AssertReturn(cbFormat >= *pcbFormatRecv, VERR_TOO_MUCH_DATA);
    546             AssertReturn(cbData   >= *pcbDataRecv,   VERR_TOO_MUCH_DATA);
     547            AssertReturn(cbData   >= *pcbDataTotal,  VERR_TOO_MUCH_DATA);
    547548        }
    548549    }
     
    664665    if (RT_SUCCESS(rc))
    665666    {
    666         /* Check if this is a uri-event. If so, let VbglR3 do all the actual
     667        /* Check if this is an URI event. If so, let VbglR3 do all the actual
    667668         * data transfer + file /directory creation internally without letting
    668          * the caller know. */
     669         * the caller know.
     670         *
     671         * This keeps the actual (guest OS-)dependent client (like VBoxClient /
     672         * VBoxTray) small by not having too much redundant code. */
    669673        if (RTStrNICmp(pszFormat, "text/uri-list", *pcbFormatRecv) == 0)
    670674            rc = vbglR3DnDHGProcessURIMessages(uClientId,
     
    953957VBGLR3DECL(int) VbglR3DnDGHAcknowledgePending(uint32_t u32ClientId,
    954958                                              uint32_t uDefAction, uint32_t uAllActions,
    955                                               const char* pcszFormat)
    956 {
    957     AssertPtrReturn(pcszFormat, VERR_INVALID_POINTER);
     959                                              const char* pcszFormats)
     960{
     961    AssertPtrReturn(pcszFormats, VERR_INVALID_POINTER);
    958962
    959963    DragAndDropSvc::VBOXDNDGHACKPENDINGMSG Msg;
     
    966970    Msg.uDefAction.SetUInt32(uDefAction);
    967971    Msg.uAllActions.SetUInt32(uAllActions);
    968     Msg.pFormat.SetPtr((void*)pcszFormat, (uint32_t)strlen(pcszFormat) + 1);
     972    Msg.pFormat.SetPtr((void*)pcszFormats, (uint32_t)strlen(pcszFormats) + 1);
    969973    /* Do request */
    970974    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     
    979983    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
    980984    AssertReturn(cbData,    VERR_INVALID_PARAMETER);
    981 
    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
    990      */
    991985
    992986    DragAndDropSvc::VBOXDNDGHSENDDATAMSG Msg;
     
    10421036    return rc;
    10431037}
     1038
     1039VBGLR3DECL(int) VbglR3DnDGHSendFile(uint32_t u32ClientId, const char *pszPath)
     1040{
     1041    return 0;
     1042}
     1043
  • trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk

    r50265 r50305  
    451451
    452452ifdef VBOX_WITH_DRAG_AND_DROP
     453 VirtualBox_QT_MOCHDRS += \
     454        src/runtime/UIDnDHandler.h
    453455 ifdef VBOX_WITH_DRAG_AND_DROP_GH
    454456  VirtualBox_QT_MOCHDRS += \
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDHandler.cpp

    r50278 r50305  
    2323#include <QStringList>
    2424#include <QTimer>
     25#include <QUrl>
    2526
    2627#ifdef LOG_GROUP
     
    168169     * Do guest -> host format conversion, if needed.
    169170     * On X11 this already maps to the Xdnd protocol.
    170      ** @todo What about MacOS X Carbon Drag Manager?
     171     ** @todo What about the MacOS Carbon Drag Manager? Needs testing.
    171172     *
    172173     * See: https://www.iana.org/assignments/media-types/media-types.xhtml
     
    176177    for (int i = 0; i < vecFmtGuest.size(); i++)
    177178    {
    178         const QString &strFmt = vecFmtGuest.at(i);
     179        const QString &strFmtGuest = vecFmtGuest.at(i);
    179180        LogFlowFunc(("\tFormat %d: %s\n", i,
    180                      strFmt.toAscii().constData()));
     181                     strFmtGuest.toAscii().constData()));
    181182#ifdef RT_OS_WINDOWS
    182         if (   strFmt.contains("text", Qt::CaseInsensitive)
     183        /* CF_TEXT */
     184        if (   strFmtGuest.contains("text/plain", Qt::CaseInsensitive)
    183185            && !lstFmtNative.contains("text/plain"))
    184186        {
    185187            lstFmtNative << "text/plain";
    186188        }
     189        /* CF_HDROP */
     190        else if (   strFmtGuest.contains("text/uri-list", Qt::CaseInsensitive)
     191                 && !lstFmtNative.contains("text/uri-list"))
     192        {
     193            lstFmtNative << "text/uri-list";
     194        }
    187195#else
    188         lstFmtNative << strFmt;
     196        /* On non-Windows just do a 1:1 mapping. */
     197        lstFmtNative << strFmtGuest;
     198# ifdef RT_OS_MACOS
     199        /** @todo Does the mapping apply here? Don't think so ... */
     200# endif
    189201#endif
    190202    }
     
    204216
    205217            /* pMData is transfered to the QDrag object, so no need for deletion. */
    206             UIDnDMimeData *pMData = new UIDnDMimeData(session, lstFmtNative,
     218            pMData = new UIDnDMimeData(session, lstFmtNative,
    207219                                                      toQtDnDAction(defaultAction),
    208220                                                      toQtDnDActions(vecActions), pParent);
     221
     222            /* Inform this object that MIME data from the guest is available so that
     223             * it can update the MIME data object accordingly. */
     224            connect(pMData, SIGNAL(sigDataAvailable(QString)),
     225                    this, SLOT(sltDataAvailable(QString)), Qt::DirectConnection);
    209226
    210227            /* Inform the MIME data object of any changes in the current action. */
     
    218235             * is finished. */
    219236            pDrag->setMimeData(pMData);
    220             pDrag->exec(toQtDnDActions(vecActions), toQtDnDAction(defaultAction));
    221 
     237            Qt::DropAction dropAction =
     238                 pDrag->exec(toQtDnDActions(vecActions), toQtDnDAction(defaultAction));
     239            LogFlowFunc(("dropAction=%ld\n", toVBoxDnDAction(dropAction)));
     240#ifdef RT_OS_WINDOWS
     241            /* Since the QDrag::exec() call above was blocking on Windows, decide what
     242             * to do now, e.g. if there was a "drop" action.
     243             *
     244             * Note: The UIDnDMimeData object will not be not accessible here anymore,
     245             *       since QDrag had its ownership and deleted it after the (blocking)
     246             *       QDrag::exec() call. */
     247#endif
    222248            rc = VINF_SUCCESS;
    223249        }
     
    310336}
    311337
     338void UIDnDHandler::sltDataAvailable(const QString &mimeType)
     339{
     340    LogFlowFunc(("pMData=0x%p, mimeType=%s\n",
     341                 pMData, mimeType.toAscii().constData()));
     342
     343    if (pMData)
     344        pMData->setData(mimeType);
     345}
     346
    312347#include "UIDnDHandler.moc"
    313348
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDHandler.h

    r50265 r50305  
    2424#include "COMEnums.h"
    2525
    26 /* Forward declarations. */
     26/* Forward declarations: */
    2727class QMimeData;
    2828class CSession;
    2929class CGuest;
     30class UIDnDMimeData;
    3031
    31 /** @todo Check for making this a full static class when possible. */
    3232class UIDnDHandler: public QObject
    3333{
     34    Q_OBJECT;
     35
    3436public:
    3537    /* Singleton factory. */
     
    5860    int            dragGHPending(CSession &session, ulong screenId, QWidget *pParent = NULL);
    5961
     62public slots:
     63
     64    void sltDataAvailable(const QString &mimetype);
     65
    6066private:
    6167    static UIDnDHandler *m_pInstance;
     
    7076    static Qt::DropActions             toQtDnDActions(const QVector<KDragAndDropAction> &vecActions);
    7177
     78    UIDnDMimeData *pMData;
     79
    7280    friend class UIDnDMimeData;
    7381};
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDMIMEData.cpp

    r50265 r50305  
    2424#include <QStringList>
    2525#include <QTimer>
     26#include <QUrl>
    2627
    2728#ifdef LOG_GROUP
     
    107108                                     QVariant::Type type) const
    108109{
    109     LogFlowFunc(("m_enmState=%d, mimeType=%s, type=%d\n",
    110                  m_enmState, mimeType.toStdString().c_str(), type));
     110    LogFlowFunc(("m_enmState=%d, mimeType=%s, type=%d (%s)\n",
     111                 m_enmState, mimeType.toStdString().c_str(),
     112                 type, QVariant::typeToName(type)));
    111113
    112114    bool fCanDrop = true;
     
    132134     * So just update our internal state to reflect the same as on other
    133135     * platforms. */
    134     m_enmState = Dropped;
     136    fCanDrop = true;
    135137#else
    136138    /* Mouse button released? See eventFilter for more information. */
     
    139141#endif
    140142
    141 #if defined (RT_OS_WINDOWS) || defined (RT_OS_MACOS)
    142     /* Special MIME handling. Later. */
    143 #endif
    144 
    145143    /* Do we support the requested MIME type? */
    146144    if (   fCanDrop
     
    154152    /* Supported types. See below in the switch statement. */
    155153    if (   fCanDrop
    156         && !(   /* Regular text. */
     154        && !(
     155             /* Plain text. */
    157156                type == QVariant::String
    158157             /* Binary data. */
     
    170169        LogFlowFunc(("Skipping request, m_enmState=%d ...\n",
    171170                     m_enmState));
    172         return QVariant();
    173     }
    174 
    175     CGuest guest = m_session.GetConsole().GetGuest();
    176     /* Start getting the data from the guest. First inform the guest we
    177      * want the data in the specified MIME type. */
    178     CProgress progress = guest.DragGHDropped(mimeType,
    179                                              UIDnDHandler::toVBoxDnDAction(m_defAction));
    180     if (guest.isOk())
    181     {
    182         msgCenter().showModalProgressDialog(progress,
    183                                             tr("Retrieving data ..."), ":/progress_dnd_gh_90px.png",
    184                                             m_pParent);
    185         if (!progress.GetCanceled())
    186         {
    187             if (   progress.isOk()
    188                 && progress.GetResultCode() == 0)
    189             {
    190                 /** @todo What about retrieving bigger files? Loop? */
    191 
    192                 /* After the data successfully arrived from the guest, we query it from Main. */
    193                 QVector<uint8_t> data = guest.DragGHGetData();
    194                 if (!data.isEmpty())
     171        return QMimeData::retrieveData(mimeType, type);
     172    }
     173
     174    if (m_enmState == Dragging)
     175    {
     176        int rc = VINF_SUCCESS;
     177
     178        CGuest guest = m_session.GetConsole().GetGuest();
     179        /* Start getting the data from the guest. First inform the guest we
     180         * want the data in the specified MIME type. */
     181        CProgress progress = guest.DragGHDropped(mimeType,
     182                                                 UIDnDHandler::toVBoxDnDAction(m_defAction));
     183        if (guest.isOk())
     184        {
     185            msgCenter().showModalProgressDialog(progress,
     186                                                tr("Retrieving data ..."), ":/progress_dnd_gh_90px.png",
     187                                                m_pParent);
     188            if (!progress.GetCanceled())
     189            {
     190                if (   progress.isOk()
     191                    && progress.GetResultCode() == 0)
    195192                {
    196                     switch (type)
     193                    /** @todo What about retrieving bigger files? Loop? */
     194
     195                    /* After the data successfully arrived from the guest, we query it from Main. */
     196                    QVector<uint8_t> data = guest.DragGHGetData();
     197                    if (!data.isEmpty())
    197198                    {
    198                         case QVariant::String:
     199                        switch (type)
    199200                        {
    200                             m_data = QVariant(QString(reinterpret_cast<const char*>(data.data())));
    201                             break;
     201                            case QVariant::String:
     202                            {
     203                                m_data = QVariant(QString(reinterpret_cast<const char*>(data.data())));
     204                                break;
     205                            }
     206
     207                            case QVariant::ByteArray:
     208                            {
     209                                QByteArray ba(reinterpret_cast<const char*>(data.constData()), data.size());
     210                                m_data = QVariant(ba);
     211                                break;
     212                            }
     213
     214                            case QVariant::List:
     215                            {
     216                                QString strData = QString(reinterpret_cast<const char*>(data.data()));
     217                                QStringList lstString = strData.split("\r\n", QString::SkipEmptyParts);
     218
     219                                m_data = QVariant(lstString);
     220                                break;
     221                            }
     222
     223                            default:
     224                                AssertMsgFailed(("Should never happen, d'oh!\n"));
     225                                rc = VERR_NOT_SUPPORTED;
     226                                break;
    202227                        }
    203 
    204                         case QVariant::ByteArray:
    205                         {
    206                             QByteArray ba(reinterpret_cast<const char*>(data.constData()), data.size());
    207                             m_data = QVariant(ba);
    208                             break;
    209                         }
    210 
    211                         case QVariant::List:
    212                         {
    213                             /** @todo Support URIs. */
    214                             break;
    215                         }
    216 
    217                         default:
    218                             AssertMsgFailed(("Should never happen, d'oh!\n"));
    219                             break;
    220228                    }
     229                    /** @todo How often to retry on empty data received? */
     230
     231                    if (RT_SUCCESS(rc))
     232                        emit sigDataAvailable(mimeType);
     233
     234                    m_enmState = DataRetrieved;
    221235                }
    222                 /** @todo How often to retry on empty data received? */
    223 
    224                 m_enmState = Finished;
     236                else
     237                    msgCenter().cannotDropData(progress, m_pParent);
    225238            }
    226239            else
    227                 msgCenter().cannotDropData(progress, m_pParent);
     240                m_enmState = Canceled;
    228241        }
    229242        else
    230             m_enmState = Canceled;
    231     }
    232     else
    233         msgCenter().cannotDropData(guest, m_pParent);
    234 
     243            msgCenter().cannotDropData(guest, m_pParent);
     244    }
     245
     246    //return QMimeData::retrieveData(mimeType, type);
    235247    return m_data;
    236248}
     
    288300#endif /* RT_OS_WINDOWS */
    289301
     302int UIDnDMimeData::setData(const QString &mimeType)
     303{
     304    LogFlowFunc(("mimeType=%s, dataType=%s\n",
     305                 mimeType.toAscii().constData(), m_data.typeName()));
     306
     307    int rc = VINF_SUCCESS;
     308
     309    switch (m_data.type())
     310    {
     311        case QVariant::String: /* Plain text. */
     312        {
     313            QMimeData::setText(m_data.toString());
     314            break;
     315        }
     316
     317        case QVariant::ByteArray: /* Raw byte data. */
     318        {
     319            QMimeData::setData(mimeType, m_data.toByteArray());
     320            break;
     321        }
     322
     323        case QVariant::StringList: /* URI. */
     324        {
     325            QList<QVariant> lstData = m_data.toList();
     326            QList<QUrl> lstURL;
     327            for (int i = 0; i < lstData.size(); i++)
     328            {
     329                QString strURL = lstData.at(i).toString();
     330                LogFlowFunc(("\tURL: %s\n",
     331                             strURL.toAscii().constData()));
     332                lstURL << QUrl(strURL.toAscii());
     333            }
     334            LogFlowFunc(("Number of URLs: %d\n",  lstURL.size()));
     335
     336            QMimeData::setUrls(f);
     337            break;
     338        }
     339
     340        default:
     341            rc = VERR_NOT_SUPPORTED;
     342            break;
     343    }
     344
     345    LogFlowFuncLeaveRC(rc);
     346    return rc;
     347}
     348
     349#include "UIDnDMIMEData.moc"
     350
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDMIMEData.h

    r50265 r50305  
    4646    {
    4747        Dragging = 0,
     48        DataRetrieved,
    4849        Dropped,
    49         Finished,
    5050        Canceled
    5151    };
     
    5656                  Qt::DropAction defAction,
    5757                  Qt::DropActions actions, QWidget *pParent);
     58
     59    int setData(const QString &mimeType);
    5860
    5961public slots:
     
    7476#endif
    7577    /** @}  */
     78
     79signals:
     80
     81    void sigDataAvailable(const QString &mimeType) const;
    7682
    7783private slots:
Note: See TracChangeset for help on using the changeset viewer.

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