VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/GuestDnDSourceImpl.cpp@ 51476

Last change on this file since 51476 was 51476, checked in by vboxsync, 11 years ago

DnD: API overhaul; now using IDnDTarget + IDnDSource. Renamed DragAndDrop* enumerations to DnD*. Also rewrote some internal code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.3 KB
Line 
1/* $Id: GuestDnDSourceImpl.cpp 51476 2014-05-30 14:58:02Z vboxsync $ */
2/** @file
3 * VBox Console COM Class implementation - Guest drag'n drop source.
4 */
5
6/*
7 * Copyright (C) 2014 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#include "GuestImpl.h"
23#include "GuestDnDSourceImpl.h"
24#include "GuestDnDPrivate.h"
25
26#include "Global.h"
27#include "AutoCaller.h"
28
29#include <iprt/cpp/utils.h> /* For unconst(). */
30
31#include <VBox/com/array.h>
32#include <VBox/GuestHost/DragAndDrop.h>
33#include <VBox/HostServices/DragAndDropSvc.h>
34
35#ifdef LOG_GROUP
36 #undef LOG_GROUP
37#endif
38#define LOG_GROUP LOG_GROUP_GUEST_DND
39#include <VBox/log.h>
40
41
42// constructor / destructor
43/////////////////////////////////////////////////////////////////////////////
44
45DEFINE_EMPTY_CTOR_DTOR(GuestDnDSource)
46
47HRESULT GuestDnDSource::FinalConstruct(void)
48{
49 LogFlowThisFunc(("\n"));
50 return BaseFinalConstruct();
51}
52
53void GuestDnDSource::FinalRelease(void)
54{
55 LogFlowThisFuncEnter();
56 uninit();
57 BaseFinalRelease();
58 LogFlowThisFuncLeave();
59}
60
61// public initializer/uninitializer for internal purposes only
62/////////////////////////////////////////////////////////////////////////////
63
64int GuestDnDSource::init(const ComObjPtr<Guest>& pGuest)
65{
66 LogFlowThisFuncEnter();
67
68 /* Enclose the state transition NotReady->InInit->Ready. */
69 AutoInitSpan autoInitSpan(this);
70 AssertReturn(autoInitSpan.isOk(), E_FAIL);
71
72 unconst(m_pGuest) = pGuest;
73
74 /* Confirm a successful initialization when it's the case. */
75 autoInitSpan.setSucceeded();
76
77 return VINF_SUCCESS;
78}
79
80/**
81 * Uninitializes the instance.
82 * Called from FinalRelease().
83 */
84void GuestDnDSource::uninit(void)
85{
86 LogFlowThisFunc(("\n"));
87
88 /* Enclose the state transition Ready->InUninit->NotReady. */
89 AutoUninitSpan autoUninitSpan(this);
90 if (autoUninitSpan.uninitDone())
91 return;
92}
93
94// implementation of wrapped private getters/setters for attributes
95/////////////////////////////////////////////////////////////////////////////
96
97HRESULT GuestDnDSource::dragIsPending(ULONG uScreenId,
98 std::vector<com::Utf8Str> &aFormats,
99 std::vector<DnDAction_T> &aAllowedActions,
100 DnDAction_T *aDefaultAction)
101{
102#if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
103 ReturnComNotImplemented();
104#else /* VBOX_WITH_DRAG_AND_DROP */
105
106 AutoCaller autoCaller(this);
107 if (FAILED(autoCaller.rc())) return autoCaller.rc();
108
109 /* Default is ignoring the action. */
110 DnDAction_T defaultAction = DnDAction_Ignore;
111
112 HRESULT hr = S_OK;
113
114 VBOXHGCMSVCPARM paParms[1];
115 int i = 0;
116 paParms[i++].setUInt32(uScreenId);
117
118 int rc = GuestDnDInst()->hostCall(DragAndDropSvc::HOST_DND_GH_REQ_PENDING,
119 i, paParms);
120 if (RT_SUCCESS(rc))
121 {
122 bool fFetchResult = true;
123 GuestDnDResponse *pResp = GuestDnDInst()->response();
124 if (pResp)
125 {
126 if (pResp->waitForGuestResponse() == VERR_TIMEOUT)
127 fFetchResult = false;
128
129 if (isDnDIgnoreAction(pResp->defAction()))
130 fFetchResult = false;
131
132 /* Fetch the default action to use. */
133 if (fFetchResult)
134 {
135 defaultAction = GuestDnD::toMainAction(pResp->defAction());
136
137 GuestDnD::toFormatVector(GuestDnDInst()->supportedFormats(),
138 pResp->format(), aFormats);
139 GuestDnD::toMainActions(pResp->allActions(), aAllowedActions);
140 }
141 }
142
143 if (aDefaultAction)
144 *aDefaultAction = defaultAction;
145 }
146
147 if (RT_FAILURE(rc))
148 hr = setError(VBOX_E_IPRT_ERROR,
149 tr("Unable to retrieve pending status (%Rrc)\n"), rc);
150
151 LogFlowFunc(("hr=%Rhrc, defaultAction=0x%x\n", hr, defaultAction));
152 return hr;
153#endif /* VBOX_WITH_DRAG_AND_DROP */
154}
155
156HRESULT GuestDnDSource::drop(const com::Utf8Str &aFormat,
157 DnDAction_T aAction, ComPtr<IProgress> &aProgress)
158{
159#if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
160 ReturnComNotImplemented();
161#else /* VBOX_WITH_DRAG_AND_DROP */
162
163 /* Input validation. */
164 if (RT_UNLIKELY((aFormat.c_str()) == NULL || *(aFormat.c_str()) == '\0'))
165 return setError(E_INVALIDARG, tr("No drop format specified"));
166
167 AutoCaller autoCaller(this);
168 if (FAILED(autoCaller.rc())) return autoCaller.rc();
169
170 uint32_t uAction = GuestDnD::toHGCMAction(aAction);
171 /* If there is no usable action, ignore this request. */
172 if (isDnDIgnoreAction(uAction))
173 return S_OK;
174
175 HRESULT hr = S_OK;
176
177 const char *pcszFormat = aFormat.c_str();
178 bool fNeedsDropDir = DnDMIMENeedsDropDir(pcszFormat, strlen(pcszFormat));
179 LogFlowFunc(("strFormat=%s, uAction=0x%x, fNeedsDropDir=%RTbool\n",
180 pcszFormat, uAction, fNeedsDropDir));
181
182 GuestDnDResponse *pResp = GuestDnDInst()->response();
183 if (pResp)
184 {
185 /* Reset any old data. */
186 pResp->reset();
187 pResp->resetProgress(m_pGuest);
188
189 /* Set the format we are going to retrieve to have it around
190 * when retrieving the data later. */
191 pResp->setFormat(aFormat);
192
193 if (fNeedsDropDir)
194 {
195 char szDropDir[RTPATH_MAX];
196 int rc = DnDDirCreateDroppedFiles(szDropDir, sizeof(szDropDir));
197 LogFlowFunc(("rc=%Rrc, szDropDir=%s\n", rc, szDropDir));
198 if (RT_FAILURE(rc))
199 return setError(VBOX_E_IPRT_ERROR,
200 tr("Unable to create the temporary drag'n drop directory \"%s\" (%Rrc)\n"),
201 szDropDir, rc);
202
203 pResp->setDropDir(szDropDir);
204 }
205
206 VBOXHGCMSVCPARM paParms[4];
207 int i = 0;
208 paParms[i++].setPointer((void*)aFormat.c_str(), (uint32_t)aFormat.length() + 1);
209 paParms[i++].setUInt32((uint32_t)aFormat.length() + 1);
210 paParms[i++].setUInt32(uAction);
211
212 int rc = GuestDnDInst()->hostCall(DragAndDropSvc::HOST_DND_GH_EVT_DROPPED,
213 i, paParms);
214 if (RT_SUCCESS(rc))
215 {
216 /* Query the progress object to the caller. */
217 pResp->queryProgressTo(aProgress.asOutParam());
218 }
219 else
220 hr = setError(VBOX_E_IPRT_ERROR,
221 tr("Error signalling to drop data (%Rrc)\n"), rc);
222 }
223
224 LogFlowFunc(("Returning hr=%Rhrc\n", hr));
225 return hr;
226#endif /* VBOX_WITH_DRAG_AND_DROP */
227}
228
229HRESULT GuestDnDSource::receiveData(std::vector<BYTE> &aData)
230{
231#if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
232 ReturnComNotImplemented();
233#else /* VBOX_WITH_DRAG_AND_DROP */
234
235 /* Input validation. */
236
237 AutoCaller autoCaller(this);
238 if (FAILED(autoCaller.rc())) return autoCaller.rc();
239
240 HRESULT hr = S_OK;
241
242 GuestDnDResponse *pResp = GuestDnDInst()->response();
243 if (pResp)
244 {
245 size_t cbData = pResp->size();
246 if (cbData)
247 {
248 const void *pvData = pResp->data();
249 AssertPtr(pvData);
250
251 Utf8Str strFormat = pResp->format();
252 LogFlowFunc(("strFormat=%s, cbData=%zu, pvData=0x%p\n",
253 strFormat.c_str(), cbData, pvData));
254
255 try
256 {
257 if (DnDMIMEHasFileURLs(strFormat.c_str(), strFormat.length()))
258 {
259 LogFlowFunc(("strDropDir=%s\n", pResp->dropDir().c_str()));
260
261 DnDURIList lstURI;
262 int rc2 = lstURI.RootFromURIData(pvData, cbData, 0 /* fFlags */);
263 if (RT_SUCCESS(rc2))
264 {
265 Utf8Str strURIs = lstURI.RootToString(pResp->dropDir());
266 size_t cbURIs = strURIs.length();
267
268 LogFlowFunc(("Found %zu root URIs (%zu bytes)\n",
269 lstURI.RootCount(), cbURIs));
270
271 aData.resize(cbURIs + 1 /* Include termination */);
272 memcpy(aData.data(), strURIs.c_str(), cbURIs);
273 }
274 else
275 hr = VBOX_E_IPRT_ERROR;
276 }
277 else
278 {
279 /* Copy the data into a safe array of bytes. */
280 aData.resize(cbData);
281 memcpy(aData.data(), pvData, cbData);
282 }
283 }
284 catch (std::bad_alloc &)
285 {
286 hr = E_OUTOFMEMORY;
287 }
288 }
289
290 /* Delete the data. */
291 pResp->reset();
292 }
293 else
294 hr = VBOX_E_INVALID_OBJECT_STATE;
295
296 LogFlowFunc(("Returning hr=%Rhrc\n", hr));
297 return hr;
298#endif /* VBOX_WITH_DRAG_AND_DROP */
299}
300
Note: See TracBrowser for help on using the repository browser.

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