Changeset 50265 in vbox
- Timestamp:
- Jan 29, 2014 11:12:44 AM (11 years ago)
- svn:sync-xref-src-repo-rev:
- 91898
- Location:
- trunk
- Files:
-
- 2 added
- 13 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/HostServices/DragAndDropSvc.h
r49891 r50265 4 4 5 5 /* 6 * Copyright (C) 2011-201 3Oracle Corporation6 * Copyright (C) 2011-2014 Oracle Corporation 7 7 * 8 8 * This file is part of VirtualBox Open Source Edition (OSE), as … … 61 61 /** 62 62 * 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! 63 65 */ 64 66 enum eHostFn … … 82 84 83 85 /* 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. */ 85 92 HOST_DND_GH_EVT_DROPPED 86 93 }; … … 88 95 /** 89 96 * 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! 90 99 */ 91 100 enum eGuestFn 92 101 { 93 102 /** 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. 96 105 */ 97 106 GUEST_DND_GET_NEXT_HOST_MSG = 300, … … 103 112 104 113 /* 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 */ 105 119 GUEST_DND_GH_ACK_PENDING = 500, 106 120 GUEST_DND_GH_SND_DATA, … … 416 430 void *pvData; 417 431 uint32_t cbData; 418 uint32_t cbAllSize; 432 uint32_t cbAllSize; /** @todo Why is this transmitted every time? */ 419 433 } VBOXDNDCBSNDDATADATA; 420 434 typedef VBOXDNDCBSNDDATADATA *PVBOXDNDCBSNDDATADATA; -
trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.cpp
r50179 r50265 229 229 } while (RT_SUCCESS(rc)); 230 230 231 int rc2 = pThis->UnregisterAsDropTarget(); 232 if (RT_SUCCESS(rc)) 233 rc = rc2; 234 231 235 OleUninitialize(); 232 236 } … … 405 409 reset(); 406 410 407 Assert(mMode == Unknown);408 411 mMode = HG; 409 412 … … 464 467 465 468 rc = OnHgCancel(); 466 467 reset();468 469 break; 469 470 } … … 473 474 LogFlowThisFunc(("HOST_DND_GH_REQ_PENDING\n")); 474 475 #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; 479 486 #else 480 487 rc = VERR_NOT_SUPPORTED; … … 487 494 LogFlowThisFunc(("HOST_DND_GH_EVT_DROPPED\n")); 488 495 #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; 494 504 #else 495 505 rc = VERR_NOT_SUPPORTED; … … 585 595 } 586 596 else 597 { 587 598 rc = VINF_SUCCESS; 599 } 588 600 } 589 601 catch (std::bad_alloc) … … 598 610 int VBoxDnDWnd::UnregisterAsDropTarget(void) 599 611 { 612 LogFlowFuncEnter(); 613 600 614 if (!pDropTarget) /* No drop target? Bail out. */ 601 615 return VINF_SUCCESS; … … 606 620 TRUE /* fLastUnlockReleases */); 607 621 if (SUCCEEDED(hr)) 608 pDropTarget->Release(); 622 { 623 ULONG cRefs = pDropTarget->Release(); 624 625 Assert(cRefs == 0); 626 pDropTarget = NULL; 627 } 609 628 610 629 int rc = SUCCEEDED(hr) … … 652 671 */ 653 672 const RTCList<RTCString> lstAllowedMimeTypes = RTCList<RTCString>() 654 /* U ri's */673 /* URI's */ 655 674 << "text/uri-list" 656 675 /* Text */ … … 661 680 << "TEXT" 662 681 << "STRING" 663 /* OpenOffice format es */682 /* OpenOffice formats */ 664 683 << "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"" 665 684 << "application/x-openoffice-drawing;windows_formatname=\"Drawing Format\""; … … 855 874 if (RT_SUCCESS(rc)) 856 875 rc = rc2; 876 877 reset(); 857 878 858 879 return rc; … … 959 980 if (RT_SUCCESS(rc)) 960 981 { 982 AssertPtr(pDropTarget); 983 961 984 uint32_t uDefAction = DND_IGNORE_ACTION; 962 985 RTCString strFormat = "unknown"; 963 if ( pDropTarget 964 && pDropTarget->HasData()) 986 if (pDropTarget->HasData()) 965 987 { 966 988 uDefAction = DND_COPY_ACTION; … … 970 992 * with \r\n. */ 971 993 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 } 978 1000 } 979 1001 … … 985 1007 uint32_t uDefAction) 986 1008 { 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)); 989 1011 int rc; 990 1012 if (mState == Dragging) 991 1013 { 992 1014 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(); 993 1032 } 994 1033 else -
trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.h
r50177 r50265 151 151 152 152 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 155 public: 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); 158 161 159 162 protected: … … 163 166 uint32_t mClientID; 164 167 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; 167 175 }; 168 176 -
trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnDDropTarget.cpp
r50177 r50265 31 31 mClientID(UINT32_MAX), 32 32 mdwCurEffect(0), 33 mpDataObject(NULL), 34 mfHasDropData(false) 33 mpvData(NULL), 34 mcbData(0), 35 hEventDrop(NIL_RTSEMEVENT) 35 36 { 36 37 int rc = VbglR3DnDConnect(&mClientID); 38 if (RT_SUCCESS(rc)) 39 rc = RTSemEventCreate(&hEventDrop); 37 40 38 41 LogFlowFunc(("clientID=%RU32, rc=%Rrc\n", … … 42 45 VBoxDnDDropTarget::~VBoxDnDDropTarget(void) 43 46 { 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)); 47 55 } 48 56 … … 94 102 AssertPtrReturn(pdwEffect, E_INVALIDARG); 95 103 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 107 139 /* Which drop effect we're going to use? */ 108 140 /* Note: pt is not used since we don't need to differentiate within our … … 114 146 /* No or incompatible data -- so no drop effect required. */ 115 147 *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)); 120 190 return hr; 121 191 } … … 126 196 127 197 #ifdef DEBUG_andy 128 LogFlowFunc((" mfHasDropData=%RTbool, grfKeyState=0x%x, x=%ld, y=%ld\n",129 m fHasDropData, 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)); 130 200 #endif 131 201 132 if (m fHasDropData)202 if (mFormatEtc.cfFormat) 133 203 { 134 204 /* Note: pt is not used since we don't need to differentiate within our … … 150 220 { 151 221 #ifdef DEBUG_andy 152 LogFlowFunc((" mfHasDropData=%RTbool\n", mfHasDropData));222 LogFlowFunc(("cfFormat=%RI16\n", mFormatEtc.cfFormat)); 153 223 #endif 154 224 155 mpWndParent->hide(); 225 if (mpWndParent) 226 mpWndParent->hide(); 156 227 157 228 return S_OK; … … 165 236 166 237 #ifdef DEBUG 167 LogFlowFunc(("m fHasDropData=%RTbool, pDataObject=0x%p, grfKeyState=0x%x, x=%ld, y=%ld\n",168 m fHasDropData, 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)); 169 240 #endif 241 HRESULT hr = S_OK; 242 170 243 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 { 174 256 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)) 179 259 { 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 } 186 327 187 328 /* Release storage medium again. */ 188 329 ReleaseStgMedium(&stgMed); 189 330 190 fCanDrop = true; 331 if (SUCCEEDED(hr)) 332 { 333 RTSemEventSignal(hEventDrop); 334 fCanDrop = true; 335 } 191 336 } 192 337 } … … 201 346 *pdwEffect = DROPEFFECT_NONE; 202 347 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; 206 354 } 207 355 … … 235 383 } 236 384 385 void 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 399 int 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 882 882 break; 883 883 } 884 #ifdef VBOX_WITH_DRAG_AND_DROP_GH885 884 case DragAndDropSvc::HOST_DND_GH_REQ_PENDING: 886 885 { … … 905 904 break; 906 905 } 907 #endif /* VBOX_WITH_DRAG_AND_DROP_GH */908 906 default: 909 AssertMsgFailedReturn(("Message %u isn't expected in this context", uMsg), 910 VERR_INVALID_PARAMETER); 907 rc = VERR_NOT_SUPPORTED; 911 908 break; 912 909 } … … 944 941 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_REQ_DATA; 945 942 Msg.hdr.cParms = 1; 943 /* Initialize parameter */ 944 Msg.pFormat.SetPtr((void*)pcszFormat, (uint32_t)strlen(pcszFormat) + 1); 946 945 /* Do request */ 947 Msg.pFormat.SetPtr((void*)pcszFormat, (uint32_t)strlen(pcszFormat) + 1);948 946 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg)); 949 947 if (RT_SUCCESS(rc)) … … 968 966 Msg.uDefAction.SetUInt32(uDefAction); 969 967 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); 971 969 /* Do request */ 972 970 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg)); … … 982 980 AssertReturn(cbData, VERR_INVALID_PARAMETER); 983 981 984 /* Todo:URI support. Currently only data is send over to the host. For URI985 * support basically the same as in the H->G case (see986 * HostServices/DragAndDrop/dndmanager.h/cpp) has to be done:987 * 1. Parse the urilist988 * 2. Recursively send "create dir" and "transfer file" msg to the host989 * 3. Patch the urilist by removing all base dirnames990 * 4. On the host all needs to received and the urilist patched afterwards991 * to point to the new location982 /** @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 992 990 */ 993 991 … … 999 997 Msg.hdr.cParms = 2; 1000 998 Msg.uSize.SetUInt32(cbData); 999 1001 1000 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) 1005 1005 { 1006 1006 /* Initialize parameter */ 1007 uint32_t cbToSend = RT_MIN(cbData - cbSen d, cbMax);1008 Msg.pData.SetPtr(static_cast<uint8_t*>(pvData) + cbSen d, cbToSend);1007 uint32_t cbToSend = RT_MIN(cbData - cbSent, cbMax); 1008 Msg.pData.SetPtr(static_cast<uint8_t*>(pvData) + cbSent, cbToSend); 1009 1009 /* Do request */ 1010 1010 rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg)); … … 1018 1018 else 1019 1019 break; 1020 cbSen d+= cbToSend;1020 cbSent += cbToSend; 1021 1021 // RTThreadSleep(500); 1022 1022 } -
trunk/src/VBox/Additions/x11/VBoxClient/draganddrop.cpp
r49891 r50265 498 498 XDestroyWindow(m_pDisplay, m_wndProxy); 499 499 500 if (m_uClientID) 500 if (m_uClientID) 501 501 { 502 502 VbglR3DnDDisconnect(m_uClientID); … … 1613 1613 1614 1614 m_pCurDnD = new DragInstance(m_pDisplay, this); 1615 if (!m_pCurDnD) 1615 if (!m_pCurDnD) 1616 1616 { 1617 1617 rc = VERR_NO_MEMORY; … … 1829 1829 } 1830 1830 1831 /* Number of invalid messages skipped in a row. */ 1832 int cMsgSkippedInvalid = 0; 1833 1831 1834 do 1832 1835 { … … 1837 1840 if (RT_SUCCESS(rc)) 1838 1841 { 1842 cMsgSkippedInvalid = 0; /* Reset skipped messages count. */ 1843 1839 1844 pThis->m_eventQueue.append(e); 1840 1845 rc = RTSemEventSignal(pThis->m_hEventSem); … … 1842 1847 return rc; 1843 1848 } 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 1844 1863 } while (!ASMAtomicReadBool(&pThis->m_fSrvStopping)); 1845 1864 -
trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk
r50191 r50265 5 5 6 6 # 7 # Copyright (C) 2006-201 3Oracle Corporation7 # Copyright (C) 2006-2014 Oracle Corporation 8 8 # 9 9 # This file is part of VirtualBox Open Source Edition (OSE), as … … 176 176 ./src/net 177 177 endif 178 178 179 179 VirtualBox_INCS = \ 180 180 $(VBOX_GUI_INC_DIRS) \ … … 390 390 src/widgets/VBoxOSTypeSelectorButton.h \ 391 391 src/widgets/UINameAndSystemEditor.h \ 392 392 src/widgets/UIWarningPane.h \ 393 393 src/widgets/UIFilmContainer.h \ 394 394 src/widgets/graphics/UIGraphicsButton.h \ … … 433 433 434 434 ifdef VBOX_GUI_WITH_NETWORK_MANAGER 435 VirtualBox_QT_MOCHDRS += \435 VirtualBox_QT_MOCHDRS += \ 436 436 src/net/UINetworkManager.h \ 437 437 src/net/UINetworkManagerDialog.h \ … … 448 448 src/settings/global/UIGlobalSettingsProxy.h \ 449 449 src/settings/global/UIGlobalSettingsUpdate.h 450 endif 451 452 ifdef VBOX_WITH_DRAG_AND_DROP 453 ifdef VBOX_WITH_DRAG_AND_DROP_GH 454 VirtualBox_QT_MOCHDRS += \ 455 src/runtime/UIDnDMIMEData.h 456 endif 450 457 endif 451 458 … … 477 484 478 485 ifdef VBOX_GUI_WITH_NETWORK_MANAGER 479 VirtualBox_QT_MOCSRCS += \486 VirtualBox_QT_MOCSRCS += \ 480 487 src/net/UINetworkReply.cpp \ 481 488 src/net/UIUpdateManager.cpp 489 endif 490 491 ifdef VBOX_WITH_DRAG_AND_DROP 492 ifdef VBOX_WITH_DRAG_AND_DROP_GH 493 VirtualBox_QT_MOCSRCS += \ 494 src/runtime/UIDnDMIMEData.cpp 495 endif 482 496 endif 483 497 … … 763 777 VirtualBox_QT_MOCSRCS += \ 764 778 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 765 785 endif 766 786 -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDHandler.cpp
r49891 r50265 7 7 8 8 /* 9 * Copyright (C) 2011-201 3Oracle Corporation9 * Copyright (C) 2011-2014 Oracle Corporation 10 10 * 11 11 * This file is part of VirtualBox Open Source Edition (OSE), as … … 21 21 #include <QApplication> 22 22 #include <QKeyEvent> 23 #include <QMimeData>24 23 #include <QStringList> 25 24 #include <QTimer> … … 33 32 /* GUI includes: */ 34 33 #include "UIDnDHandler.h" 34 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 35 # include "UIDnDMIMEData.h" 36 #endif 35 37 #include "UIMessageCenter.h" 36 38 … … 40 42 #include "CGuest.h" 41 43 42 UIDnDHandler *UIDnDHandler::m_pInstance = 0;43 44 UIDnDHandler::UIDnDHandler( )44 UIDnDHandler *UIDnDHandler::m_pInstance = NULL; 45 46 UIDnDHandler::UIDnDHandler(void) 45 47 { 46 48 } … … 50 52 */ 51 53 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 */) 54 Qt::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 */) 53 57 { 54 58 LogFlowFunc(("screenId=%RU32, x=%d, y=%d, action=%ld\n", … … 66 70 } 67 71 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 */) 72 Qt::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 */) 69 75 { 70 76 #ifdef DEBUG_andy … … 85 91 } 86 92 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 */) 93 Qt::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 */) 88 96 { 89 97 LogFlowFunc(("screenId=%RU32, x=%d, y=%d, action=%ld\n", … … 132 140 } 133 141 134 void UIDnDHandler::dragHGLeave(CGuest &guest, ulong screenId, QWidget * /* pParent = 0*/)142 void UIDnDHandler::dragHGLeave(CGuest &guest, ulong screenId, QWidget * /* pParent = NULL */) 135 143 { 136 144 LogFlowFunc(("screenId=%RU32\n", screenId)); … … 138 146 } 139 147 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 { 148 int UIDnDHandler::dragGHPending(CSession &session, ulong screenId, QWidget *pParent /* = NULL */) 149 { 150 int rc; 151 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 281 152 /* 282 153 * How this works: Host is asking the guest if there is any DnD … … 289 160 */ 290 161 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 294 197 295 198 if ( defaultAction != KDragAndDropAction_Ignore 296 && ! formats.isEmpty())199 && !lstFmtNative.isEmpty()) 297 200 { 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 } 307 228 } 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; 308 237 } 309 238 … … 341 270 Qt::DropAction UIDnDHandler::toQtDnDAction(KDragAndDropAction action) 342 271 { 272 Qt::DropAction dropAct = Qt::IgnoreAction; 343 273 if (action == KDragAndDropAction_Copy) 344 returnQt::CopyAction;274 dropAct = Qt::CopyAction; 345 275 if (action == KDragAndDropAction_Move) 346 returnQt::MoveAction;276 dropAct = Qt::MoveAction; 347 277 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 284 Qt::DropActions UIDnDHandler::toQtDnDActions(const QVector<KDragAndDropAction> &vecActions) 285 { 286 Qt::DropActions dropActs = Qt::IgnoreAction; 287 for (int i = 0; i < vecActions.size(); i++) 357 288 { 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; 364 305 } 365 306 } 366 return a; 307 308 LogFlowFunc(("dropActions=0x%x\n", dropActs)); 309 return dropActs; 367 310 } 368 311 -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDHandler.h
r44529 r50265 1 /* $Id$ */ 1 2 /** @file 2 3 * … … 6 7 7 8 /* 8 * Copyright (C) 2011-201 2Oracle Corporation9 * Copyright (C) 2011-2014 Oracle Corporation 9 10 * 10 11 * This file is part of VirtualBox Open Source Edition (OSE), as … … 23 24 #include "COMEnums.h" 24 25 25 /* Forward declarations :*/26 /* Forward declarations. */ 26 27 class QMimeData; 27 28 class CSession; 28 29 class CGuest; 29 30 30 /* Todo: check for making this a full static class when possible. */31 /** @todo Check for making this a full static class when possible. */ 31 32 class UIDnDHandler: public QObject 32 33 { 33 34 public: 34 /* Singleton */35 static UIDnDHandler* instance( )35 /* Singleton factory. */ 36 static UIDnDHandler* instance(void) 36 37 { 37 38 if (!m_pInstance) … … 39 40 return m_pInstance; 40 41 } 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 } 42 50 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); 48 56 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); 51 59 52 60 private: 53 61 static UIDnDHandler *m_pInstance; 54 62 55 UIDnDHandler( );56 ~UIDnDHandler() {}63 UIDnDHandler(void); 64 virtual ~UIDnDHandler(void) {} 57 65 58 /* Private helpers */66 /* Private helpers. */ 59 67 static KDragAndDropAction toVBoxDnDAction(Qt::DropAction action); 60 68 static QVector<KDragAndDropAction> toVBoxDnDActions(Qt::DropActions actions); 61 69 static Qt::DropAction toQtDnDAction(KDragAndDropAction action); 62 static Qt::DropActions toQtDnDActions(const QVector<KDragAndDropAction> & actions);70 static Qt::DropActions toQtDnDActions(const QVector<KDragAndDropAction> &vecActions); 63 71 64 72 friend class UIDnDMimeData; -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineView.cpp
r50248 r50265 1169 1169 } 1170 1170 1171 void UIMachineView::handleGHDnd( )1171 void UIMachineView::handleGHDnd(void) 1172 1172 { 1173 1173 /* The guest object to talk to. */ -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMouseHandler.cpp
r48950 r50265 907 907 || cpnt.y() > iCh - 1) 908 908 { 909 if ((mouseButtons.testFlag(Qt::LeftButton))) 909 bool fHandledGHDnD 910 = RT_BOOL(mouseButtons.testFlag(Qt::LeftButton)); 911 if (fHandledGHDnD) 910 912 { 911 913 m_views[uScreenId]->handleGHDnd(); 912 913 return false; 914 return true; 914 915 } 915 916 } -
trunk/src/VBox/HostServices/DragAndDrop/service.cpp
r49891 r50265 5 5 6 6 /* 7 * Copyright (C) 2011-201 3Oracle Corporation7 * Copyright (C) 2011-2014 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 177 177 switch (u32Function) 178 178 { 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. */ 179 184 case DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG: 180 185 { -
trunk/src/VBox/Main/src-client/GuestDnDImpl.cpp
r49891 r50265 5 5 6 6 /* 7 * Copyright (C) 2011-201 3Oracle Corporation7 * Copyright (C) 2011-2014 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 167 167 class DnDGuestResponse 168 168 { 169 169 170 public: 171 170 172 DnDGuestResponse(const ComObjPtr<Guest>& pGuest); 171 ~DnDGuestResponse(); 172 173 int notifyAboutGuestResponse(); 174 int waitForGuestResponse(); 173 174 virtual ~DnDGuestResponse(void); 175 176 public: 177 178 int notifyAboutGuestResponse(void); 179 int waitForGuestResponse(RTMSINTERVAL msTimeout = 500); 175 180 176 181 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; } 178 183 179 184 void setAllActions(uint32_t a) { m_allActions = a; } … … 181 186 182 187 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 reset Data();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; } 189 194 190 195 int setProgress(unsigned uPercentage, uint32_t uState, int rcOp = VINF_SUCCESS); … … 213 218 , m_pDnDResponse(new DnDGuestResponse(pGuest)) 214 219 {} 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; } 218 223 219 224 void adjustCoords(ULONG uScreenId, ULONG *puX, ULONG *puY) const; … … 274 279 DnDGuestResponse::~DnDGuestResponse() 275 280 { 276 reset Data();281 reset(); 277 282 int rc = RTSemEventDestroy(m_EventSem); 278 283 AssertRC(rc); … … 284 289 } 285 290 286 int DnDGuestResponse::waitForGuestResponse( )287 { 288 int vrc = RTSemEventWait(m_EventSem, 300);291 int DnDGuestResponse::waitForGuestResponse(RTMSINTERVAL msTimeout /*= 500 */) 292 { 293 int vrc = RTSemEventWait(m_EventSem, msTimeout); 289 294 #ifdef DEBUG_andy 290 LogFlowFunc((" rc=%Rrc\n", vrc));295 LogFlowFunc(("msTimeout=%RU32, rc=%Rrc\n", msTimeout, vrc)); 291 296 #endif 292 297 return vrc; 293 298 } 294 299 295 int DnDGuestResponse:: addData(void *pvData, uint32_t cbData, uint32_t *pcbCurSize)300 int DnDGuestResponse::dataAdd(void *pvData, uint32_t cbData, uint32_t *pcbCurSize) 296 301 { 297 302 int rc = VINF_SUCCESS; 303 304 /** @todo Make reallocation scheme a bit smarter here. */ 298 305 m_pvData = RTMemRealloc(m_pvData, m_cbData + cbData); 299 306 if (m_pvData) 300 307 { 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; 304 314 } 305 315 else … … 309 319 } 310 320 311 void DnDGuestResponse::reset Data()321 void DnDGuestResponse::reset(void) 312 322 { 313 323 if (m_pvData) … … 316 326 m_pvData = NULL; 317 327 } 328 318 329 m_cbData = 0; 319 330 } … … 747 758 } 748 759 749 HRESULT GuestDnD::dragHGPutData(ULONG uScreenId, IN_BSTR bstrFormat, ComSafeArrayIn(BYTE, data), IProgress **ppProgress) 760 HRESULT GuestDnD::dragHGPutData(ULONG uScreenId, IN_BSTR bstrFormat, 761 ComSafeArrayIn(BYTE, data), IProgress **ppProgress) 750 762 { 751 763 DPTR(GuestDnD); … … 786 798 } 787 799 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 801 HRESULT GuestDnD::dragGHPending(ULONG uScreenId, 802 ComSafeArrayOut(BSTR, formats), 803 ComSafeArrayOut(DragAndDropAction_T, allowedActions), 804 DragAndDropAction_T *pDefaultAction) 790 805 { 791 806 DPTR(GuestDnD); … … 821 836 /* Convert the action bit field to a vector of actions. */ 822 837 d->toMainActions(pDnD->allActions(), ComSafeArrayOutArg(allowedActions)); 838 839 LogFlowFunc(("*pDefaultAction=0x%x\n", *pDefaultAction)); 823 840 } 824 841 catch (HRESULT rc2) … … 830 847 } 831 848 832 HRESULT GuestDnD::dragGHDropped(IN_BSTR bstrFormat, DragAndDropAction_T action, IProgress **ppProgress) 849 HRESULT GuestDnD::dragGHDropped(IN_BSTR bstrFormat, DragAndDropAction_T action, 850 IProgress **ppProgress) 833 851 { 834 852 DPTR(GuestDnD); … … 845 863 try 846 864 { 865 LogFlowFunc(("strFormat=%s, uAction=0x%x\n", strFormat.c_str(), uAction)); 866 847 867 VBOXHGCMSVCPARM paParms[3]; 848 868 int i = 0; … … 853 873 DnDGuestResponse *pDnD = d->response(); 854 874 /* Reset any old data and the progress status. */ 855 pDnD->reset Data();875 pDnD->reset(); 856 876 pDnD->resetProgress(p); 857 877 … … 879 899 880 900 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. */ 890 920 sfaData.detachTo(ComSafeArrayOutArg(data)); 921 891 922 /* Delete the data. */ 892 pDnD->reset Data();923 pDnD->reset(); 893 924 } 894 925 else … … 897 928 return rc; 898 929 } 899 900 # endif /* VBOX_WITH_DRAG_AND_DROP_GH */ 930 #endif /* VBOX_WITH_DRAG_AND_DROP_GH */ 901 931 902 932 DECLCALLBACK(int) GuestDnD::notifyGuestDragAndDropEvent(void *pvExtension, uint32_t u32Function, void *pvParms, uint32_t cbParms) … … 929 959 break; 930 960 } 961 931 962 case DragAndDropSvc::GUEST_DND_HG_REQ_DATA: 932 963 { … … 939 970 break; 940 971 } 972 941 973 case DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS: 942 974 { … … 948 980 break; 949 981 } 982 950 983 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 951 984 case DragAndDropSvc::GUEST_DND_GH_ACK_PENDING: … … 961 994 break; 962 995 } 996 963 997 case DragAndDropSvc::GUEST_DND_GH_SND_DATA: 964 998 { … … 967 1001 AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDDATADATA) == cbParms, VERR_INVALID_PARAMETER); 968 1002 AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER); 1003 969 1004 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 } 972 1026 /* Todo: for now we instantly confirm the cancel. Check if the 973 1027 * guest should first clean up stuff itself and than really confirm … … 977 1031 break; 978 1032 } 1033 979 1034 case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR: 980 1035 { … … 983 1038 AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBEVTERRORDATA) == cbParms, VERR_INVALID_PARAMETER); 984 1039 AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_EVT_ERROR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER); 1040 985 1041 /* Cleanup */ 986 pResp->reset Data();1042 pResp->reset(); 987 1043 rc = pResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_ERROR, pCBData->rc); 988 1044 break; … … 990 1046 #endif /* VBOX_WITH_DRAG_AND_DROP_GH */ 991 1047 default: 992 AssertMsgFailedReturn(("Function %RU32 not supported\n", u32Function), VERR_NOT_SUPPORTED);1048 rc = VERR_NOT_SUPPORTED; /* Tell the guest. */ 993 1049 break; 994 1050 }
Note:
See TracChangeset
for help on using the changeset viewer.