VirtualBox

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

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

DnD/Main: Renamed GuestDnDMsg::setNextXXX() -> GuestDnDMsg::appendXXX().

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.6 KB
Line 
1/* $Id: GuestDnDPrivate.h 85554 2020-07-30 13:07:17Z 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 */
361 int init(size_t cbBuf = _64K)
362 {
363 reset();
364
365 pvScratchBuf = RTMemAlloc(cbBuf);
366 if (!pvScratchBuf)
367 return VERR_NO_MEMORY;
368
369 cbScratchBuf = cbBuf;
370 return VINF_SUCCESS;
371 }
372
373 /**
374 * Destroys a transfer data object.
375 */
376 void destroy(void)
377 {
378 reset();
379
380 if (pvScratchBuf)
381 {
382 Assert(cbScratchBuf);
383 RTMemFree(pvScratchBuf);
384 pvScratchBuf = NULL;
385 }
386 cbScratchBuf = 0;
387 }
388
389 /**
390 * Resets a transfer data object.
391 */
392 void reset(void)
393 {
394 LogFlowFuncEnter();
395
396 cObjToProcess = 0;
397 cObjProcessed = 0;
398 }
399
400 /**
401 * Returns whether this transfer object is complete or not.
402 *
403 * @returns \c true if complete, \c false if not.
404 */
405 bool isComplete(void) const
406 {
407 return (cObjProcessed == cObjToProcess);
408 }
409
410 /** Number of objects to process. */
411 uint64_t cObjToProcess;
412 /** Number of objects already processed. */
413 uint64_t cObjProcessed;
414 /** Pointer to an optional scratch buffer to use for
415 * doing the actual chunk transfers. */
416 void *pvScratchBuf;
417 /** Size (in bytes) of scratch buffer. */
418 size_t cbScratchBuf;
419};
420
421/**
422 * Class for keeping around DnD transfer send data (Host -> Guest).
423 */
424struct GuestDnDTransferSendData : public GuestDnDTransferData
425{
426 GuestDnDTransferSendData()
427 : fObjState(0)
428 {
429 RT_ZERO(List);
430 int rc2 = DnDTransferListInit(&List);
431 AssertRC(rc2);
432 }
433
434 virtual ~GuestDnDTransferSendData()
435 {
436 destroy();
437 }
438
439 /**
440 * Destroys the object.
441 */
442 void destroy(void)
443 {
444 DnDTransferListDestroy(&List);
445 }
446
447 /**
448 * Resets the object.
449 */
450 void reset(void)
451 {
452 DnDTransferListReset(&List);
453 fObjState = 0;
454
455 GuestDnDTransferData::reset();
456 }
457
458 /** Transfer List to handle. */
459 DNDTRANSFERLIST List;
460 /** Current state of object in transfer.
461 * This is needed for keeping compatibility to old(er) DnD HGCM protocols.
462 *
463 * At the moment we only support transferring one object at a time. */
464 uint32_t fObjState;
465};
466
467/**
468 * Context structure for sending data to the guest.
469 */
470struct GuestDnDSendCtx : public GuestDnDData
471{
472 GuestDnDSendCtx(void);
473
474 /**
475 * Resets the object.
476 */
477 void reset(void);
478
479 /** Pointer to guest target class this context belongs to. */
480 GuestDnDTarget *pTarget;
481 /** Pointer to guest response class this context belongs to. */
482 GuestDnDResponse *pResp;
483 /** Target (VM) screen ID. */
484 uint32_t uScreenID;
485 /** Transfer data structure. */
486 GuestDnDTransferSendData Transfer;
487 /** Callback event to use. */
488 GuestDnDCallbackEvent EventCallback;
489};
490
491struct GuestDnDTransferRecvData : public GuestDnDTransferData
492{
493 GuestDnDTransferRecvData()
494 {
495 RT_ZERO(DroppedFiles);
496 int rc2 = DnDDroppedFilesInit(&DroppedFiles);
497 AssertRC(rc2);
498
499 RT_ZERO(List);
500 rc2 = DnDTransferListInit(&List);
501 AssertRC(rc2);
502
503 RT_ZERO(ObjCur);
504 rc2 = DnDTransferObjectInit(&ObjCur);
505 AssertRC(rc2);
506 }
507
508 virtual ~GuestDnDTransferRecvData()
509 {
510 destroy();
511 }
512
513 /**
514 * Destroys the object.
515 */
516 void destroy(void)
517 {
518 DnDTransferListDestroy(&List);
519 }
520
521 /**
522 * Resets the object.
523 */
524 void reset(void)
525 {
526 DnDDroppedFilesClose(&DroppedFiles);
527 DnDTransferListReset(&List);
528 DnDTransferObjectReset(&ObjCur);
529
530 GuestDnDTransferData::reset();
531 }
532
533 /** The "VirtualBox Dropped Files" directory on the host we're going
534 * to utilize for transferring files from guest to the host. */
535 DNDDROPPEDFILES DroppedFiles;
536 /** Transfer List to handle.
537 * Currently we only support one transfer list at a time. */
538 DNDTRANSFERLIST List;
539 /** Current transfer object being handled.
540 * Currently we only support one transfer object at a time. */
541 DNDTRANSFEROBJECT ObjCur;
542};
543
544/**
545 * Context structure for receiving data from the guest.
546 */
547struct GuestDnDRecvCtx : public GuestDnDData
548{
549 GuestDnDRecvCtx(void);
550
551 /**
552 * Resets the object.
553 */
554 void reset(void);
555
556 /** Pointer to guest source class this context belongs to. */
557 GuestDnDSource *pSource;
558 /** Pointer to guest response class this context belongs to. */
559 GuestDnDResponse *pResp;
560 /** Formats offered by the guest (and supported by the host). */
561 GuestDnDMIMEList lstFmtOffered;
562 /** Original drop format requested to receive from the guest. */
563 com::Utf8Str strFmtReq;
564 /** Intermediate drop format to be received from the guest.
565 * Some original drop formats require a different intermediate
566 * drop format:
567 *
568 * Receiving a file link as "text/plain" requires still to
569 * receive the file from the guest as "text/uri-list" first,
570 * then pointing to the file path on the host with the data
571 * in "text/plain" format returned. */
572 com::Utf8Str strFmtRecv;
573 /** Desired drop action to perform on the host.
574 * Needed to tell the guest if data has to be
575 * deleted e.g. when moving instead of copying. */
576 VBOXDNDACTION enmAction;
577 /** Transfer data structure. */
578 GuestDnDTransferRecvData Transfer;
579 /** Callback event to use. */
580 GuestDnDCallbackEvent EventCallback;
581};
582
583/**
584 * Class for maintainig a (buffered) guest DnD message.
585 */
586class GuestDnDMsg
587{
588public:
589
590 GuestDnDMsg(void)
591 : uMsg(0)
592 , cParms(0)
593 , cParmsAlloc(0)
594 , paParms(NULL) { }
595
596 virtual ~GuestDnDMsg(void)
597 {
598 reset();
599 }
600
601public:
602
603 /**
604 * Appends a new HGCM parameter to the message and returns the pointer to it.
605 */
606 PVBOXHGCMSVCPARM getNextParam(void)
607 {
608 if (cParms >= cParmsAlloc)
609 {
610 if (!paParms)
611 paParms = (PVBOXHGCMSVCPARM)RTMemAlloc(4 * sizeof(VBOXHGCMSVCPARM));
612 else
613 paParms = (PVBOXHGCMSVCPARM)RTMemRealloc(paParms, (cParmsAlloc + 4) * sizeof(VBOXHGCMSVCPARM));
614 if (!paParms)
615 throw VERR_NO_MEMORY;
616 RT_BZERO(&paParms[cParmsAlloc], 4 * sizeof(VBOXHGCMSVCPARM));
617 cParmsAlloc += 4;
618 }
619
620 return &paParms[cParms++];
621 }
622
623 /**
624 * Returns the current parameter count.
625 *
626 * @returns Current parameter count.
627 */
628 uint32_t getCount(void) const { return cParms; }
629
630 /**
631 * Returns the pointer to the beginning of the HGCM parameters array. Use with care.
632 *
633 * @returns Pointer to the beginning of the HGCM parameters array.
634 */
635 PVBOXHGCMSVCPARM getParms(void) const { return paParms; }
636
637 /**
638 * Returns the message type.
639 *
640 * @returns Message type.
641 */
642 uint32_t getType(void) const { return uMsg; }
643
644 /**
645 * Resets the object.
646 */
647 void reset(void)
648 {
649 if (paParms)
650 {
651 /* Remove deep copies. */
652 for (uint32_t i = 0; i < cParms; i++)
653 {
654 if ( paParms[i].type == VBOX_HGCM_SVC_PARM_PTR
655 && paParms[i].u.pointer.size)
656 {
657 AssertPtr(paParms[i].u.pointer.addr);
658 RTMemFree(paParms[i].u.pointer.addr);
659 }
660 }
661
662 RTMemFree(paParms);
663 paParms = NULL;
664 }
665
666 uMsg = cParms = cParmsAlloc = 0;
667 }
668
669 /**
670 * Appends a new message parameter of type pointer.
671 *
672 * @returns VBox status code.
673 * @param pvBuf Pointer to data to use.
674 * @param cbBuf Size (in bytes) of data to use.
675 */
676 int appendPointer(void *pvBuf, uint32_t cbBuf)
677 {
678 PVBOXHGCMSVCPARM pParm = getNextParam();
679 if (!pParm)
680 return VERR_NO_MEMORY;
681
682 void *pvTmp = NULL;
683 if (cbBuf)
684 {
685 AssertPtr(pvBuf);
686 pvTmp = RTMemDup(pvBuf, cbBuf);
687 if (!pvTmp)
688 return VERR_NO_MEMORY;
689 }
690
691 HGCMSvcSetPv(pParm, pvTmp, cbBuf);
692 return VINF_SUCCESS;
693 }
694
695 /**
696 * Appends a new message parameter of type string.
697 *
698 * @returns VBox status code.
699 * @param pszString Pointer to string data to use.
700 */
701 int appendString(const char *pszString)
702 {
703 PVBOXHGCMSVCPARM pParm = getNextParam();
704 if (!pParm)
705 return VERR_NO_MEMORY;
706
707 char *pszTemp = RTStrDup(pszString);
708 if (!pszTemp)
709 return VERR_NO_MEMORY;
710
711 HGCMSvcSetStr(pParm, pszTemp);
712 return VINF_SUCCESS;
713 }
714
715 /**
716 * Appends a new message parameter of type uint32_t.
717 *
718 * @returns VBox status code.
719 * @param u32Val uint32_t value to use.
720 */
721 int appendUInt32(uint32_t u32Val)
722 {
723 PVBOXHGCMSVCPARM pParm = getNextParam();
724 if (!pParm)
725 return VERR_NO_MEMORY;
726
727 HGCMSvcSetU32(pParm, u32Val);
728 return VINF_SUCCESS;
729 }
730
731 /**
732 * Appends a new message parameter of type uint64_t.
733 *
734 * @returns VBox status code.
735 * @param u64Val uint64_t value to use.
736 */
737 int appendUInt64(uint64_t u64Val)
738 {
739 PVBOXHGCMSVCPARM pParm = getNextParam();
740 if (!pParm)
741 return VERR_NO_MEMORY;
742
743 HGCMSvcSetU64(pParm, u64Val);
744 return VINF_SUCCESS;
745 }
746
747 /**
748 * Sets the HGCM message type (function number).
749 *
750 * @param uMsgType Message type to set.
751 */
752 void setType(uint32_t uMsgType) { uMsg = uMsgType; }
753
754protected:
755
756 /** Message type. */
757 uint32_t uMsg;
758 /** Message parameters. */
759 uint32_t cParms;
760 /** Size of array. */
761 uint32_t cParmsAlloc;
762 /** Array of HGCM parameters */
763 PVBOXHGCMSVCPARM paParms;
764};
765
766/** Guest DnD callback function definition. */
767typedef DECLCALLBACKPTR(int, PFNGUESTDNDCALLBACK,(uint32_t uMsg, void *pvParms, size_t cbParms, void *pvUser));
768
769/**
770 * Structure for keeping a guest DnD callback.
771 * Each callback can handle one HGCM message, however, multiple HGCM messages can be registered
772 * to the same callback (function).
773 */
774typedef struct GuestDnDCallback
775{
776 GuestDnDCallback(void)
777 : uMessgage(0)
778 , pfnCallback(NULL)
779 , pvUser(NULL) { }
780
781 GuestDnDCallback(PFNGUESTDNDCALLBACK pvCB, uint32_t uMsg, void *pvUsr = NULL)
782 : uMessgage(uMsg)
783 , pfnCallback(pvCB)
784 , pvUser(pvUsr) { }
785
786 /** The HGCM message ID to handle. */
787 uint32_t uMessgage;
788 /** Pointer to callback function. */
789 PFNGUESTDNDCALLBACK pfnCallback;
790 /** Pointer to user-supplied data. */
791 void *pvUser;
792} GuestDnDCallback;
793
794/** Contains registered callback pointers for specific HGCM message types. */
795typedef std::map<uint32_t, GuestDnDCallback> GuestDnDCallbackMap;
796
797/** @todo r=andy This class needs to go, as this now is too inflexible when it comes to all
798 * the callback handling/dispatching. It's part of the initial code and only adds
799 * unnecessary complexity. */
800class GuestDnDResponse
801{
802
803public:
804
805 GuestDnDResponse(const ComObjPtr<Guest>& pGuest);
806 virtual ~GuestDnDResponse(void);
807
808public:
809
810 int notifyAboutGuestResponse(void) const;
811 int waitForGuestResponse(RTMSINTERVAL msTimeout = 500) const;
812
813 void setActionsAllowed(VBOXDNDACTIONLIST a) { m_dndLstActionsAllowed = a; }
814 VBOXDNDACTIONLIST getActionsAllowed(void) const { return m_dndLstActionsAllowed; }
815
816 void setActionDefault(VBOXDNDACTION a) { m_dndActionDefault = a; }
817 VBOXDNDACTION getActionDefault(void) const { return m_dndActionDefault; }
818
819 void setFormats(const GuestDnDMIMEList &lstFormats) { m_lstFormats = lstFormats; }
820 GuestDnDMIMEList formats(void) const { return m_lstFormats; }
821
822 void reset(void);
823
824 bool isProgressCanceled(void) const;
825 int setCallback(uint32_t uMsg, PFNGUESTDNDCALLBACK pfnCallback, void *pvUser = NULL);
826 int setProgress(unsigned uPercentage, uint32_t uState, int rcOp = VINF_SUCCESS, const Utf8Str &strMsg = "");
827 HRESULT resetProgress(const ComObjPtr<Guest>& pParent);
828 HRESULT queryProgressTo(IProgress **ppProgress);
829
830public:
831
832 /** @name HGCM callback handling.
833 @{ */
834 int onDispatch(uint32_t u32Function, void *pvParms, uint32_t cbParms);
835 /** @} */
836
837protected:
838
839 /** Pointer to context this class is tied to. */
840 void *m_pvCtx;
841 /** Event for waiting for response. */
842 RTSEMEVENT m_EventSem;
843 /** Default action to perform in case of a
844 * successful drop. */
845 VBOXDNDACTION m_dndActionDefault;
846 /** Actions supported by the guest in case of a successful drop. */
847 VBOXDNDACTIONLIST m_dndLstActionsAllowed;
848 /** Format(s) requested/supported from the guest. */
849 GuestDnDMIMEList m_lstFormats;
850 /** Pointer to IGuest parent object. */
851 ComObjPtr<Guest> m_pParent;
852 /** Pointer to associated progress object. Optional. */
853 ComObjPtr<Progress> m_pProgress;
854 /** Callback map. */
855 GuestDnDCallbackMap m_mapCallbacks;
856};
857
858/**
859 * Private singleton class for the guest's DnD implementation.
860 *
861 * Can't be instanciated directly, only via the factory pattern.
862 * Keeps track of all ongoing DnD transfers.
863 */
864class GuestDnD
865{
866public:
867
868 /**
869 * Creates the Singleton GuestDnD object.
870 *
871 * @returns Newly created Singleton object, or NULL on failure.
872 */
873 static GuestDnD *createInstance(const ComObjPtr<Guest>& pGuest)
874 {
875 Assert(NULL == GuestDnD::s_pInstance);
876 GuestDnD::s_pInstance = new GuestDnD(pGuest);
877 return GuestDnD::s_pInstance;
878 }
879
880 /**
881 * Destroys the Singleton GuestDnD object.
882 */
883 static void destroyInstance(void)
884 {
885 if (GuestDnD::s_pInstance)
886 {
887 delete GuestDnD::s_pInstance;
888 GuestDnD::s_pInstance = NULL;
889 }
890 }
891
892 /**
893 * Returns the Singleton GuestDnD object.
894 *
895 * @returns Pointer to Singleton GuestDnD object, or NULL if not created yet.
896 */
897 static inline GuestDnD *getInstance(void)
898 {
899 AssertPtr(GuestDnD::s_pInstance);
900 return GuestDnD::s_pInstance;
901 }
902
903protected:
904
905 /** List of registered DnD sources. */
906 typedef std::list< ComObjPtr<GuestDnDSource> > GuestDnDSrcList;
907 /** List of registered DnD targets. */
908 typedef std::list< ComObjPtr<GuestDnDTarget> > GuestDnDTgtList;
909
910 /** Constructor; will throw rc on failure. */
911 GuestDnD(const ComObjPtr<Guest>& pGuest);
912 virtual ~GuestDnD(void);
913
914public:
915
916 /** @name Public helper functions.
917 * @{ */
918 HRESULT adjustScreenCoordinates(ULONG uScreenId, ULONG *puX, ULONG *puY) const;
919 int hostCall(uint32_t u32Function, uint32_t cParms, PVBOXHGCMSVCPARM paParms) const;
920 GuestDnDResponse *response(void) { return m_pResponse; }
921 GuestDnDMIMEList defaultFormats(void) const { return m_strDefaultFormats; }
922 /** @} */
923
924 /** @name Source / target management. */
925 int registerSource(const ComObjPtr<GuestDnDSource> &Source);
926 int unregisterSource(const ComObjPtr<GuestDnDSource> &Source);
927 size_t getSourceCount(void);
928
929 int registerTarget(const ComObjPtr<GuestDnDTarget> &Target);
930 int unregisterTarget(const ComObjPtr<GuestDnDTarget> &Target);
931 size_t getTargetCount(void);
932 /** @} */
933
934public:
935
936 /** @name Static low-level HGCM callback handler.
937 * @{ */
938 static DECLCALLBACK(int) notifyDnDDispatcher(void *pvExtension, uint32_t u32Function, void *pvParms, uint32_t cbParms);
939 /** @} */
940
941 /** @name Static helper methods.
942 * @{ */
943 static bool isFormatInFormatList(const com::Utf8Str &strFormat, const GuestDnDMIMEList &lstFormats);
944 static GuestDnDMIMEList toFormatList(const com::Utf8Str &strFormats);
945 static com::Utf8Str toFormatString(const GuestDnDMIMEList &lstFormats);
946 static GuestDnDMIMEList toFilteredFormatList(const GuestDnDMIMEList &lstFormatsSupported, const GuestDnDMIMEList &lstFormatsWanted);
947 static GuestDnDMIMEList toFilteredFormatList(const GuestDnDMIMEList &lstFormatsSupported, const com::Utf8Str &strFormatsWanted);
948 static DnDAction_T toMainAction(VBOXDNDACTION dndAction);
949 static std::vector<DnDAction_T> toMainActions(VBOXDNDACTIONLIST dndActionList);
950 static VBOXDNDACTION toHGCMAction(DnDAction_T enmAction);
951 static void toHGCMActions(DnDAction_T enmDefAction, VBOXDNDACTION *pDefAction, const std::vector<DnDAction_T> vecAllowedActions, VBOXDNDACTIONLIST *pLstAllowedActions);
952 /** @} */
953
954protected:
955
956 /** @name Singleton properties.
957 * @{ */
958 /** List of supported default MIME/Content-type formats. */
959 GuestDnDMIMEList m_strDefaultFormats;
960 /** Pointer to guest implementation. */
961 const ComObjPtr<Guest> m_pGuest;
962 /** The current (last) response from the guest. At the
963 * moment we only support only response a time (ARQ-style). */
964 GuestDnDResponse *m_pResponse;
965 /** Critical section to serialize access. */
966 RTCRITSECT m_CritSect;
967 /** Number of active transfers (guest->host or host->guest). */
968 uint32_t m_cTransfersPending;
969 GuestDnDSrcList m_lstSrc;
970 GuestDnDTgtList m_lstTgt;
971 /** @} */
972
973private:
974
975 /** Static pointer to singleton instance. */
976 static GuestDnD *s_pInstance;
977};
978
979/** Access to the GuestDnD's singleton instance. */
980#define GuestDnDInst() GuestDnD::getInstance()
981
982/** List of pointers to guest DnD Messages. */
983typedef std::list<GuestDnDMsg *> GuestDnDMsgList;
984
985/**
986 * IDnDBase class implementation for sharing code between
987 * IGuestDnDSource and IGuestDnDTarget implementation.
988 */
989class GuestDnDBase
990{
991protected:
992
993 GuestDnDBase(void);
994
995protected:
996
997 /** Shared (internal) IDnDBase method implementations.
998 * @{ */
999 HRESULT i_isFormatSupported(const com::Utf8Str &aFormat, BOOL *aSupported);
1000 HRESULT i_getFormats(GuestDnDMIMEList &aFormats);
1001 HRESULT i_addFormats(const GuestDnDMIMEList &aFormats);
1002 HRESULT i_removeFormats(const GuestDnDMIMEList &aFormats);
1003
1004 HRESULT i_getProtocolVersion(ULONG *puVersion);
1005 /** @} */
1006
1007protected:
1008
1009 int getProtocolVersion(uint32_t *puVersion);
1010
1011 /** @name Functions for handling a simple host HGCM message queue.
1012 * @{ */
1013 int msgQueueAdd(GuestDnDMsg *pMsg);
1014 GuestDnDMsg *msgQueueGetNext(void);
1015 void msgQueueRemoveNext(void);
1016 void msgQueueClear(void);
1017 /** @} */
1018
1019 int sendCancel(void);
1020 int updateProgress(GuestDnDData *pData, GuestDnDResponse *pResp, size_t cbDataAdd = 0);
1021 int waitForEvent(GuestDnDCallbackEvent *pEvent, GuestDnDResponse *pResp, RTMSINTERVAL msTimeout);
1022
1023protected:
1024
1025 /** @name Public attributes (through getters/setters).
1026 * @{ */
1027 /** Pointer to guest implementation. */
1028 const ComObjPtr<Guest> m_pGuest;
1029 /** List of supported MIME types by the source. */
1030 GuestDnDMIMEList m_lstFmtSupported;
1031 /** List of offered MIME types to the counterpart. */
1032 GuestDnDMIMEList m_lstFmtOffered;
1033 /** Whether the object still is in pending state. */
1034 bool m_fIsPending;
1035 /** @} */
1036
1037 /**
1038 * Internal stuff.
1039 */
1040 struct
1041 {
1042 /** The DnD protocol version to use, depending on the
1043 * installed Guest Additions. See DragAndDropSvc.h for
1044 * a protocol changelog. */
1045 uint32_t uProtocolVersion;
1046 /** Outgoing message queue (FIFO). */
1047 GuestDnDMsgList lstMsgOut;
1048 } m_DataBase;
1049};
1050#endif /* !MAIN_INCLUDED_GuestDnDPrivate_h */
1051
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