Changeset 50305 in vbox
- Timestamp:
- Feb 3, 2014 10:47:45 AM (11 years ago)
- Location:
- trunk
- Files:
-
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/HostServices/DragAndDropSvc.h
r50265 r50305 68 68 HOST_DND_SET_MODE = 100, 69 69 70 /* H->G */ 70 /* 71 * Host -> Guest messages 72 */ 73 71 74 HOST_DND_HG_EVT_ENTER = 200, 72 75 HOST_DND_HG_EVT_MOVE, … … 78 81 HOST_DND_HG_SND_DATA, 79 82 /** 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. */ 81 84 HOST_DND_HG_SND_MORE_DATA, 85 /** Directory entry to be handled on the guest. */ 82 86 HOST_DND_HG_SND_DIR, 87 /** File entry to be handled on the guest. */ 83 88 HOST_DND_HG_SND_FILE, 84 89 85 /* G->H */ 90 /* 91 * Guest -> Host messages 92 */ 93 86 94 /** The host asks the guest whether a DnD operation 87 95 * is in progress when the mouse leaves the guest window. */ … … 90 98 * has been started and that the host wants the data in 91 99 * 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 93 104 }; 94 105 … … 107 118 108 119 /* 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. */ 109 123 GUEST_DND_HG_ACK_OP = 400, 124 /** The guest requests the actual DnD data to be sent 125 * from the host. */ 110 126 GUEST_DND_HG_REQ_DATA, 111 127 GUEST_DND_HG_EVT_PROGRESS, … … 119 135 GUEST_DND_GH_ACK_PENDING = 500, 120 136 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 122 141 }; 123 142 -
trunk/include/VBox/VBoxGuestLib.h
r49891 r50305 4 4 5 5 /* 6 * Copyright (C) 2006-201 3Oracle Corporation6 * Copyright (C) 2006-2014 Oracle Corporation 7 7 * 8 8 * This file is part of VirtualBox Open Source Edition (OSE), as … … 722 722 VBGLR3DECL(int) VbglR3DnDHGRequestData(uint32_t u32ClientId, const char* pcszFormat); 723 723 # ifdef VBOX_WITH_DRAG_AND_DROP_GH 724 VBGLR3DECL(int) VbglR3DnDGHAcknowledgePending(uint32_t u32ClientId, uint32_t uDefAction, uint32_t uAllActions, const char* pcszFormat );724 VBGLR3DECL(int) VbglR3DnDGHAcknowledgePending(uint32_t u32ClientId, uint32_t uDefAction, uint32_t uAllActions, const char* pcszFormats); 725 725 VBGLR3DECL(int) VbglR3DnDGHSendData(uint32_t u32ClientId, void *pvData, uint32_t cbData); 726 726 VBGLR3DECL(int) VbglR3DnDGHErrorEvent(uint32_t u32ClientId, int rcOp); -
trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.cpp
r50266 r50305 515 515 reset(); 516 516 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; 517 553 #else 518 554 rc = VERR_NOT_SUPPORTED; … … 934 970 #endif 935 971 936 #if 1937 972 /** @todo Multi-monitor setups? */ 938 973 int iScreenX = GetSystemMetrics(SM_CXSCREEN) - 1; … … 963 998 else 964 999 LogFlowFunc(("Unable to send input, error=0x%x\n", GetLastError())); 965 #else966 SetCursorPos(p.x, p.y);967 #endif968 1000 969 1001 #ifdef DEBUG_andy … … 981 1013 if (RT_SUCCESS(rc)) 982 1014 { 1015 uint32_t uDefAction = DND_IGNORE_ACTION; 1016 983 1017 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()) 988 1020 { 989 1021 uDefAction = DND_COPY_ACTION; 990 1022 uAllActions = uDefAction; 991 1023 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())); 998 1026 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")); 1001 1031 } 1002 1032 … … 1008 1038 uint32_t uDefAction) 1009 1039 { 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 1012 1055 int rc; 1013 1056 if (mState == Dragging) 1014 1057 { 1015 1058 AssertPtr(pDropTarget); 1016 rc = pDropTarget->WaitForDrop(30 * 1000 /* Timeout */);1059 rc = pDropTarget->WaitForDrop(30 * 1000 /* Timeout in ms */); 1017 1060 if (RT_SUCCESS(rc)) 1018 1061 { … … 1035 1078 rc = VERR_WRONG_ORDER; 1036 1079 1080 LogFlowFuncLeaveRC(rc); 1081 return rc; 1082 } 1083 1084 int 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 1092 int VBoxDnDWnd::OnGhSendFile(const char *pszFormats, uint32_t cbFormats, 1093 uint32_t uDefAction) 1094 { 1095 int rc = 0; 1037 1096 LogFlowFuncLeaveRC(rc); 1038 1097 return rc; -
trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.h
r50265 r50305 155 155 public: 156 156 157 bool HasData(void) { return RT_BOOL(mFormatEtc.cfFormat != 0); }158 157 void *DataMutableRaw(void) { return mpvData; } 159 158 uint32_t DataSize(void) { return mcbData; } 159 RTCString Formats(void); 160 160 int WaitForDrop(RTMSINTERVAL msTimeout); 161 161 … … 170 170 * DVTARGETDEVICE here! */ 171 171 FORMATETC mFormatEtc; 172 RTCString mFormats; 172 173 void *mpvData; 173 174 uint32_t mcbData; … … 338 339 int OnGhIsDnDPending(uint32_t uScreenID); 339 340 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); 340 343 #endif 341 344 -
trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnDDropTarget.cpp
r50265 r50305 17 17 #include <windows.h> 18 18 #include <new> /* For bad_alloc. */ 19 #include <Shlobj.h> /* For DROPFILES and friends. */ 19 20 20 21 #include "VBoxTray.h" … … 107 108 reset(); 108 109 110 /** @todo At the moment we only support one DnD format at a time. */ 111 109 112 /* Try different formats. CF_HDROP is the most common one, so start 110 113 * with this. */ 111 /** @todo At the moment we only support TYMED_HGLOBAL. */112 114 FORMATETC fmtEtc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; 113 115 HRESULT hr = pDataObject->QueryGetData(&fmtEtc); 114 if (hr != S_OK) 116 if (hr == S_OK) 117 { 118 mFormats = "text/uri-list"; 119 } 120 else 115 121 { 116 122 LogFlowFunc(("CF_HDROP not supported, hr=%Rhrc\n", hr)); … … 125 131 fmtEtc.cfFormat = 0; /* Mark it to not supported. */ 126 132 } 133 else 134 { 135 mFormats = "text/plain;charset=utf-8"; 136 } 127 137 } 128 138 … … 130 140 if (fmtEtc.cfFormat) 131 141 { 132 LogFlowFunc(("Found supported format %RI16\n", fmtEtc.cfFormat)); 142 LogFlowFunc(("Found supported format %RI16 (%s)\n", 143 fmtEtc.cfFormat, VBoxDnDDataObject::ClipboardFormatToString(fmtEtc.cfFormat))); 133 144 134 145 /* Make a copy of the FORMATETC structure so that we later can 135 146 * 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! */ 137 148 memcpy(&mFormatEtc, &fmtEtc, sizeof(FORMATETC)); 138 149 … … 164 175 while (pEnumFormats->Next(1, &curFormatEtc, 165 176 NULL /* pceltFetched */) == S_OK) 166 177 { 167 178 WCHAR wszCfName[128]; /* 128 chars should be enough, rest will be truncated. */ 168 179 hr2 = GetClipboardFormatNameW(curFormatEtc.cfFormat, wszCfName, 169 180 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", 171 182 curFormatEtc.cfFormat, 183 VBoxDnDDataObject::ClipboardFormatToString(curFormatEtc.cfFormat), 172 184 curFormatEtc.tymed, 173 185 curFormatEtc.dwAspect, … … 176 188 177 189 pEnumFormats->Release(); 178 190 } 179 191 180 192 break; … … 236 248 237 249 #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)); 240 253 #endif 241 254 HRESULT hr = S_OK; … … 248 261 hr = pDataObject->QueryGetData(&mFormatEtc); 249 262 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; 253 269 254 270 if (SUCCEEDED(hr)) … … 272 288 LogFlowFunc(("Locking HGLOBAL storage failed with %Rrc\n", 273 289 RTErrConvertFromWin32(GetLastError()))); 274 hr = ERROR_INVALID_HANDLE; 290 rc = VERR_INVALID_HANDLE; 291 hr = E_INVALIDARG; /* Set special hr for OLE. */ 275 292 } 276 293 break; … … 279 296 AssertMsgFailed(("Storage medium type %RI32 supported\n", 280 297 mFormatEtc.tymed)); 281 hr = ERROR_NOT_SUPPORTED; 298 rc = VERR_NOT_SUPPORTED; 299 hr = DV_E_TYMED; /* Set special hr for OLE. */ 282 300 break; 283 301 } 284 302 285 if ( SUCCEEDED(hr))303 if (RT_SUCCESS(rc)) 286 304 { 287 305 /* Second stage: Do the actual copying of the data object's data, … … 289 307 switch (mFormatEtc.cfFormat) 290 308 { 309 /* Handling CF_TEXT means that the system already did some marshalling 310 * to convert RTF or unicode text to plain ANSI text. */ 291 311 case CF_TEXT: 292 312 { 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 298 327 break; 299 328 } 300 329 301 330 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); 302 438 break; 439 } 303 440 304 441 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))); 307 445 hr = ERROR_NOT_SUPPORTED; 446 hr = DV_E_CLIPFORMAT; /* Set special hr for OLE. */ 308 447 break; 309 448 } … … 320 459 321 460 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")); 325 462 break; 326 463 } … … 329 466 ReleaseStgMedium(&stgMed); 330 467 331 if (SUCCEEDED(hr)) 468 /** @todo Signal in any case to avoid hangs/timeouts? */ 469 if (RT_SUCCESS(rc)) 332 470 { 333 471 RTSemEventSignal(hEventDrop); … … 349 487 mpWndParent->hide(); 350 488 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 353 493 return hr; 354 494 } … … 395 535 mcbData = 0; 396 536 RT_ZERO(mFormatEtc); 537 mFormats = ""; 538 } 539 540 RTCString VBoxDnDDropTarget::Formats(void) 541 { 542 return mFormats; 397 543 } 398 544 -
trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDragAndDrop.cpp
r50265 r50305 329 329 return VERR_NO_MEMORY; 330 330 331 /* Create and query the drop target directory. */331 /* Create and query the (unique) drop target directory. */ 332 332 char pszDropDir[RTPATH_MAX]; 333 333 int rc = vbglR3DnDCreateDropDir(pszDropDir, sizeof(pszDropDir)); … … 486 486 } /* while */ 487 487 488 RTMemFree(pvTmpData); 488 if (pvTmpData) 489 RTMemFree(pvTmpData); 489 490 490 491 /* Cleanup on failure or if the user has canceled. */ … … 509 510 void *pvData, 510 511 uint32_t cbData, 511 uint32_t *pcbData Recv)512 uint32_t *pcbDataTotal) 512 513 { 513 514 AssertPtrReturn(puScreenId, VERR_INVALID_POINTER); … … 517 518 AssertPtrReturn(pvData, VERR_INVALID_POINTER); 518 519 AssertReturn(cbData, VERR_INVALID_PARAMETER); 519 AssertPtrReturn(pcbData Recv,VERR_INVALID_POINTER);520 AssertPtrReturn(pcbDataTotal, VERR_INVALID_POINTER); 520 521 521 522 DragAndDropSvc::VBOXDNDHGSENDDATAMSG Msg; … … 535 536 { 536 537 rc = Msg.hdr.result; 537 if ( RT_SUCCESS(rc)538 if ( RT_SUCCESS(rc) 538 539 || rc == VERR_BUFFER_OVERFLOW) 539 540 { … … 541 542 rc = Msg.uScreenId.GetUInt32(puScreenId); AssertRC(rc); 542 543 rc = Msg.cFormat.GetUInt32(pcbFormatRecv); AssertRC(rc); 543 rc = Msg.cData.GetUInt32(pcbData Recv); AssertRC(rc);544 rc = Msg.cData.GetUInt32(pcbDataTotal); AssertRC(rc); 544 545 /* A little bit paranoia */ 545 546 AssertReturn(cbFormat >= *pcbFormatRecv, VERR_TOO_MUCH_DATA); 546 AssertReturn(cbData >= *pcbData Recv,VERR_TOO_MUCH_DATA);547 AssertReturn(cbData >= *pcbDataTotal, VERR_TOO_MUCH_DATA); 547 548 } 548 549 } … … 664 665 if (RT_SUCCESS(rc)) 665 666 { 666 /* Check if this is a uri-event. If so, let VbglR3 do all the actual667 /* Check if this is an URI event. If so, let VbglR3 do all the actual 667 668 * 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. */ 669 673 if (RTStrNICmp(pszFormat, "text/uri-list", *pcbFormatRecv) == 0) 670 674 rc = vbglR3DnDHGProcessURIMessages(uClientId, … … 953 957 VBGLR3DECL(int) VbglR3DnDGHAcknowledgePending(uint32_t u32ClientId, 954 958 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); 958 962 959 963 DragAndDropSvc::VBOXDNDGHACKPENDINGMSG Msg; … … 966 970 Msg.uDefAction.SetUInt32(uDefAction); 967 971 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); 969 973 /* Do request */ 970 974 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg)); … … 979 983 AssertPtrReturn(pvData, VERR_INVALID_POINTER); 980 984 AssertReturn(cbData, VERR_INVALID_PARAMETER); 981 982 /** @todo Add URI support. Currently only data is send over to the host. For URI983 * support basically the same as in the H->G case (see984 * HostServices/DragAndDrop/dndmanager.h/cpp) has to be done:985 * 1. Parse the urilist986 * 2. Recursively send "create dir" and "transfer file" msg to the host987 * 3. Patch the urilist by removing all base dirnames988 * 4. On the host all needs to received and the urilist patched afterwards989 * to point to the new location990 */991 985 992 986 DragAndDropSvc::VBOXDNDGHSENDDATAMSG Msg; … … 1042 1036 return rc; 1043 1037 } 1038 1039 VBGLR3DECL(int) VbglR3DnDGHSendFile(uint32_t u32ClientId, const char *pszPath) 1040 { 1041 return 0; 1042 } 1043 -
trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk
r50265 r50305 451 451 452 452 ifdef VBOX_WITH_DRAG_AND_DROP 453 VirtualBox_QT_MOCHDRS += \ 454 src/runtime/UIDnDHandler.h 453 455 ifdef VBOX_WITH_DRAG_AND_DROP_GH 454 456 VirtualBox_QT_MOCHDRS += \ -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDHandler.cpp
r50278 r50305 23 23 #include <QStringList> 24 24 #include <QTimer> 25 #include <QUrl> 25 26 26 27 #ifdef LOG_GROUP … … 168 169 * Do guest -> host format conversion, if needed. 169 170 * 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. 171 172 * 172 173 * See: https://www.iana.org/assignments/media-types/media-types.xhtml … … 176 177 for (int i = 0; i < vecFmtGuest.size(); i++) 177 178 { 178 const QString &strFmt = vecFmtGuest.at(i);179 const QString &strFmtGuest = vecFmtGuest.at(i); 179 180 LogFlowFunc(("\tFormat %d: %s\n", i, 180 strFmt .toAscii().constData()));181 strFmtGuest.toAscii().constData())); 181 182 #ifdef RT_OS_WINDOWS 182 if ( strFmt.contains("text", Qt::CaseInsensitive) 183 /* CF_TEXT */ 184 if ( strFmtGuest.contains("text/plain", Qt::CaseInsensitive) 183 185 && !lstFmtNative.contains("text/plain")) 184 186 { 185 187 lstFmtNative << "text/plain"; 186 188 } 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 } 187 195 #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 189 201 #endif 190 202 } … … 204 216 205 217 /* 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, 207 219 toQtDnDAction(defaultAction), 208 220 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); 209 226 210 227 /* Inform the MIME data object of any changes in the current action. */ … … 218 235 * is finished. */ 219 236 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 222 248 rc = VINF_SUCCESS; 223 249 } … … 310 336 } 311 337 338 void 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 312 347 #include "UIDnDHandler.moc" 313 348 -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDHandler.h
r50265 r50305 24 24 #include "COMEnums.h" 25 25 26 /* Forward declarations .*/26 /* Forward declarations: */ 27 27 class QMimeData; 28 28 class CSession; 29 29 class CGuest; 30 class UIDnDMimeData; 30 31 31 /** @todo Check for making this a full static class when possible. */32 32 class UIDnDHandler: public QObject 33 33 { 34 Q_OBJECT; 35 34 36 public: 35 37 /* Singleton factory. */ … … 58 60 int dragGHPending(CSession &session, ulong screenId, QWidget *pParent = NULL); 59 61 62 public slots: 63 64 void sltDataAvailable(const QString &mimetype); 65 60 66 private: 61 67 static UIDnDHandler *m_pInstance; … … 70 76 static Qt::DropActions toQtDnDActions(const QVector<KDragAndDropAction> &vecActions); 71 77 78 UIDnDMimeData *pMData; 79 72 80 friend class UIDnDMimeData; 73 81 }; -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDMIMEData.cpp
r50265 r50305 24 24 #include <QStringList> 25 25 #include <QTimer> 26 #include <QUrl> 26 27 27 28 #ifdef LOG_GROUP … … 107 108 QVariant::Type type) const 108 109 { 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))); 111 113 112 114 bool fCanDrop = true; … … 132 134 * So just update our internal state to reflect the same as on other 133 135 * platforms. */ 134 m_enmState = Dropped;136 fCanDrop = true; 135 137 #else 136 138 /* Mouse button released? See eventFilter for more information. */ … … 139 141 #endif 140 142 141 #if defined (RT_OS_WINDOWS) || defined (RT_OS_MACOS)142 /* Special MIME handling. Later. */143 #endif144 145 143 /* Do we support the requested MIME type? */ 146 144 if ( fCanDrop … … 154 152 /* Supported types. See below in the switch statement. */ 155 153 if ( fCanDrop 156 && !( /* Regular text. */ 154 && !( 155 /* Plain text. */ 157 156 type == QVariant::String 158 157 /* Binary data. */ … … 170 169 LogFlowFunc(("Skipping request, m_enmState=%d ...\n", 171 170 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) 195 192 { 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()) 197 198 { 198 case QVariant::String:199 switch (type) 199 200 { 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; 202 227 } 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;220 228 } 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; 221 235 } 222 /** @todo How often to retry on empty data received? */ 223 224 m_enmState = Finished; 236 else 237 msgCenter().cannotDropData(progress, m_pParent); 225 238 } 226 239 else 227 m sgCenter().cannotDropData(progress, m_pParent);240 m_enmState = Canceled; 228 241 } 229 242 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); 235 247 return m_data; 236 248 } … … 288 300 #endif /* RT_OS_WINDOWS */ 289 301 302 int 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 46 46 { 47 47 Dragging = 0, 48 DataRetrieved, 48 49 Dropped, 49 Finished,50 50 Canceled 51 51 }; … … 56 56 Qt::DropAction defAction, 57 57 Qt::DropActions actions, QWidget *pParent); 58 59 int setData(const QString &mimeType); 58 60 59 61 public slots: … … 74 76 #endif 75 77 /** @} */ 78 79 signals: 80 81 void sigDataAvailable(const QString &mimeType) const; 76 82 77 83 private slots:
Note:
See TracChangeset
for help on using the changeset viewer.