VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/GuestDnDTargetImpl.cpp@ 51556

Last change on this file since 51556 was 51556, checked in by vboxsync, 10 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: 13.9 KB
Line 
1/* $Id: GuestDnDTargetImpl.cpp 51556 2014-06-05 14:38:31Z vboxsync $ */
2/** @file
3 * VBox Console COM Class implementation - Guest drag'n drop target.
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 "GuestDnDTargetImpl.h"
24
25#include "Global.h"
26#include "AutoCaller.h"
27
28#include <algorithm> /* For std::find(). */
29#include <iprt/cpp/utils.h> /* For unconst(). */
30
31#include <VBox/com/array.h>
32#include <VBox/HostServices/DragAndDropSvc.h>
33
34#ifdef LOG_GROUP
35 #undef LOG_GROUP
36#endif
37#define LOG_GROUP LOG_GROUP_GUEST_DND
38#include <VBox/log.h>
39
40
41// constructor / destructor
42/////////////////////////////////////////////////////////////////////////////
43
44DEFINE_EMPTY_CTOR_DTOR(GuestDnDTarget)
45
46HRESULT GuestDnDTarget::FinalConstruct(void)
47{
48 LogFlowThisFunc(("\n"));
49 return BaseFinalConstruct();
50}
51
52void GuestDnDTarget::FinalRelease(void)
53{
54 LogFlowThisFuncEnter();
55 uninit();
56 BaseFinalRelease();
57 LogFlowThisFuncLeave();
58}
59
60// public initializer/uninitializer for internal purposes only
61/////////////////////////////////////////////////////////////////////////////
62
63int GuestDnDTarget::init(const ComObjPtr<Guest>& pGuest)
64{
65 LogFlowThisFuncEnter();
66
67 /* Enclose the state transition NotReady->InInit->Ready. */
68 AutoInitSpan autoInitSpan(this);
69 AssertReturn(autoInitSpan.isOk(), E_FAIL);
70
71 unconst(m_pGuest) = pGuest;
72
73 /* Confirm a successful initialization when it's the case. */
74 autoInitSpan.setSucceeded();
75
76 return VINF_SUCCESS;
77}
78
79/**
80 * Uninitializes the instance.
81 * Called from FinalRelease().
82 */
83void GuestDnDTarget::uninit(void)
84{
85 LogFlowThisFunc(("\n"));
86
87 /* Enclose the state transition Ready->InUninit->NotReady. */
88 AutoUninitSpan autoUninitSpan(this);
89 if (autoUninitSpan.uninitDone())
90 return;
91}
92
93// implementation of wrapped IDnDBase methods.
94/////////////////////////////////////////////////////////////////////////////
95
96HRESULT GuestDnDTarget::isFormatSupported(const com::Utf8Str &aFormat,
97 BOOL *aSupported)
98{
99#if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
100 ReturnComNotImplemented();
101#else /* VBOX_WITH_DRAG_AND_DROP */
102
103 return GuestDnDBase::isFormatSupported(aFormat, aSupported);
104#endif /* VBOX_WITH_DRAG_AND_DROP */
105}
106
107HRESULT GuestDnDTarget::getFormats(std::vector<com::Utf8Str> &aFormats)
108{
109#if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
110 ReturnComNotImplemented();
111#else /* VBOX_WITH_DRAG_AND_DROP */
112
113 return GuestDnDBase::getFormats(aFormats);
114#endif /* VBOX_WITH_DRAG_AND_DROP */
115}
116
117HRESULT GuestDnDTarget::addFormats(const std::vector<com::Utf8Str> &aFormats)
118{
119#if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
120 ReturnComNotImplemented();
121#else /* VBOX_WITH_DRAG_AND_DROP */
122
123 return GuestDnDBase::addFormats(aFormats);
124#endif /* VBOX_WITH_DRAG_AND_DROP */
125}
126
127HRESULT GuestDnDTarget::removeFormats(const std::vector<com::Utf8Str> &aFormats)
128{
129#if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
130 ReturnComNotImplemented();
131#else /* VBOX_WITH_DRAG_AND_DROP */
132
133 return GuestDnDBase::removeFormats(aFormats);
134#endif /* VBOX_WITH_DRAG_AND_DROP */
135}
136
137// implementation of wrapped IDnDTarget methods.
138/////////////////////////////////////////////////////////////////////////////
139
140HRESULT GuestDnDTarget::enter(ULONG aScreenId, ULONG aX, ULONG aY,
141 DnDAction_T aDefaultAction,
142 const std::vector<DnDAction_T> &aAllowedActions,
143 const std::vector<com::Utf8Str> &aFormats,
144 DnDAction_T *aResultAction)
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 /* Input validation. */
151 if (aDefaultAction == DnDAction_Ignore)
152 return setError(E_INVALIDARG, tr("No default action specified"));
153 if (!aAllowedActions.size())
154 return setError(E_INVALIDARG, tr("Number of allowed actions is empty"));
155 if (!aFormats.size())
156 return setError(E_INVALIDARG, tr("Number of supported formats is empty"));
157
158 AutoCaller autoCaller(this);
159 if (FAILED(autoCaller.rc())) return autoCaller.rc();
160
161 /* Default action is ignoring. */
162 DnDAction_T resAction = DnDAction_Ignore;
163
164 /* Check & convert the drag & drop actions */
165 uint32_t uDefAction = 0;
166 uint32_t uAllowedActions = 0;
167 GuestDnD::toHGCMActions(aDefaultAction, &uDefAction,
168 aAllowedActions, &uAllowedActions);
169 /* If there is no usable action, ignore this request. */
170 if (isDnDIgnoreAction(uDefAction))
171 return S_OK;
172
173 /* Make a flat data string out of the supported format list. */
174 Utf8Str strFormats = GuestDnD::toFormatString(m_strFormats, aFormats);
175 /* If there is no valid supported format, ignore this request. */
176 if (strFormats.isEmpty())
177 return S_OK;
178
179 HRESULT hr = S_OK;
180
181 /* Adjust the coordinates in a multi-monitor setup. */
182 int rc = GuestDnDInst()->adjustScreenCoordinates(aScreenId, &aX, &aY);
183 if (RT_SUCCESS(rc))
184 {
185 VBOXHGCMSVCPARM paParms[8];
186 int i = 0;
187 paParms[i++].setUInt32(aScreenId);
188 paParms[i++].setUInt32(aX);
189 paParms[i++].setUInt32(aY);
190 paParms[i++].setUInt32(uDefAction);
191 paParms[i++].setUInt32(uAllowedActions);
192 paParms[i++].setPointer((void*)strFormats.c_str(), strFormats.length() + 1);
193 paParms[i++].setUInt32(strFormats.length() + 1);
194
195 rc = GuestDnDInst()->hostCall(DragAndDropSvc::HOST_DND_HG_EVT_ENTER,
196 i, paParms);
197 if (RT_SUCCESS(rc))
198 {
199 GuestDnDResponse *pResp = GuestDnDInst()->response();
200 if (pResp && RT_SUCCESS(pResp->waitForGuestResponse()))
201 resAction = GuestDnD::toMainAction(pResp->defAction());
202 }
203 }
204
205 if (aResultAction)
206 *aResultAction = resAction;
207
208 LogFlowFunc(("hr=%Rhrc, resAction=%ld\n", hr, resAction));
209 return hr;
210#endif /* VBOX_WITH_DRAG_AND_DROP */
211}
212
213HRESULT GuestDnDTarget::move(ULONG aScreenId, ULONG aX, ULONG aY,
214 DnDAction_T aDefaultAction,
215 const std::vector<DnDAction_T> &aAllowedActions,
216 const std::vector<com::Utf8Str> &aFormats,
217 DnDAction_T *aResultAction)
218{
219#if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
220 ReturnComNotImplemented();
221#else /* VBOX_WITH_DRAG_AND_DROP */
222
223 /* Input validation. */
224
225 AutoCaller autoCaller(this);
226 if (FAILED(autoCaller.rc())) return autoCaller.rc();
227
228 /* Default action is ignoring. */
229 DnDAction_T resAction = DnDAction_Ignore;
230
231 /* Check & convert the drag & drop actions. */
232 uint32_t uDefAction = 0;
233 uint32_t uAllowedActions = 0;
234 GuestDnD::toHGCMActions(aDefaultAction, &uDefAction,
235 aAllowedActions, &uAllowedActions);
236 /* If there is no usable action, ignore this request. */
237 if (isDnDIgnoreAction(uDefAction))
238 return S_OK;
239
240 /* Make a flat data string out of the supported format list. */
241 RTCString strFormats = GuestDnD::toFormatString(m_strFormats, aFormats);
242 /* If there is no valid supported format, ignore this request. */
243 if (strFormats.isEmpty())
244 return S_OK;
245
246 HRESULT hr = S_OK;
247
248 int rc = GuestDnDInst()->adjustScreenCoordinates(aScreenId, &aX, &aY);
249 if (RT_SUCCESS(rc))
250 {
251 VBOXHGCMSVCPARM paParms[8];
252 int i = 0;
253 paParms[i++].setUInt32(aScreenId);
254 paParms[i++].setUInt32(aX);
255 paParms[i++].setUInt32(aY);
256 paParms[i++].setUInt32(uDefAction);
257 paParms[i++].setUInt32(uAllowedActions);
258 paParms[i++].setPointer((void*)strFormats.c_str(), strFormats.length() + 1);
259 paParms[i++].setUInt32(strFormats.length() + 1);
260
261 rc = GuestDnDInst()->hostCall(DragAndDropSvc::HOST_DND_HG_EVT_MOVE,
262 i, paParms);
263 if (RT_SUCCESS(rc))
264 {
265 GuestDnDResponse *pResp = GuestDnDInst()->response();
266 if (pResp && RT_SUCCESS(pResp->waitForGuestResponse()))
267 resAction = GuestDnD::toMainAction(pResp->defAction());
268 }
269 }
270
271 if (aResultAction)
272 *aResultAction = resAction;
273
274 LogFlowFunc(("hr=%Rhrc, *pResultAction=%ld\n", hr, resAction));
275 return hr;
276#endif /* VBOX_WITH_DRAG_AND_DROP */
277}
278
279HRESULT GuestDnDTarget::leave(ULONG uScreenId)
280{
281#if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
282 ReturnComNotImplemented();
283#else /* VBOX_WITH_DRAG_AND_DROP */
284
285 AutoCaller autoCaller(this);
286 if (FAILED(autoCaller.rc())) return autoCaller.rc();
287
288 HRESULT hr = S_OK;
289 int rc = GuestDnDInst()->hostCall(DragAndDropSvc::HOST_DND_HG_EVT_LEAVE,
290 0 /* cParms */, NULL /* paParms */);
291 if (RT_SUCCESS(rc))
292 {
293 GuestDnDResponse *pResp = GuestDnDInst()->response();
294 if (pResp)
295 pResp->waitForGuestResponse();
296 }
297
298 LogFlowFunc(("hr=%Rhrc\n", hr));
299 return hr;
300#endif /* VBOX_WITH_DRAG_AND_DROP */
301}
302
303HRESULT GuestDnDTarget::drop(ULONG aScreenId, ULONG aX, ULONG aY,
304 DnDAction_T aDefaultAction,
305 const std::vector<DnDAction_T> &aAllowedActions,
306 const std::vector<com::Utf8Str> &aFormats,
307 com::Utf8Str &aFormat, DnDAction_T *aResultAction)
308{
309#if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
310 ReturnComNotImplemented();
311#else /* VBOX_WITH_DRAG_AND_DROP */
312
313 /* Input validation. */
314
315 /* Everything else is optional. */
316
317 AutoCaller autoCaller(this);
318 if (FAILED(autoCaller.rc())) return autoCaller.rc();
319
320 /* Default action is ignoring. */
321 DnDAction_T resAction = DnDAction_Ignore;
322
323 /* Check & convert the drag & drop actions. */
324 uint32_t uDefAction = 0;
325 uint32_t uAllowedActions = 0;
326 GuestDnD::toHGCMActions(aDefaultAction, &uDefAction,
327 aAllowedActions, &uAllowedActions);
328 /* If there is no usable action, ignore this request. */
329 if (isDnDIgnoreAction(uDefAction))
330 return S_OK;
331
332 /* Make a flat data string out of the supported format list. */
333 Utf8Str strFormats = GuestDnD::toFormatString(m_strFormats, aFormats);
334 /* If there is no valid supported format, ignore this request. */
335 if (strFormats.isEmpty())
336 return S_OK;
337
338 HRESULT hr = S_OK;
339
340 /* Adjust the coordinates in a multi-monitor setup. */
341 int rc = GuestDnDInst()->adjustScreenCoordinates(aScreenId, &aX, &aY);
342 if (RT_SUCCESS(rc))
343 {
344 VBOXHGCMSVCPARM paParms[8];
345 int i = 0;
346 paParms[i++].setUInt32(aScreenId);
347 paParms[i++].setUInt32(aX);
348 paParms[i++].setUInt32(aY);
349 paParms[i++].setUInt32(uDefAction);
350 paParms[i++].setUInt32(uAllowedActions);
351 paParms[i++].setPointer((void*)strFormats.c_str(), strFormats.length() + 1);
352 paParms[i++].setUInt32(strFormats.length() + 1);
353
354 rc = GuestDnDInst()->hostCall(DragAndDropSvc::HOST_DND_HG_EVT_DROPPED,
355 i, paParms);
356 if (RT_SUCCESS(rc))
357 {
358 GuestDnDResponse *pResp = GuestDnDInst()->response();
359 if (pResp && RT_SUCCESS(pResp->waitForGuestResponse()))
360 {
361 resAction = GuestDnD::toMainAction(pResp->defAction());
362 aFormat = pResp->format();
363
364 LogFlowFunc(("resFormat=%s, resAction=%RU32\n",
365 pResp->format().c_str(), pResp->defAction()));
366 }
367 }
368 }
369
370 if (aResultAction)
371 *aResultAction = resAction;
372
373 return hr;
374#endif /* VBOX_WITH_DRAG_AND_DROP */
375}
376
377HRESULT GuestDnDTarget::sendData(ULONG aScreenId,
378 const com::Utf8Str &aFormat,
379 const std::vector<BYTE> &aData,
380 ComPtr<IProgress> &aProgress)
381{
382#if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
383 ReturnComNotImplemented();
384#else /* VBOX_WITH_DRAG_AND_DROP */
385
386 /* Input validation */
387
388
389 AutoCaller autoCaller(this);
390 if (FAILED(autoCaller.rc())) return autoCaller.rc();
391
392 HRESULT hr = S_OK;
393
394 VBOXHGCMSVCPARM paParms[8];
395 int i = 0;
396 paParms[i++].setUInt32(aScreenId);
397 paParms[i++].setPointer((void *)aFormat.c_str(), (uint32_t)aFormat.length() + 1);
398 paParms[i++].setUInt32((uint32_t)aFormat.length() + 1);
399 paParms[i++].setPointer((void *)aData.front(), (uint32_t)aData.size());
400 paParms[i++].setUInt32((uint32_t)aData.size());
401
402 GuestDnDResponse *pResp = GuestDnDInst()->response();
403 if (pResp)
404 {
405 /* Reset any old progress status. */
406 pResp->resetProgress(m_pGuest);
407
408 /* Note: The actual data transfer of files/directoies is performed by the
409 * DnD host service. */
410 int rc = GuestDnDInst()->hostCall(DragAndDropSvc::HOST_DND_HG_SND_DATA,
411 i, paParms);
412 if (RT_SUCCESS(rc))
413 {
414 /* Query the progress object to the caller. */
415 if (aProgress)
416 pResp->queryProgressTo(aProgress.asOutParam());
417 }
418 }
419
420 return hr;
421#endif /* VBOX_WITH_DRAG_AND_DROP */
422}
423
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