VirtualBox

source: vbox/trunk/src/VBox/Main/include/GuestDnDPrivate.h@ 85574

Last change on this file since 85574 was 85560, checked in by vboxsync, 5 years ago

DnD/Main: Extended GuestDnD::toFormatList() to be able to specify an optional formats separator.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.8 KB
Line 
1/* $Id: GuestDnDPrivate.h 85560 2020-07-30 13:42:03Z vboxsync $ */
2/** @file
3 * Private guest drag and drop code, used by GuestDnDTarget +
4 * GuestDnDSource.
5 */
6
7/*
8 * Copyright (C) 2011-2020 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#ifndef MAIN_INCLUDED_GuestDnDPrivate_h
20#define MAIN_INCLUDED_GuestDnDPrivate_h
21#ifndef RT_WITHOUT_PRAGMA_ONCE
22# pragma once
23#endif
24
25#include <iprt/dir.h>
26#include <iprt/file.h>
27#include <iprt/path.h>
28
29#include <VBox/hgcmsvc.h> /* For PVBOXHGCMSVCPARM. */
30#include <VBox/GuestHost/DragAndDrop.h>
31#include <VBox/GuestHost/DragAndDropDefs.h>
32#include <VBox/HostServices/DragAndDropSvc.h>
33
34/**
35 * Forward prototype declarations.
36 */
37class Guest;
38class GuestDnDBase;
39class GuestDnDResponse;
40class GuestDnDSource;
41class GuestDnDTarget;
42class Progress;
43
44/**
45 * Type definitions.
46 */
47
48/** List (vector) of MIME types. */
49typedef std::vector<com::Utf8Str> GuestDnDMIMEList;
50
51/**
52 * Class to handle a guest DnD callback event.
53 */
54class GuestDnDCallbackEvent
55{
56public:
57
58 GuestDnDCallbackEvent(void)
59 : m_SemEvent(NIL_RTSEMEVENT)
60 , m_Rc(VINF_SUCCESS) { }
61
62 virtual ~GuestDnDCallbackEvent(void);
63
64public:
65
66 int Reset(void);
67
68 int Notify(int rc = VINF_SUCCESS);
69
70 int Result(void) const { return m_Rc; }
71
72 int Wait(RTMSINTERVAL msTimeout);
73
74protected:
75
76 /** Event semaphore to notify on error/completion. */
77 RTSEMEVENT m_SemEvent;
78 /** Callback result. */
79 int m_Rc;
80};
81
82/**
83 * Struct for handling the (raw) meta data.
84 */
85struct GuestDnDMetaData
86{
87 GuestDnDMetaData(void)
88 : pvData(NULL)
89 , cbData(0)
90 , cbAllocated(0)
91 , cbAnnounced(0) { }
92
93 virtual ~GuestDnDMetaData(void)
94 {
95 reset();
96 }
97
98 /**
99 * Adds new meta data.
100 *
101 * @returns New (total) meta data size in bytes.
102 * @param pvDataAdd Pointer of data to add.
103 * @param cbDataAdd Size (in bytes) of data to add.
104 */
105 size_t add(const void *pvDataAdd, size_t cbDataAdd)
106 {
107 LogFlowThisFunc(("cbAllocated=%zu, cbAnnounced=%zu, pvDataAdd=%p, cbDataAdd=%zu\n",
108 cbAllocated, cbAnnounced, pvDataAdd, cbDataAdd));
109 if (!cbDataAdd)
110 return 0;
111 AssertPtrReturn(pvDataAdd, 0);
112
113 const size_t cbAllocatedTmp = cbData + cbDataAdd;
114 if (cbAllocatedTmp > cbAllocated)
115 {
116 int rc = resize(cbAllocatedTmp);
117 if (RT_FAILURE(rc))
118 return 0;
119 }
120
121 Assert(cbAllocated >= cbData + cbDataAdd);
122 memcpy((uint8_t *)pvData + cbData, pvDataAdd, cbDataAdd);
123
124 cbData += cbDataAdd;
125
126 return cbData;
127 }
128
129 /**
130 * Adds new meta data.
131 *
132 * @returns New (total) meta data size in bytes.
133 * @param vecAdd Meta data to add.
134 */
135 size_t add(const std::vector<BYTE> &vecAdd)
136 {
137 if (!vecAdd.size())
138 return 0;
139
140 if (vecAdd.size() > UINT32_MAX) /* Paranoia. */
141 return 0;
142
143 return add(&vecAdd.front(), (uint32_t)vecAdd.size());
144 }
145
146 /**
147 * Resets (clears) all data.
148 */
149 void reset(void)
150 {
151 strFmt = "";
152
153 if (pvData)
154 {
155 Assert(cbAllocated);
156 RTMemFree(pvData);
157 pvData = NULL;
158 }
159
160 cbData = 0;
161 cbAllocated = 0;
162 cbAnnounced = 0;
163 }
164
165 /**
166 * Resizes the allocation size.
167 *
168 * @returns VBox status code.
169 * @param cbSize New allocation size (in bytes).
170 */
171 int resize(size_t cbSize)
172 {
173 if (!cbSize)
174 {
175 reset();
176 return VINF_SUCCESS;
177 }
178
179 if (cbSize == cbAllocated)
180 return VINF_SUCCESS;
181
182 cbSize = RT_ALIGN_Z(cbSize, PAGE_SIZE);
183
184 if (cbSize > _32M) /* Meta data can be up to 32MB. */
185 return VERR_BUFFER_OVERFLOW;
186
187 void *pvTmp = NULL;
188 if (!cbAllocated)
189 {
190 Assert(cbData == 0);
191 pvTmp = RTMemAllocZ(cbSize);
192 }
193 else
194 {
195 AssertPtr(pvData);
196 pvTmp = RTMemRealloc(pvData, cbSize);
197 }
198
199 if (pvTmp)
200 {
201 pvData = pvTmp;
202 cbAllocated = cbSize;
203 return VINF_SUCCESS;
204 }
205
206 return VERR_NO_MEMORY;
207 }
208
209 /** Format string of this meta data. */
210 com::Utf8Str strFmt;
211 /** Pointer to allocated meta data. */
212 void *pvData;
213 /** Used bytes of meta data. Must not exceed cbAllocated. */
214 size_t cbData;
215 /** Size (in bytes) of allocated meta data. */
216 size_t cbAllocated;
217 /** Size (in bytes) of announced meta data. */
218 size_t cbAnnounced;
219};
220
221/**
222 * Struct for accounting shared DnD data to be sent/received.
223 */
224struct GuestDnDData
225{
226 GuestDnDData(void)
227 : cbExtra(0)
228 , cbProcessed(0) { }
229
230 virtual ~GuestDnDData(void)
231 {
232 reset();
233 }
234
235 /**
236 * Adds processed data to the internal accounting.
237 *
238 * @returns New processed data size.
239 * @param cbDataAdd Bytes to add as done processing.
240 */
241 size_t addProcessed(size_t cbDataAdd)
242 {
243 const size_t cbTotal = getTotalAnnounced(); RT_NOREF(cbTotal);
244 AssertReturn(cbProcessed + cbDataAdd <= cbTotal, 0);
245 cbProcessed += cbDataAdd;
246 return cbProcessed;
247 }
248
249 /**
250 * Returns whether all data has been processed or not.
251 *
252 * @returns \c true if all data has been processed, \c false if not.
253 */
254 bool isComplete(void) const
255 {
256 const size_t cbTotal = getTotalAnnounced();
257 LogFlowFunc(("cbProcessed=%zu, cbTotal=%zu\n", cbProcessed, cbTotal));
258 AssertReturn(cbProcessed <= cbTotal, true);
259 return (cbProcessed == cbTotal);
260 }
261
262 /**
263 * Returns the percentage (0-100) of the already processed data.
264 *
265 * @returns Percentage (0-100) of the already processed data.
266 */
267 uint8_t getPercentComplete(void) const
268 {
269 const size_t cbTotal = getTotalAnnounced();
270 return (uint8_t)(cbProcessed * 100 / RT_MAX(cbTotal, 1));
271 }
272
273 /**
274 * Returns the remaining (outstanding) data left for processing.
275 *
276 * @returns Remaining (outstanding) data (in bytes) left for processing.
277 */
278 size_t getRemaining(void) const
279 {
280 const size_t cbTotal = getTotalAnnounced();
281 AssertReturn(cbProcessed <= cbTotal, 0);
282 return cbTotal - cbProcessed;
283 }
284
285 /**
286 * Returns the total data size (in bytes) announced.
287 *
288 * @returns Total data size (in bytes) announced.
289 */
290 size_t getTotalAnnounced(void) const
291 {
292 return Meta.cbAnnounced + cbExtra;
293 }
294
295 /**
296 * Returns the total data size (in bytes) available.
297 * For receiving data, this represents the already received data.
298 * For sending data, this represents the data left to send.
299 *
300 * @returns Total data size (in bytes) available.
301 */
302 size_t getTotalAvailable(void) const
303 {
304 return Meta.cbData + cbExtra;
305 }
306
307 /**
308 * Resets all data.
309 */
310 void reset(void)
311 {
312 Meta.reset();
313
314 cbExtra = 0;
315 cbProcessed = 0;
316 }
317
318 /** For storing the actual meta data.
319 * This might be an URI list or just plain raw data,
320 * according to the format being sent. */
321 GuestDnDMetaData Meta;
322 /** Extra data to send/receive (in bytes). Can be 0 for raw data.
323 * For (file) transfers this is the total size for all files. */
324 size_t cbExtra;
325 /** Overall size (in bytes) of processed data. */
326 size_t cbProcessed;
327};
328
329/** Initial object context state / no state set. */
330#define DND_OBJ_STATE_NONE 0
331/** The header was received / sent. */
332#define DND_OBJ_STATE_HAS_HDR RT_BIT(0)
333/** Validation mask for object context state. */
334#define DND_OBJ_STATE_VALID_MASK UINT32_C(0x00000001)
335
336/**
337 * Base class for keeping around DnD (file) transfer data.
338 * Used for sending / receiving transfer data.
339 */
340struct GuestDnDTransferData
341{
342
343public:
344
345 GuestDnDTransferData(void)
346 : cObjToProcess(0)
347 , cObjProcessed(0)
348 , pvScratchBuf(NULL)
349 , cbScratchBuf(0) { }
350
351 virtual ~GuestDnDTransferData(void)
352 {
353 destroy();
354 }
355
356 /**
357 * Initializes a transfer data object.
358 *
359 * @param cbBuf Scratch buffer size (in bytes) to use.
360 * If not specified, DND_DEFAULT_CHUNK_SIZE will be used.
361 */
362 int init(size_t cbBuf = DND_DEFAULT_CHUNK_SIZE)
363 {
364 reset();
365
366 pvScratchBuf = RTMemAlloc(cbBuf);
367 if (!pvScratchBuf)
368 return VERR_NO_MEMORY;
369
370 cbScratchBuf = cbBuf;
371 return VINF_SUCCESS;
372 }
373
374 /**
375 * Destroys a transfer data object.
376 */
377 void destroy(void)
378 {
379 reset();
380
381 if (pvScratchBuf)
382 {
383 Assert(cbScratchBuf);
384 RTMemFree(pvScratchBuf);
385 pvScratchBuf = NULL;
386 }
387 cbScratchBuf = 0;
388 }
389
390 /**
391 * Resets a transfer data object.
392 */
393 void reset(void)
394 {
395 LogFlowFuncEnter();
396
397 cObjToProcess = 0;
398 cObjProcessed = 0;
399 }
400
401 /**
402 * Returns whether this transfer object is complete or not.
403 *
404 * @returns \c true if complete, \c false if not.
405 */
406 bool isComplete(void) const
407 {
408 return (cObjProcessed == cObjToProcess);
409 }
410
411 /** Number of objects to process. */
412 uint64_t cObjToProcess;
413 /** Number of objects already processed. */
414 uint64_t cObjProcessed;
415 /** Pointer to an optional scratch buffer to use for
416 * doing the actual chunk transfers. */
417 void *pvScratchBuf;
418 /** Size (in bytes) of scratch buffer. */
419 size_t cbScratchBuf;
420};
421
422/**
423 * Class for keeping around DnD transfer send data (Host -> Guest).
424 */
425struct GuestDnDTransferSendData : public GuestDnDTransferData
426{
427 GuestDnDTransferSendData()
428 : fObjState(0)
429 {
430 RT_ZERO(List);
431 int rc2 = DnDTransferListInit(&List);
432 AssertRC(rc2);
433 }
434
435 virtual ~GuestDnDTransferSendData()
436 {
437 destroy();
438 }
439
440 /**
441 * Destroys the object.
442 */
443 void destroy(void)
444 {
445 DnDTransferListDestroy(&List);
446 }
447
448 /**
449 * Resets the object.
450 */
451 void reset(void)
452 {
453 DnDTransferListReset(&List);
454 fObjState = 0;
455
456 GuestDnDTransferData::reset();
457 }
458
459 /** Transfer List to handle. */
460 DNDTRANSFERLIST List;
461 /** Current state of object in transfer.
462 * This is needed for keeping compatibility to old(er) DnD HGCM protocols.
463 *
464 * At the moment we only support transferring one object at a time. */
465 uint32_t fObjState;
466};
467
468/**
469 * Context structure for sending data to the guest.
470 */
471struct GuestDnDSendCtx : public GuestDnDData
472{
473 GuestDnDSendCtx(void);
474
475 /**
476 * Resets the object.
477 */
478 void reset(void);
479
480 /** Pointer to guest target class this context belongs to. */
481 GuestDnDTarget *pTarget;
482 /** Pointer to guest response class this context belongs to. */
483 GuestDnDResponse *pResp;
484 /** Target (VM) screen ID. */
485 uint32_t uScreenID;
486 /** Transfer data structure. */
487 GuestDnDTransferSendData Transfer;
488 /** Callback event to use. */
489 GuestDnDCallbackEvent EventCallback;
490};
491
492struct GuestDnDTransferRecvData : public GuestDnDTransferData
493{
494 GuestDnDTransferRecvData()
495 {
496 RT_ZERO(DroppedFiles);
497 int rc2 = DnDDroppedFilesInit(&DroppedFiles);
498 AssertRC(rc2);
499
500 RT_ZERO(List);
501 rc2 = DnDTransferListInit(&List);
502 AssertRC(rc2);
503
504 RT_ZERO(ObjCur);
505 rc2 = DnDTransferObjectInit(&ObjCur);
506 AssertRC(rc2);
507 }
508
509 virtual ~GuestDnDTransferRecvData()
510 {
511 destroy();
512 }
513
514 /**
515 * Destroys the object.
516 */
517 void destroy(void)
518 {
519 DnDTransferListDestroy(&List);
520 }
521
522 /**
523 * Resets the object.
524 */
525 void reset(void)
526 {
527 DnDDroppedFilesClose(&DroppedFiles);
528 DnDTransferListReset(&List);
529 DnDTransferObjectReset(&ObjCur);
530
531 GuestDnDTransferData::reset();
532 }
533
534 /** The "VirtualBox Dropped Files" directory on the host we're going
535 * to utilize for transferring files from guest to the host. */
536 DNDDROPPEDFILES DroppedFiles;
537 /** Transfer List to handle.
538 * Currently we only support one transfer list at a time. */
539 DNDTRANSFERLIST List;
540 /** Current transfer object being handled.
541 * Currently we only support one transfer object at a time. */
542 DNDTRANSFEROBJECT ObjCur;
543};
544
545/**
546 * Context structure for receiving data from the guest.
547 */
548struct GuestDnDRecvCtx : public GuestDnDData
549{
550 GuestDnDRecvCtx(void);
551
552 /**
553 * Resets the object.
554 */
555 void reset(void);
556
557 /** Pointer to guest source class this context belongs to. */
558 GuestDnDSource *pSource;
559 /** Pointer to guest response class this context belongs to. */
560 GuestDnDResponse *pResp;
561 /** Formats offered by the guest (and supported by the host). */
562 GuestDnDMIMEList lstFmtOffered;
563 /** Original drop format requested to receive from the guest. */
564 com::Utf8Str strFmtReq;
565 /** Intermediate drop format to be received from the guest.
566 * Some original drop formats require a different intermediate
567 * drop format:
568 *
569 * Receiving a file link as "text/plain" requires still to
570 * receive the file from the guest as "text/uri-list" first,
571 * then pointing to the file path on the host with the data
572 * in "text/plain" format returned. */
573 com::Utf8Str strFmtRecv;
574 /** Desired drop action to perform on the host.
575 * Needed to tell the guest if data has to be
576 * deleted e.g. when moving instead of copying. */
577 VBOXDNDACTION enmAction;
578 /** Transfer data structure. */
579 GuestDnDTransferRecvData Transfer;
580 /** Callback event to use. */
581 GuestDnDCallbackEvent EventCallback;
582};
583
584/**
585 * Class for maintainig a (buffered) guest DnD message.
586 */
587class GuestDnDMsg
588{
589public:
590
591 GuestDnDMsg(void)
592 : uMsg(0)
593 , cParms(0)
594 , cParmsAlloc(0)
595 , paParms(NULL) { }
596
597 virtual ~GuestDnDMsg(void)
598 {
599 reset();
600 }
601
602public:
603
604 /**
605 * Appends a new HGCM parameter to the message and returns the pointer to it.
606 */
607 PVBOXHGCMSVCPARM getNextParam(void)
608 {
609 if (cParms >= cParmsAlloc)
610 {
611 if (!paParms)
612 paParms = (PVBOXHGCMSVCPARM)RTMemAlloc(4 * sizeof(VBOXHGCMSVCPARM));
613 else
614 paParms = (PVBOXHGCMSVCPARM)RTMemRealloc(paParms, (cParmsAlloc + 4) * sizeof(VBOXHGCMSVCPARM));
615 if (!paParms)
616 throw VERR_NO_MEMORY;
617 RT_BZERO(&paParms[cParmsAlloc], 4 * sizeof(VBOXHGCMSVCPARM));
618 cParmsAlloc += 4;
619 }
620
621 return &paParms[cParms++];
622 }
623
624 /**
625 * Returns the current parameter count.
626 *
627 * @returns Current parameter count.
628 */
629 uint32_t getCount(void) const { return cParms; }
630
631 /**
632 * Returns the pointer to the beginning of the HGCM parameters array. Use with care.
633 *
634 * @returns Pointer to the beginning of the HGCM parameters array.
635 */
636 PVBOXHGCMSVCPARM getParms(void) const { return paParms; }
637
638 /**
639 * Returns the message type.
640 *
641 * @returns Message type.
642 */
643 uint32_t getType(void) const { return uMsg; }
644
645 /**
646 * Resets the object.
647 */
648 void reset(void)
649 {
650 if (paParms)
651 {
652 /* Remove deep copies. */
653 for (uint32_t i = 0; i < cParms; i++)
654 {
655 if ( paParms[i].type == VBOX_HGCM_SVC_PARM_PTR
656 && paParms[i].u.pointer.size)
657 {
658 AssertPtr(paParms[i].u.pointer.addr);
659 RTMemFree(paParms[i].u.pointer.addr);
660 }
661 }
662
663 RTMemFree(paParms);
664 paParms = NULL;
665 }
666
667 uMsg = cParms = cParmsAlloc = 0;
668 }
669
670 /**
671 * Appends a new message parameter of type pointer.
672 *
673 * @returns VBox status code.
674 * @param pvBuf Pointer to data to use.
675 * @param cbBuf Size (in bytes) of data to use.
676 */
677 int appendPointer(void *pvBuf, uint32_t cbBuf)
678 {
679 PVBOXHGCMSVCPARM pParm = getNextParam();
680 if (!pParm)
681 return VERR_NO_MEMORY;
682
683 void *pvTmp = NULL;
684 if (cbBuf)
685 {
686 AssertPtr(pvBuf);
687 pvTmp = RTMemDup(pvBuf, cbBuf);
688 if (!pvTmp)
689 return VERR_NO_MEMORY;
690 }
691
692 HGCMSvcSetPv(pParm, pvTmp, cbBuf);
693 return VINF_SUCCESS;
694 }
695
696 /**
697 * Appends a new message parameter of type string.
698 *
699 * @returns VBox status code.
700 * @param pszString Pointer to string data to use.
701 */
702 int appendString(const char *pszString)
703 {
704 PVBOXHGCMSVCPARM pParm = getNextParam();
705 if (!pParm)
706 return VERR_NO_MEMORY;
707
708 char *pszTemp = RTStrDup(pszString);
709 if (!pszTemp)
710 return VERR_NO_MEMORY;
711
712 HGCMSvcSetStr(pParm, pszTemp);
713 return VINF_SUCCESS;
714 }
715
716 /**
717 * Appends a new message parameter of type uint32_t.
718 *
719 * @returns VBox status code.
720 * @param u32Val uint32_t value to use.
721 */
722 int appendUInt32(uint32_t u32Val)
723 {
724 PVBOXHGCMSVCPARM pParm = getNextParam();
725 if (!pParm)
726 return VERR_NO_MEMORY;
727
728 HGCMSvcSetU32(pParm, u32Val);
729 return VINF_SUCCESS;
730 }
731
732 /**
733 * Appends a new message parameter of type uint64_t.
734 *
735 * @returns VBox status code.
736 * @param u64Val uint64_t value to use.
737 */
738 int appendUInt64(uint64_t u64Val)
739 {
740 PVBOXHGCMSVCPARM pParm = getNextParam();
741 if (!pParm)
742 return VERR_NO_MEMORY;
743
744 HGCMSvcSetU64(pParm, u64Val);
745 return VINF_SUCCESS;
746 }
747
748 /**
749 * Sets the HGCM message type (function number).
750 *
751 * @param uMsgType Message type to set.
752 */
753 void setType(uint32_t uMsgType) { uMsg = uMsgType; }
754
755protected:
756
757 /** Message type. */
758 uint32_t uMsg;
759 /** Message parameters. */
760 uint32_t cParms;
761 /** Size of array. */
762 uint32_t cParmsAlloc;
763 /** Array of HGCM parameters */
764 PVBOXHGCMSVCPARM paParms;
765};
766
767/** Guest DnD callback function definition. */
768typedef DECLCALLBACKPTR(int, PFNGUESTDNDCALLBACK,(uint32_t uMsg, void *pvParms, size_t cbParms, void *pvUser));
769
770/**
771 * Structure for keeping a guest DnD callback.
772 * Each callback can handle one HGCM message, however, multiple HGCM messages can be registered
773 * to the same callback (function).
774 */
775typedef struct GuestDnDCallback
776{
777 GuestDnDCallback(void)
778 : uMessgage(0)
779 , pfnCallback(NULL)
780 , pvUser(NULL) { }
781
782 GuestDnDCallback(PFNGUESTDNDCALLBACK pvCB, uint32_t uMsg, void *pvUsr = NULL)
783 : uMessgage(uMsg)
784 , pfnCallback(pvCB)
785 , pvUser(pvUsr) { }
786
787 /** The HGCM message ID to handle. */
788 uint32_t uMessgage;
789 /** Pointer to callback function. */
790 PFNGUESTDNDCALLBACK pfnCallback;
791 /** Pointer to user-supplied data. */
792 void *pvUser;
793} GuestDnDCallback;
794
795/** Contains registered callback pointers for specific HGCM message types. */
796typedef std::map<uint32_t, GuestDnDCallback> GuestDnDCallbackMap;
797
798/** @todo r=andy This class needs to go, as this now is too inflexible when it comes to all
799 * the callback handling/dispatching. It's part of the initial code and only adds
800 * unnecessary complexity. */
801class GuestDnDResponse
802{
803
804public:
805
806 GuestDnDResponse(const ComObjPtr<Guest>& pGuest);
807 virtual ~GuestDnDResponse(void);
808
809public:
810
811 int notifyAboutGuestResponse(void) const;
812 int waitForGuestResponse(RTMSINTERVAL msTimeout = 500) const;
813
814 void setActionsAllowed(VBOXDNDACTIONLIST a) { m_dndLstActionsAllowed = a; }
815 VBOXDNDACTIONLIST getActionsAllowed(void) const { return m_dndLstActionsAllowed; }
816
817 void setActionDefault(VBOXDNDACTION a) { m_dndActionDefault = a; }
818 VBOXDNDACTION getActionDefault(void) const { return m_dndActionDefault; }
819
820 void setFormats(const GuestDnDMIMEList &lstFormats) { m_lstFormats = lstFormats; }
821 GuestDnDMIMEList formats(void) const { return m_lstFormats; }
822
823 void reset(void);
824
825 bool isProgressCanceled(void) const;
826 int setCallback(uint32_t uMsg, PFNGUESTDNDCALLBACK pfnCallback, void *pvUser = NULL);
827 int setProgress(unsigned uPercentage, uint32_t uState, int rcOp = VINF_SUCCESS, const Utf8Str &strMsg = "");
828 HRESULT resetProgress(const ComObjPtr<Guest>& pParent);
829 HRESULT queryProgressTo(IProgress **ppProgress);
830
831public:
832
833 /** @name HGCM callback handling.
834 @{ */
835 int onDispatch(uint32_t u32Function, void *pvParms, uint32_t cbParms);
836 /** @} */
837
838protected:
839
840 /** Pointer to context this class is tied to. */
841 void *m_pvCtx;
842 /** Event for waiting for response. */
843 RTSEMEVENT m_EventSem;
844 /** Default action to perform in case of a
845 * successful drop. */
846 VBOXDNDACTION m_dndActionDefault;
847 /** Actions supported by the guest in case of a successful drop. */
848 VBOXDNDACTIONLIST m_dndLstActionsAllowed;
849 /** Format(s) requested/supported from the guest. */
850 GuestDnDMIMEList m_lstFormats;
851 /** Pointer to IGuest parent object. */
852 ComObjPtr<Guest> m_pParent;
853 /** Pointer to associated progress object. Optional. */
854 ComObjPtr<Progress> m_pProgress;
855 /** Callback map. */
856 GuestDnDCallbackMap m_mapCallbacks;
857};
858
859/**
860 * Private singleton class for the guest's DnD implementation.
861 *
862 * Can't be instanciated directly, only via the factory pattern.
863 * Keeps track of all ongoing DnD transfers.
864 */
865class GuestDnD
866{
867public:
868
869 /**
870 * Creates the Singleton GuestDnD object.
871 *
872 * @returns Newly created Singleton object, or NULL on failure.
873 */
874 static GuestDnD *createInstance(const ComObjPtr<Guest>& pGuest)
875 {
876 Assert(NULL == GuestDnD::s_pInstance);
877 GuestDnD::s_pInstance = new GuestDnD(pGuest);
878 return GuestDnD::s_pInstance;
879 }
880
881 /**
882 * Destroys the Singleton GuestDnD object.
883 */
884 static void destroyInstance(void)
885 {
886 if (GuestDnD::s_pInstance)
887 {
888 delete GuestDnD::s_pInstance;
889 GuestDnD::s_pInstance = NULL;
890 }
891 }
892
893 /**
894 * Returns the Singleton GuestDnD object.
895 *
896 * @returns Pointer to Singleton GuestDnD object, or NULL if not created yet.
897 */
898 static inline GuestDnD *getInstance(void)
899 {
900 AssertPtr(GuestDnD::s_pInstance);
901 return GuestDnD::s_pInstance;
902 }
903
904protected:
905
906 /** List of registered DnD sources. */
907 typedef std::list< ComObjPtr<GuestDnDSource> > GuestDnDSrcList;
908 /** List of registered DnD targets. */
909 typedef std::list< ComObjPtr<GuestDnDTarget> > GuestDnDTgtList;
910
911 /** Constructor; will throw rc on failure. */
912 GuestDnD(const ComObjPtr<Guest>& pGuest);
913 virtual ~GuestDnD(void);
914
915public:
916
917 /** @name Public helper functions.
918 * @{ */
919 HRESULT adjustScreenCoordinates(ULONG uScreenId, ULONG *puX, ULONG *puY) const;
920 int hostCall(uint32_t u32Function, uint32_t cParms, PVBOXHGCMSVCPARM paParms) const;
921 GuestDnDResponse *response(void) { return m_pResponse; }
922 GuestDnDMIMEList defaultFormats(void) const { return m_strDefaultFormats; }
923 /** @} */
924
925 /** @name Source / target management. */
926 int registerSource(const ComObjPtr<GuestDnDSource> &Source);
927 int unregisterSource(const ComObjPtr<GuestDnDSource> &Source);
928 size_t getSourceCount(void);
929
930 int registerTarget(const ComObjPtr<GuestDnDTarget> &Target);
931 int unregisterTarget(const ComObjPtr<GuestDnDTarget> &Target);
932 size_t getTargetCount(void);
933 /** @} */
934
935public:
936
937 /** @name Static low-level HGCM callback handler.
938 * @{ */
939 static DECLCALLBACK(int) notifyDnDDispatcher(void *pvExtension, uint32_t u32Function, void *pvParms, uint32_t cbParms);
940 /** @} */
941
942 /** @name Static helper methods.
943 * @{ */
944 static bool isFormatInFormatList(const com::Utf8Str &strFormat, const GuestDnDMIMEList &lstFormats);
945 static GuestDnDMIMEList toFormatList(const com::Utf8Str &strFormats, const com::Utf8Str &strSep = DND_FORMATS_SEPARATOR);
946 static com::Utf8Str toFormatString(const GuestDnDMIMEList &lstFormats);
947 static GuestDnDMIMEList toFilteredFormatList(const GuestDnDMIMEList &lstFormatsSupported, const GuestDnDMIMEList &lstFormatsWanted);
948 static GuestDnDMIMEList toFilteredFormatList(const GuestDnDMIMEList &lstFormatsSupported, const com::Utf8Str &strFormatsWanted);
949 static DnDAction_T toMainAction(VBOXDNDACTION dndAction);
950 static std::vector<DnDAction_T> toMainActions(VBOXDNDACTIONLIST dndActionList);
951 static VBOXDNDACTION toHGCMAction(DnDAction_T enmAction);
952 static void toHGCMActions(DnDAction_T enmDefAction, VBOXDNDACTION *pDefAction, const std::vector<DnDAction_T> vecAllowedActions, VBOXDNDACTIONLIST *pLstAllowedActions);
953 /** @} */
954
955protected:
956
957 /** @name Singleton properties.
958 * @{ */
959 /** List of supported default MIME/Content-type formats. */
960 GuestDnDMIMEList m_strDefaultFormats;
961 /** Pointer to guest implementation. */
962 const ComObjPtr<Guest> m_pGuest;
963 /** The current (last) response from the guest. At the
964 * moment we only support only response a time (ARQ-style). */
965 GuestDnDResponse *m_pResponse;
966 /** Critical section to serialize access. */
967 RTCRITSECT m_CritSect;
968 /** Number of active transfers (guest->host or host->guest). */
969 uint32_t m_cTransfersPending;
970 GuestDnDSrcList m_lstSrc;
971 GuestDnDTgtList m_lstTgt;
972 /** @} */
973
974private:
975
976 /** Static pointer to singleton instance. */
977 static GuestDnD *s_pInstance;
978};
979
980/** Access to the GuestDnD's singleton instance. */
981#define GuestDnDInst() GuestDnD::getInstance()
982
983/** List of pointers to guest DnD Messages. */
984typedef std::list<GuestDnDMsg *> GuestDnDMsgList;
985
986/**
987 * IDnDBase class implementation for sharing code between
988 * IGuestDnDSource and IGuestDnDTarget implementation.
989 */
990class GuestDnDBase
991{
992protected:
993
994 GuestDnDBase(void);
995
996protected:
997
998 /** Shared (internal) IDnDBase method implementations.
999 * @{ */
1000 bool i_isFormatSupported(const com::Utf8Str &aFormat) const;
1001 const GuestDnDMIMEList &i_getFormats(void) const;
1002 HRESULT i_addFormats(const GuestDnDMIMEList &aFormats);
1003 HRESULT i_removeFormats(const GuestDnDMIMEList &aFormats);
1004
1005 HRESULT i_getProtocolVersion(ULONG *puVersion);
1006 /** @} */
1007
1008protected:
1009
1010 int getProtocolVersion(uint32_t *puVersion);
1011
1012 /** @name Functions for handling a simple host HGCM message queue.
1013 * @{ */
1014 int msgQueueAdd(GuestDnDMsg *pMsg);
1015 GuestDnDMsg *msgQueueGetNext(void);
1016 void msgQueueRemoveNext(void);
1017 void msgQueueClear(void);
1018 /** @} */
1019
1020 int sendCancel(void);
1021 int updateProgress(GuestDnDData *pData, GuestDnDResponse *pResp, size_t cbDataAdd = 0);
1022 int waitForEvent(GuestDnDCallbackEvent *pEvent, GuestDnDResponse *pResp, RTMSINTERVAL msTimeout);
1023
1024protected:
1025
1026 /** @name Public attributes (through getters/setters).
1027 * @{ */
1028 /** Pointer to guest implementation. */
1029 const ComObjPtr<Guest> m_pGuest;
1030 /** List of supported MIME types by the source. */
1031 GuestDnDMIMEList m_lstFmtSupported;
1032 /** List of offered MIME types to the counterpart. */
1033 GuestDnDMIMEList m_lstFmtOffered;
1034 /** Whether the object still is in pending state. */
1035 bool m_fIsPending;
1036 /** @} */
1037
1038 /**
1039 * Internal stuff.
1040 */
1041 struct
1042 {
1043 /** The DnD protocol version to use, depending on the
1044 * installed Guest Additions. See DragAndDropSvc.h for
1045 * a protocol changelog. */
1046 uint32_t uProtocolVersion;
1047 /** Outgoing message queue (FIFO). */
1048 GuestDnDMsgList lstMsgOut;
1049 } m_DataBase;
1050};
1051#endif /* !MAIN_INCLUDED_GuestDnDPrivate_h */
1052
Note: See TracBrowser for help on using the repository browser.

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