VirtualBox

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

Last change on this file since 45020 was 44102, checked in by vboxsync, 12 years ago

HostServices/Dnd: avoid floating point arithmetics here

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