VirtualBox

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

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

DnD: Added support for dynamically managing formats on the host.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.7 KB
Line 
1/* $Id: GuestDnDSourceImpl.cpp 51556 2014-06-05 14:38:31Z 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 IDnDBase methods.
95/////////////////////////////////////////////////////////////////////////////
96
97HRESULT GuestDnDSource::isFormatSupported(const com::Utf8Str &aFormat,
98 BOOL *aSupported)
99{
100#if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
101 ReturnComNotImplemented();
102#else /* VBOX_WITH_DRAG_AND_DROP */
103
104 return GuestDnDBase::isFormatSupported(aFormat, aSupported);
105#endif /* VBOX_WITH_DRAG_AND_DROP */
106}
107
108HRESULT GuestDnDSource::getFormats(std::vector<com::Utf8Str> &aFormats)
109{
110#if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
111 ReturnComNotImplemented();
112#else /* VBOX_WITH_DRAG_AND_DROP */
113
114 return GuestDnDBase::getFormats(aFormats);
115#endif /* VBOX_WITH_DRAG_AND_DROP */
116}
117
118HRESULT GuestDnDSource::addFormats(const std::vector<com::Utf8Str> &aFormats)
119{
120#if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
121 ReturnComNotImplemented();
122#else /* VBOX_WITH_DRAG_AND_DROP */
123
124 return GuestDnDBase::addFormats(aFormats);
125#endif /* VBOX_WITH_DRAG_AND_DROP */
126}
127
128HRESULT GuestDnDSource::removeFormats(const std::vector<com::Utf8Str> &aFormats)
129{
130#if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
131 ReturnComNotImplemented();
132#else /* VBOX_WITH_DRAG_AND_DROP */
133
134 return GuestDnDBase::removeFormats(aFormats);
135#endif /* VBOX_WITH_DRAG_AND_DROP */
136}
137
138// implementation of wrapped IDnDTarget methods.
139/////////////////////////////////////////////////////////////////////////////
140
141HRESULT GuestDnDSource::dragIsPending(ULONG uScreenId,
142 std::vector<com::Utf8Str> &aFormats,
143 std::vector<DnDAction_T> &aAllowedActions,
144 DnDAction_T *aDefaultAction)
145{
146#if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
147 ReturnComNotImplemented();
148#else /* VBOX_WITH_DRAG_AND_DROP */
149
150 AutoCaller autoCaller(this);
151 if (FAILED(autoCaller.rc())) return autoCaller.rc();
152
153 /* Default is ignoring the action. */
154 DnDAction_T defaultAction = DnDAction_Ignore;
155
156 HRESULT hr = S_OK;
157
158 VBOXHGCMSVCPARM paParms[1];
159 int i = 0;
160 paParms[i++].setUInt32(uScreenId);
161
162 int rc = GuestDnDInst()->hostCall(DragAndDropSvc::HOST_DND_GH_REQ_PENDING,
163 i, paParms);
164 if (RT_SUCCESS(rc))
165 {
166 bool fFetchResult = true;
167 GuestDnDResponse *pResp = GuestDnDInst()->response();
168 if (pResp)
169 {
170 if (pResp->waitForGuestResponse() == VERR_TIMEOUT)
171 fFetchResult = false;
172
173 if (isDnDIgnoreAction(pResp->defAction()))
174 fFetchResult = false;
175
176 /* Fetch the default action to use. */
177 if (fFetchResult)
178 {
179 defaultAction = GuestDnD::toMainAction(pResp->defAction());
180
181 GuestDnD::toFormatVector(m_strFormats, pResp->format(), aFormats);
182 GuestDnD::toMainActions(pResp->allActions(), aAllowedActions);
183 }
184 }
185
186 if (aDefaultAction)
187 *aDefaultAction = defaultAction;
188 }
189
190 if (RT_FAILURE(rc))
191 hr = setError(VBOX_E_IPRT_ERROR,
192 tr("Unable to retrieve pending status (%Rrc)\n"), rc);
193
194 LogFlowFunc(("hr=%Rhrc, defaultAction=0x%x\n", hr, defaultAction));
195 return hr;
196#endif /* VBOX_WITH_DRAG_AND_DROP */
197}
198
199HRESULT GuestDnDSource::drop(const com::Utf8Str &aFormat,
200 DnDAction_T aAction, ComPtr<IProgress> &aProgress)
201{
202#if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
203 ReturnComNotImplemented();
204#else /* VBOX_WITH_DRAG_AND_DROP */
205
206 /* Input validation. */
207 if (RT_UNLIKELY((aFormat.c_str()) == NULL || *(aFormat.c_str()) == '\0'))
208 return setError(E_INVALIDARG, tr("No drop format specified"));
209
210 AutoCaller autoCaller(this);
211 if (FAILED(autoCaller.rc())) return autoCaller.rc();
212
213 uint32_t uAction = GuestDnD::toHGCMAction(aAction);
214 /* If there is no usable action, ignore this request. */
215 if (isDnDIgnoreAction(uAction))
216 return S_OK;
217
218 HRESULT hr = S_OK;
219
220 const char *pcszFormat = aFormat.c_str();
221 bool fNeedsDropDir = DnDMIMENeedsDropDir(pcszFormat, strlen(pcszFormat));
222 LogFlowFunc(("strFormat=%s, uAction=0x%x, fNeedsDropDir=%RTbool\n",
223 pcszFormat, uAction, fNeedsDropDir));
224
225 GuestDnDResponse *pResp = GuestDnDInst()->response();
226 if (pResp)
227 {
228 /* Reset any old data. */
229 pResp->reset();
230 pResp->resetProgress(m_pGuest);
231
232 /* Set the format we are going to retrieve to have it around
233 * when retrieving the data later. */
234 pResp->setFormat(aFormat);
235
236 if (fNeedsDropDir)
237 {
238 char szDropDir[RTPATH_MAX];
239 int rc = DnDDirCreateDroppedFiles(szDropDir, sizeof(szDropDir));
240 LogFlowFunc(("rc=%Rrc, szDropDir=%s\n", rc, szDropDir));
241 if (RT_FAILURE(rc))
242 return setError(VBOX_E_IPRT_ERROR,
243 tr("Unable to create the temporary drag'n drop directory \"%s\" (%Rrc)\n"),
244 szDropDir, rc);
245
246 pResp->setDropDir(szDropDir);
247 }
248
249 VBOXHGCMSVCPARM paParms[4];
250 int i = 0;
251 paParms[i++].setPointer((void*)aFormat.c_str(), (uint32_t)aFormat.length() + 1);
252 paParms[i++].setUInt32((uint32_t)aFormat.length() + 1);
253 paParms[i++].setUInt32(uAction);
254
255 int rc = GuestDnDInst()->hostCall(DragAndDropSvc::HOST_DND_GH_EVT_DROPPED,
256 i, paParms);
257 if (RT_SUCCESS(rc))
258 {
259 /* Query the progress object to the caller. */
260 pResp->queryProgressTo(aProgress.asOutParam());
261 }
262 else
263 hr = setError(VBOX_E_IPRT_ERROR,
264 tr("Error signalling to drop data (%Rrc)\n"), rc);
265 }
266
267 LogFlowFunc(("Returning hr=%Rhrc\n", hr));
268 return hr;
269#endif /* VBOX_WITH_DRAG_AND_DROP */
270}
271
272HRESULT GuestDnDSource::receiveData(std::vector<BYTE> &aData)
273{
274#if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
275 ReturnComNotImplemented();
276#else /* VBOX_WITH_DRAG_AND_DROP */
277
278 /* Input validation. */
279
280 AutoCaller autoCaller(this);
281 if (FAILED(autoCaller.rc())) return autoCaller.rc();
282
283 HRESULT hr = S_OK;
284
285 GuestDnDResponse *pResp = GuestDnDInst()->response();
286 if (pResp)
287 {
288 size_t cbData = pResp->size();
289 if (cbData)
290 {
291 const void *pvData = pResp->data();
292 AssertPtr(pvData);
293
294 Utf8Str strFormat = pResp->format();
295 LogFlowFunc(("strFormat=%s, cbData=%zu, pvData=0x%p\n",
296 strFormat.c_str(), cbData, pvData));
297
298 try
299 {
300 if (DnDMIMEHasFileURLs(strFormat.c_str(), strFormat.length()))
301 {
302 LogFlowFunc(("strDropDir=%s\n", pResp->dropDir().c_str()));
303
304 DnDURIList lstURI;
305 int rc2 = lstURI.RootFromURIData(pvData, cbData, 0 /* fFlags */);
306 if (RT_SUCCESS(rc2))
307 {
308 Utf8Str strURIs = lstURI.RootToString(pResp->dropDir());
309 size_t cbURIs = strURIs.length();
310
311 LogFlowFunc(("Found %zu root URIs (%zu bytes)\n",
312 lstURI.RootCount(), cbURIs));
313
314 aData.resize(cbURIs + 1 /* Include termination */);
315 memcpy((void *)aData.front(), strURIs.c_str(), cbURIs);
316 }
317 else
318 hr = VBOX_E_IPRT_ERROR;
319 }
320 else
321 {
322 /* Copy the data into a safe array of bytes. */
323 aData.resize(cbData);
324 memcpy((void *)aData.front(), pvData, cbData);
325 }
326 }
327 catch (std::bad_alloc &)
328 {
329 hr = E_OUTOFMEMORY;
330 }
331 }
332
333 /* Delete the data. */
334 pResp->reset();
335 }
336 else
337 hr = VBOX_E_INVALID_OBJECT_STATE;
338
339 LogFlowFunc(("Returning hr=%Rhrc\n", hr));
340 return hr;
341#endif /* VBOX_WITH_DRAG_AND_DROP */
342}
343
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