VirtualBox

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

最後變更 在這個檔案從50508是 50508,由 vboxsync 提交於 11 年 前

DnD: Update.

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

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