VirtualBox

source: vbox/trunk/src/VBox/HostServices/DragAndDrop/dndmanager.cpp@ 54266

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

DnD: Update, bugfixes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.3 KB
Line 
1/* $Id: dndmanager.cpp 50561 2014-02-24 21:07:22Z vboxsync $ */
2/** @file
3 * Drag and Drop manager.
4 */
5
6/*
7 * Copyright (C) 2011-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 * Header Files *
20 ******************************************************************************/
21
22#ifdef LOG_GROUP
23 #undef LOG_GROUP
24#endif
25#define LOG_GROUP LOG_GROUP_GUEST_DND
26
27#include "dndmanager.h"
28
29#include <VBox/log.h>
30#include <iprt/file.h>
31#include <iprt/dir.h>
32#include <iprt/path.h>
33#include <iprt/uri.h>
34
35/******************************************************************************
36 * Private declarations *
37 ******************************************************************************/
38
39typedef DECLCALLBACK(int) FNDNDPRIVATEPROGRESS(size_t cbDone, void *pvUser);
40typedef FNDNDPRIVATEPROGRESS *PFNDNDPRIVATEPROGRESS;
41
42/**
43 * Internal DnD message class for informing the
44 * guest about a new directory.
45 *
46 * @see DnDHGSendDataMessage
47 */
48class DnDHGSendDirPrivate: public DnDMessage
49{
50public:
51
52 DnDHGSendDirPrivate(DnDURIObject URIObject,
53 PFNDNDPRIVATEPROGRESS pfnProgressCallback, void *pvProgressUser)
54 : m_URIObject(URIObject)
55 , m_pfnProgressCallback(pfnProgressCallback)
56 , m_pvProgressUser(pvProgressUser)
57 {
58 RTCString strPath = m_URIObject.GetDestPath();
59 LogFlowFunc(("strPath=%s (%zu)\n", strPath.c_str(), strPath.length()));
60
61 VBOXHGCMSVCPARM paTmpParms[3];
62 paTmpParms[0].setString(strPath.c_str());
63 paTmpParms[1].setUInt32((uint32_t)(strPath.length() + 1));
64 paTmpParms[2].setUInt32(m_URIObject.GetMode());
65
66 m_pNextMsg = new HGCM::Message(DragAndDropSvc::HOST_DND_HG_SND_DIR, 3, paTmpParms);
67 }
68
69public:
70
71 int currentMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
72 {
73 int rc = DnDMessage::currentMessage(uMsg, cParms, paParms);
74 /* Advance progress info */
75 if ( RT_SUCCESS(rc)
76 && m_pfnProgressCallback)
77 rc = m_pfnProgressCallback(m_URIObject.GetSize(), m_pvProgressUser);
78
79 return rc;
80 }
81
82protected:
83
84 DnDURIObject m_URIObject;
85
86 /* Progress stuff. */
87 PFNDNDPRIVATEPROGRESS m_pfnProgressCallback;
88 void *m_pvProgressUser;
89};
90
91/**
92 * Internal DnD message class for informing the guest about a new file.
93 *
94 * @see DnDHGSendDataMessage
95 */
96class DnDHGSendFilePrivate: public DnDMessage
97{
98public:
99
100 DnDHGSendFilePrivate(DnDURIObject URIObject,
101 PFNDNDPRIVATEPROGRESS pfnProgressCallback, void *pvProgressUser);
102 virtual ~DnDHGSendFilePrivate(void);
103
104public:
105
106 int currentMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
107
108protected:
109
110 DnDURIObject m_URIObject;
111 /** Skeleton parameters for the next upcoming message in case
112 * the file data didn't fit completely into the first one. */
113 VBOXHGCMSVCPARM m_aSkelParms[5];
114
115 /* Progress stuff. */
116 PFNDNDPRIVATEPROGRESS m_pfnProgressCallback;
117 void *m_pvProgressUser;
118};
119
120/**
121 * Internal DnD message class for informing the guest about new drag & drop
122 * data.
123 *
124 * @see DnDHGSendDataMessage
125 */
126class DnDHGSendDataMessagePrivate: public DnDMessage
127{
128public:
129
130 DnDHGSendDataMessagePrivate(uint32_t uMsg, uint32_t cParms,
131 VBOXHGCMSVCPARM paParms[],
132 PFNDNDPRIVATEPROGRESS pfnProgressCallback, void *pvProgressUser);
133 int currentMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
134
135protected:
136 size_t m_cbSize;
137 size_t m_cbDone;
138
139 /* Progress stuff. */
140 PFNDNDPRIVATEPROGRESS m_pfnProgressCallback;
141 void *m_pvProgressUser;
142};
143
144/******************************************************************************
145 * Implementation *
146 ******************************************************************************/
147
148/******************************************************************************
149 * DnDHGSendFilePrivate *
150 ******************************************************************************/
151
152DnDHGSendFilePrivate::DnDHGSendFilePrivate(DnDURIObject URIObject,
153 PFNDNDPRIVATEPROGRESS pfnProgressCallback, void *pvProgressUser)
154 : m_URIObject(URIObject)
155 , m_pfnProgressCallback(pfnProgressCallback)
156 , m_pvProgressUser(pvProgressUser)
157{
158 LogFlowFunc(("strPath=%s (%zu)\n",
159 m_URIObject.GetDestPath().c_str(), m_URIObject.GetDestPath().length()));
160
161 m_aSkelParms[0].setString(m_URIObject.GetDestPath().c_str()); /* pvName */
162 m_aSkelParms[1].setUInt32((uint32_t)(m_URIObject.GetDestPath().length() + 1)); /* cbName */
163 m_aSkelParms[2].setPointer(NULL, 0); /* pvData */
164 m_aSkelParms[3].setUInt32(0); /* cbData */
165 m_aSkelParms[4].setUInt32(m_URIObject.GetMode()); /* fMode */
166
167 m_pNextMsg = new HGCM::Message(DragAndDropSvc::HOST_DND_HG_SND_FILE, 5, m_aSkelParms);
168}
169
170DnDHGSendFilePrivate::~DnDHGSendFilePrivate(void)
171{
172}
173
174int DnDHGSendFilePrivate::currentMessage(uint32_t uMsg, uint32_t cParms,
175 VBOXHGCMSVCPARM paParms[])
176{
177 if (!m_pNextMsg)
178 return VERR_NO_DATA;
179
180 int rc = m_pNextMsg->getData(uMsg, cParms, paParms);
181 clearNextMsg();
182 if (RT_FAILURE(rc))
183 return rc;
184
185 uint32_t cbRead;
186 if (RT_SUCCESS(rc))
187 {
188 /* Get buffer size + pointer to buffer from guest side. */
189 uint32_t cbToRead = paParms[2].u.pointer.size; /* cbData */
190 Assert(cbToRead);
191 void *pvBuf = paParms[2].u.pointer.addr; /* pvData */
192 AssertPtr(pvBuf);
193
194 rc = m_URIObject.Read(pvBuf, cbToRead, &cbRead);
195 LogFlowFunc(("Read %RU32 bytes (%RU32 bytes buffer) for \"%s\", rc=%Rrc\n",
196 cbRead, cbToRead, m_URIObject.GetDestPath().c_str(), rc));
197
198 if (RT_LIKELY(RT_SUCCESS(rc)))
199 {
200 /* Tell the guest the actual size read. */
201 paParms[3].setUInt32((uint32_t)cbRead); /* cbData */
202 }
203 }
204
205 if (RT_SUCCESS(rc))
206 {
207 if (!m_URIObject.IsComplete())
208 {
209 try
210 {
211 /* More data needed to send over. Prepare the next message. */
212 m_pNextMsg = new HGCM::Message(DragAndDropSvc::HOST_DND_HG_SND_FILE, 5 /* cParms */,
213 m_aSkelParms);
214 }
215 catch(std::bad_alloc &)
216 {
217 rc = VERR_NO_MEMORY;
218 }
219 }
220
221 /* Advance progress info. */
222 if ( RT_SUCCESS(rc)
223 && m_pfnProgressCallback)
224 {
225 rc = m_pfnProgressCallback(cbRead, m_pvProgressUser);
226 }
227 }
228
229 return rc;
230}
231
232/******************************************************************************
233 * DnDHGSendDataMessagePrivate *
234 ******************************************************************************/
235
236DnDHGSendDataMessagePrivate::DnDHGSendDataMessagePrivate(uint32_t uMsg, uint32_t cParms,
237 VBOXHGCMSVCPARM paParms[],
238 PFNDNDPRIVATEPROGRESS pfnProgressCallback,
239 void *pvProgressUser)
240 : m_cbSize(paParms[4].u.uint32)
241 , m_cbDone(0)
242 , m_pfnProgressCallback(pfnProgressCallback)
243 , m_pvProgressUser(pvProgressUser)
244{
245 /* Create the initial data message. This might throw
246 * a bad_alloc exception. */
247 m_pNextMsg = new HGCM::Message(uMsg, cParms, paParms);
248}
249
250int DnDHGSendDataMessagePrivate::currentMessage(uint32_t uMsg, uint32_t cParms,
251 VBOXHGCMSVCPARM paParms[])
252{
253 /** @todo Don't copy the data parts ... just move the data pointer in
254 * the original data ptr. */
255 if (!m_pNextMsg)
256 return VERR_NO_DATA;
257
258 int rc = VINF_SUCCESS;
259
260 HGCM::Message *pCurMsg = m_pNextMsg;
261 AssertPtr(pCurMsg);
262
263 m_pNextMsg = 0;
264 rc = pCurMsg->getData(uMsg, cParms, paParms);
265
266 /* Depending on the current message, the data pointer is on a
267 * different position (HOST_DND_HG_SND_DATA=3;
268 * HOST_DND_HG_SND_MORE_DATA=0). */
269 int iPos = uMsg == DragAndDropSvc::HOST_DND_HG_SND_DATA ? 3 : 0;
270 m_cbDone += paParms[iPos + 1].u.uint32;
271
272 /* Info + data send already? */
273 if (rc == VERR_BUFFER_OVERFLOW)
274 {
275 paParms[iPos + 1].u.uint32 = paParms[iPos].u.pointer.size;
276 VBOXHGCMSVCPARM paTmpParms[2];
277 void *pvOldData;
278 uint32_t cOldData;
279 pCurMsg->getParmPtrInfo(iPos, &pvOldData, &cOldData);
280 paTmpParms[0].setPointer(static_cast<uint8_t*>(pvOldData) + paParms[iPos].u.pointer.size, cOldData - paParms[iPos].u.pointer.size);
281 paTmpParms[1].setUInt32(cOldData - paParms[iPos].u.pointer.size);
282
283 try
284 {
285 m_pNextMsg = new HGCM::Message(DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA, 2, paTmpParms);
286 }
287 catch(std::bad_alloc &)
288 {
289 rc = VERR_NO_MEMORY;
290 }
291 }
292
293 if (pCurMsg)
294 delete pCurMsg;
295
296 /* Advance progress info. */
297 if ( RT_SUCCESS(rc)
298 && m_pfnProgressCallback)
299 {
300 rc = m_pfnProgressCallback(m_cbDone, m_pvProgressUser);
301 }
302
303 return rc;
304}
305
306/******************************************************************************
307 * DnDHGSendDataMessage *
308 ******************************************************************************/
309
310/*
311 * This class is a meta message class. It doesn't consist of any own message
312 * data, but handle the meta info, the data itself as well as any files or
313 * directories which have to be transfered to the guest.
314 */
315DnDHGSendDataMessage::DnDHGSendDataMessage(uint32_t uMsg, uint32_t cParms,
316 VBOXHGCMSVCPARM paParms[],
317 PFNDNDPROGRESS pfnProgressCallback,
318 void *pvProgressUser)
319 : m_cbTotal(0)
320 , m_cbTransfered(0)
321 , m_pfnProgressCallback(pfnProgressCallback)
322 , m_pvProgressUser(pvProgressUser)
323{
324 if (cParms < 5) /* Paranoia. */
325 return;
326
327 const char *pszFormat = static_cast<const char*>(paParms[1].u.pointer.addr);
328 uint32_t cbFormat = paParms[1].u.pointer.size;
329
330 int rc = VINF_SUCCESS;
331 RTCString strNewURIs;
332
333 /* Do we need to build up a file tree? */
334 if (DnDMIMEHasFileURLs(pszFormat, cbFormat))
335 {
336 const char *pszList = static_cast<const char*>(paParms[3].u.pointer.addr);
337 AssertPtr(pszList);
338 uint32_t cbList = paParms[3].u.pointer.size;
339 Assert(cbList);
340
341 LogFlowFunc(("Old data (%RU32 bytes): '%s'\n", cbList, pszList));
342
343 /* The list is separated by newline (even if only one file is listed). */
344 RTCList<RTCString> lstURIOrg
345 = RTCString(pszList, cbList).split("\r\n");
346 if (!lstURIOrg.isEmpty())
347 {
348 rc = m_lstURI.AppendURIPathsFromList(lstURIOrg, 0 /* fFlags */);
349 if (RT_SUCCESS(rc))
350 {
351 /* Add the total size of all meta data + files transferred to
352 * the message's total byte count. */
353 m_cbTotal += m_lstURI.TotalBytes();
354
355 /* We have to change the actual DnD data. Remove any host paths and
356 * just decode the filename into the new data. The Guest Additions will
357 * add the correct path again before sending the DnD drop event to
358 * some window. */
359 strNewURIs = m_lstURI.RootToString();
360
361 /* Note: We don't delete the old pointer here, cause this is done
362 * by the caller. We just use the RTString data, which has the
363 * scope of this ctor. This is enough cause the data is copied in
364 * the DnDHGSendDataMessagePrivate anyway. */
365 paParms[3].u.pointer.addr = (void *)strNewURIs.c_str();
366 paParms[3].u.pointer.size = (uint32_t)(strNewURIs.length() + 1);
367 paParms[4].u.uint32 = (uint32_t)(strNewURIs.length() + 1);
368
369 LogFlowFunc(("Set new data (%RU32 bytes): '%s'\n",
370 paParms[3].u.pointer.size,
371 (const char*)paParms[3].u.pointer.addr));
372 }
373 }
374 }
375
376 /* Add the size of the data to the todo list. */
377 m_cbTotal += paParms[4].u.uint32;
378 LogFlowFunc(("cbTotal=%zu\n", m_cbTotal));
379
380 /* The first message is the meta info for the data and the data itself. */
381 m_pNextPathMsg = new DnDHGSendDataMessagePrivate(uMsg, cParms, paParms,
382 &DnDHGSendDataMessage::progressCallback, this);
383}
384
385DnDHGSendDataMessage::~DnDHGSendDataMessage(void)
386{
387 if (m_pNextPathMsg)
388 delete m_pNextPathMsg;
389}
390
391HGCM::Message* DnDHGSendDataMessage::nextHGCMMessage(void)
392{
393 if (!m_pNextPathMsg)
394 return NULL;
395
396 return m_pNextPathMsg->nextHGCMMessage();
397}
398
399int DnDHGSendDataMessage::currentMessageInfo(uint32_t *puMsg, uint32_t *pcParms)
400{
401 if (!m_pNextPathMsg)
402 return VERR_NO_DATA;
403
404 return m_pNextPathMsg->currentMessageInfo(puMsg, pcParms);
405}
406
407int DnDHGSendDataMessage::currentMessage(uint32_t uMsg,
408 uint32_t cParms, VBOXHGCMSVCPARM paParms[])
409{
410 if (!m_pNextPathMsg)
411 return VERR_NO_DATA;
412
413 /* Fill the data out of our current queued message. */
414 int rc = m_pNextPathMsg->currentMessage(uMsg, cParms, paParms);
415 /* Has this message more data to deliver? */
416 if (!m_pNextPathMsg->isMessageWaiting())
417 {
418 delete m_pNextPathMsg;
419 m_pNextPathMsg = NULL;
420 }
421
422 /* File/directory data to send? */
423 if (!m_pNextPathMsg)
424 {
425 if (m_lstURI.IsEmpty())
426 return rc;
427
428 /* Create new messages based on our internal path list. Currently
429 * this could be directories or regular files. */
430 const DnDURIObject &nextObj = m_lstURI.First();
431 try
432 {
433 uint32_t fMode = nextObj.GetMode();
434 LogFlowFunc(("Processing srcPath=%s, dstPath=%s, fMode=0x%x, cbSize=%RU32, fIsDir=%RTbool, fIsFile=%RTbool\n",
435 nextObj.GetSourcePath().c_str(), nextObj.GetDestPath().c_str(),
436 fMode, nextObj.GetSize(),
437 RTFS_IS_DIRECTORY(fMode), RTFS_IS_FILE(fMode)));
438
439 if (RTFS_IS_DIRECTORY(fMode))
440 m_pNextPathMsg = new DnDHGSendDirPrivate(nextObj,
441 &DnDHGSendDataMessage::progressCallback /* pfnProgressCallback */,
442 this /* pvProgressUser */);
443 else if (RTFS_IS_FILE(fMode))
444 m_pNextPathMsg = new DnDHGSendFilePrivate(nextObj,
445 &DnDHGSendDataMessage::progressCallback /* pfnProgressCallback */,
446 this /* pvProgressUser */);
447 else
448 AssertMsgFailedReturn(("fMode=0x%x is not supported for srcPath=%s, dstPath=%s\n",
449 fMode, nextObj.GetSourcePath().c_str(), nextObj.GetDestPath().c_str()),
450 VERR_NO_DATA);
451
452 m_lstURI.RemoveFirst();
453 }
454 catch(std::bad_alloc &)
455 {
456 rc = VERR_NO_MEMORY;
457 }
458 }
459
460 return rc;
461}
462
463int DnDHGSendDataMessage::progressCallback(size_t cbDone, void *pvUser)
464{
465 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
466
467 DnDHGSendDataMessage *pSelf = static_cast<DnDHGSendDataMessage *>(pvUser);
468 AssertPtr(pSelf);
469
470 /* How many bytes are transfered already. */
471 pSelf->m_cbTransfered += cbDone;
472
473 /* Advance progress info. */
474 int rc = VINF_SUCCESS;
475 if ( pSelf->m_pfnProgressCallback
476 && pSelf->m_cbTotal)
477 {
478 AssertMsg(pSelf->m_cbTransfered <= pSelf->m_cbTotal,
479 ("More bytes transferred (%zu) than expected (%zu), cbDone=%zu\n",
480 pSelf->m_cbTransfered, pSelf->m_cbTotal, cbDone));
481
482 unsigned uPercentage = (unsigned)((uint64_t)pSelf->m_cbTransfered * 100 / pSelf->m_cbTotal);
483 rc = pSelf->m_pfnProgressCallback(RT_MIN(uPercentage, 100),
484 DragAndDropSvc::DND_PROGRESS_RUNNING,
485 VINF_SUCCESS /* rc */, pSelf->m_pvProgressUser);
486 }
487
488 return rc;
489}
490
491/******************************************************************************
492 * DnDManager *
493 ******************************************************************************/
494
495int DnDManager::addMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
496{
497 int rc = VINF_SUCCESS;
498
499 try
500 {
501 switch (uMsg)
502 {
503 case DragAndDropSvc::HOST_DND_HG_EVT_ENTER:
504 {
505 clear();
506 LogFlowFunc(("HOST_DND_HG_EVT_ENTER\n"));
507
508 /* Verify parameter count and types. */
509 if ( cParms != 7
510 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */
511 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* x-pos */
512 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* y-pos */
513 || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* default action */
514 || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* allowed actions */
515 || paParms[5].type != VBOX_HGCM_SVC_PARM_PTR /* data */
516 || paParms[6].type != VBOX_HGCM_SVC_PARM_32BIT /* size */)
517 rc = VERR_INVALID_PARAMETER;
518 else
519 {
520 m_fOpInProcess = true;
521 DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms);
522 m_dndMessageQueue.append(pMessage);
523 }
524 break;
525 }
526
527 case DragAndDropSvc::HOST_DND_HG_EVT_MOVE:
528 {
529 LogFlowFunc(("HOST_DND_HG_EVT_MOVE\n"));
530
531 /* Verify parameter count and types. */
532 if ( cParms != 7
533 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */
534 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* x-pos */
535 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* y-pos */
536 || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* default action */
537 || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* allowed actions */
538 || paParms[5].type != VBOX_HGCM_SVC_PARM_PTR /* data */
539 || paParms[6].type != VBOX_HGCM_SVC_PARM_32BIT /* size */)
540 {
541 rc = VERR_INVALID_PARAMETER;
542 }
543 else
544 {
545 m_fOpInProcess = true;
546 DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms);
547 m_dndMessageQueue.append(pMessage);
548 }
549 break;
550 }
551
552 case DragAndDropSvc::HOST_DND_HG_EVT_LEAVE:
553 {
554 LogFlowFunc(("HOST_DND_HG_EVT_LEAVE\n"));
555
556 /* Verify parameter count and types. */
557 if (cParms != 0)
558 rc = VERR_INVALID_PARAMETER;
559 else
560 {
561 DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms);
562 m_dndMessageQueue.append(pMessage);
563 }
564
565 m_fOpInProcess = false;
566 break;
567 }
568
569 case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED:
570 {
571 LogFlowFunc(("HOST_DND_HG_EVT_DROPPED\n"));
572
573 /* Verify parameter count and types. */
574 if ( cParms != 7
575 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */
576 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* x-pos */
577 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* y-pos */
578 || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* default action */
579 || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* allowed actions */
580 || paParms[5].type != VBOX_HGCM_SVC_PARM_PTR /* data */
581 || paParms[6].type != VBOX_HGCM_SVC_PARM_32BIT /* size */)
582 {
583 rc = VERR_INVALID_PARAMETER;
584 }
585 else
586 {
587 DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms);
588 m_dndMessageQueue.append(pMessage);
589 }
590 break;
591 }
592
593 case DragAndDropSvc::HOST_DND_HG_SND_DATA:
594 {
595 LogFlowFunc(("HOST_DND_HG_SND_DATA\n"));
596
597 /* Verify parameter count and types. */
598 if ( cParms != 5
599 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */
600 || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* format */
601 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* format size */
602 || paParms[3].type != VBOX_HGCM_SVC_PARM_PTR /* data */
603 || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* data size */)
604 {
605 rc = VERR_INVALID_PARAMETER;
606 }
607 else
608 {
609 DnDHGSendDataMessage *pMessage =
610 new DnDHGSendDataMessage(uMsg, cParms, paParms,
611 m_pfnProgressCallback, m_pvProgressUser);
612 m_dndMessageQueue.append(pMessage);
613 }
614 break;
615 }
616
617#ifdef VBOX_WITH_DRAG_AND_DROP_GH
618 case DragAndDropSvc::HOST_DND_GH_REQ_PENDING:
619 {
620 LogFlowFunc(("HOST_DND_GH_REQ_PENDING\n"));
621
622 /* Verify parameter count and types. */
623 if ( cParms != 1
624 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */)
625 {
626 rc = VERR_INVALID_PARAMETER;
627 }
628 else
629 {
630 DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms);
631 m_dndMessageQueue.append(pMessage);
632 }
633 break;
634 }
635
636 case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED:
637 {
638 LogFlowFunc(("HOST_DND_GH_EVT_DROPPED\n"));
639
640 /* Verify parameter count and types. */
641 if ( cParms != 3
642 || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* format */
643 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* format size */
644 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* action */)
645 {
646 rc = VERR_INVALID_PARAMETER;
647 }
648 else
649 {
650 try
651 {
652 DnDGenericMessage *pMessage
653 = new DnDGenericMessage(uMsg, cParms, paParms);
654 m_dndMessageQueue.append(pMessage);
655 }
656 catch(std::bad_alloc &)
657 {
658 rc = VERR_NO_MEMORY;
659 }
660 }
661 break;
662 }
663#endif /* VBOX_WITH_DRAG_AND_DROP_GH */
664
665 default:
666 rc = VERR_NOT_IMPLEMENTED;
667 break;
668 }
669 }
670 catch(std::bad_alloc &)
671 {
672 rc = VERR_NO_MEMORY;
673 }
674
675 return rc;
676}
677
678HGCM::Message* DnDManager::nextHGCMMessage(void)
679{
680 if (m_pCurMsg)
681 return m_pCurMsg->nextHGCMMessage();
682
683 if (m_dndMessageQueue.isEmpty())
684 return NULL;
685
686 return m_dndMessageQueue.first()->nextHGCMMessage();
687}
688
689int DnDManager::nextMessageInfo(uint32_t *puMsg, uint32_t *pcParms)
690{
691 AssertPtrReturn(puMsg, VERR_INVALID_POINTER);
692 AssertPtrReturn(pcParms, VERR_INVALID_POINTER);
693
694 int rc = VINF_SUCCESS;
695
696 if (m_pCurMsg)
697 rc = m_pCurMsg->currentMessageInfo(puMsg, pcParms);
698 else
699 {
700 if (m_dndMessageQueue.isEmpty())
701 {
702 rc = VERR_NO_DATA;
703// if (m_pfnProgressCallback)
704// m_pfnProgressCallback(100.0, DragAndDropSvc::DND_OP_CANCELLED, m_pvProgressUser);
705 }
706 else
707 rc = m_dndMessageQueue.first()->currentMessageInfo(puMsg, pcParms);
708 }
709
710 LogFlowFunc(("Returning puMsg=%RU32, pcParms=%RU32, rc=%Rrc\n", *puMsg, *pcParms, rc));
711 return rc;
712}
713
714int DnDManager::nextMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
715{
716 LogFlowFunc(("uMsg=%RU32, cParms=%RU32\n", uMsg, cParms));
717
718 if (!m_pCurMsg)
719 {
720 /* Check for pending messages in our queue. */
721 if (m_dndMessageQueue.isEmpty())
722 {
723 LogFlowFunc(("Message queue is empty, returning\n"));
724 return VERR_NO_DATA;
725 }
726
727 m_pCurMsg = m_dndMessageQueue.first();
728 m_dndMessageQueue.removeFirst();
729 }
730
731 /* Fetch the current message info */
732 int rc = m_pCurMsg->currentMessage(uMsg, cParms, paParms);
733 /* If this message doesn't provide any additional sub messages, clear it. */
734 if (!m_pCurMsg->isMessageWaiting())
735 {
736 delete m_pCurMsg;
737 m_pCurMsg = NULL;
738 }
739
740 /*
741 * If there was an error handling the current message or the user has canceled
742 * the operation, we need to cleanup all pending events and inform the progress
743 * callback about our exit.
744 */
745 if ( RT_FAILURE(rc)
746 && m_pfnProgressCallback)
747 {
748 /* Clear any pending messages. */
749 clear();
750
751 /* Create a new cancel message to inform the guest + call
752 * the host whether the current transfer was canceled or aborted
753 * due to an error. */
754 try
755 {
756 Assert(!m_pCurMsg);
757 m_pCurMsg = new DnDHGCancelMessage();
758 m_pfnProgressCallback(100 /* Percent */,
759 rc == VERR_CANCELLED
760 ? DragAndDropSvc::DND_PROGRESS_CANCELLED
761 : DragAndDropSvc::DND_PROGRESS_ERROR, rc, m_pvProgressUser);
762 }
763 catch(std::bad_alloc &)
764 {
765 rc = VERR_NO_MEMORY;
766 }
767 }
768
769 LogFlowFunc(("Message processed with rc=%Rrc\n", rc));
770 return rc;
771}
772
773void DnDManager::clear(void)
774{
775 if (m_pCurMsg)
776 {
777 delete m_pCurMsg;
778 m_pCurMsg = 0;
779 }
780
781 while (!m_dndMessageQueue.isEmpty())
782 {
783 delete m_dndMessageQueue.last();
784 m_dndMessageQueue.removeLast();
785 }
786}
787
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