summaryrefslogtreecommitdiffstats
path: root/src/VBox/HostServices/DragAndDrop/dndmanager.cpp
blob: 137df6cc32c08e388189f04ccb1d75ed53cbd7fd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
/* $Id: dndmanager.cpp $ */
/** @file
 * Drag and Drop manager: Handling of DnD messages on the host side.
 */

/*
 * Copyright (C) 2011-2023 Oracle and/or its affiliates.
 *
 * This file is part of VirtualBox base platform packages, as
 * available from https://www.virtualbox.org.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation, in version 3 of the
 * License.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <https://www.gnu.org/licenses>.
 *
 * SPDX-License-Identifier: GPL-3.0-only
 */


/*********************************************************************************************************************************
*   Header Files                                                                                                                 *
*********************************************************************************************************************************/

#ifdef LOG_GROUP
 #undef LOG_GROUP
#endif
#define LOG_GROUP LOG_GROUP_GUEST_DND

#include "dndmanager.h"

#include <VBox/log.h>
#include <iprt/file.h>
#include <iprt/dir.h>
#include <iprt/path.h>
#include <iprt/uri.h>


/*********************************************************************************************************************************
*   DnDManager                                                                                                                   *
*********************************************************************************************************************************/

/**
 * Adds a DnD message to the manager's queue.
 *
 * @returns IPRT status code.
 * @param   pMsg                Pointer to DnD message to add. The queue then owns the pointer.
 * @param   fAppend             Whether to append or prepend the message to the queue.
 */
int DnDManager::AddMsg(DnDMessage *pMsg, bool fAppend /* = true */)
{
    AssertPtrReturn(pMsg, VERR_INVALID_POINTER);

    LogFlowFunc(("uMsg=%s (%#x), cParms=%RU32, fAppend=%RTbool\n",
                 DnDHostMsgToStr(pMsg->GetType()), pMsg->GetType(), pMsg->GetParamCount(), fAppend));

    if (fAppend)
        m_queueMsg.append(pMsg);
    else
        m_queueMsg.prepend(pMsg);

#ifdef DEBUG
    DumpQueue();
#endif

    /** @todo Catch / handle OOM? */

    return VINF_SUCCESS;
}

/**
 * Adds a DnD message to the manager's queue.
 *
 * @returns IPRT status code.
 * @param   uMsg                Type (function number) of message to add.
 * @param   cParms              Number of parameters of message to add.
 * @param   paParms             Array of parameters of message to add.
 * @param   fAppend             Whether to append or prepend the message to the queue.
 */
int DnDManager::AddMsg(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool fAppend /* = true */)
{
    int rc;

    try
    {
        DnDMessage *pMsg = new DnDGenericMessage(uMsg, cParms, paParms);
        rc = AddMsg(pMsg, fAppend);
    }
    catch(std::bad_alloc &)
    {
        rc = VERR_NO_MEMORY;
    }

    LogFlowFuncLeaveRC(rc);
    return rc;
}

#ifdef DEBUG
void DnDManager::DumpQueue(void)
{
    LogFunc(("Current queue (%zu items, FIFO) is: %s", m_queueMsg.size(), m_queueMsg.isEmpty() ? "<Empty>" : ""));
    for (size_t i = 0; i < m_queueMsg.size(); ++i)
    {
        if (i > 0)
            Log((" - "));
        DnDMessage const *pMsg = m_queueMsg[i];
        uint32_t const uType = pMsg->GetType();
        Log(("%s (%d / %#x) cRefS=%RU32", DnDHostMsgToStr(uType), uType, uType, pMsg->RefCount()));
    }
    Log(("\n"));
}
#endif /* DEBUG */

/**
 * Retrieves information about the next message in the queue.
 *
 * @returns IPRT status code. VERR_NO_DATA if no next message is available.
 * @param   fAddRef             Set to \c true to increase the message's reference count, or \c false if not.
 * @param   puType              Where to store the message type.
 * @param   pcParms             Where to store the message parameter count.
 */
int DnDManager::GetNextMsgInfo(bool fAddRef, uint32_t *puType, uint32_t *pcParms)
{
    AssertPtrReturn(puType, VERR_INVALID_POINTER);
    AssertPtrReturn(pcParms, VERR_INVALID_POINTER);

    int rc;

    if (m_queueMsg.isEmpty())
    {
        rc = VERR_NO_DATA;
    }
    else
    {
        DnDMessage *pMsg = m_queueMsg.first();
        AssertPtr(pMsg);

        *puType  = pMsg->GetType();
        *pcParms = pMsg->GetParamCount();

        if (fAddRef)
            pMsg->AddRef();

        rc = VINF_SUCCESS;
    }

#ifdef DEBUG
    DumpQueue();
#endif

    LogFlowFunc(("Returning uMsg=%s (%#x), cParms=%RU32, fAddRef=%RTbool, rc=%Rrc\n",
                 DnDHostMsgToStr(*puType), *puType, *pcParms, fAddRef, rc));
    return rc;
}

/**
 * Retrieves the next queued up message and removes it from the queue on success.
 *
 * @returns VBox status code.
 * @retval  VERR_NO_DATA if no next message is available.
 * @param   uMsg                Message type to retrieve.
 * @param   cParms              Number of parameters the \@a paParms array can store.
 * @param   paParms             Where to store the message parameters.
 */
int DnDManager::GetNextMsg(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
{
    LogFlowFunc(("uMsg=%s (%#x), cParms=%RU32\n", DnDHostMsgToStr(uMsg), uMsg, cParms));

    /* Check for pending messages in our queue. */
    if (m_queueMsg.isEmpty())
        return VERR_NO_DATA;

#ifdef DEBUG
    DumpQueue();
#endif

    /* Get the current message. */
    DnDMessage *pMsg = m_queueMsg.first();
    AssertPtr(pMsg);

    if (pMsg->Release() == 0)     /* Not referenced by any client anymore? */
        m_queueMsg.removeFirst(); /* Remove the current message from the queue. */

    /* Fetch the current message info. */
    int rc = pMsg->GetData(uMsg, cParms, paParms);

    /*
     * If there was an error handling the current message or the user has canceled
     * the operation, we need to cleanup all pending events.
     */
    if (RT_FAILURE(rc))
    {
        /* Clear any pending messages. */
        Reset(true /* fForce */);
    }

    LogFlowFunc(("Message processed with rc=%Rrc\n", rc));
    return rc;
}

/**
 * Resets the manager by clearing the message queue and internal state.
 *
 * @param   fForce              Set to \c true to forcefully also remove still referenced messages, or \c false to only
 *                              remove non-referenced messages.
 */
void DnDManager::Reset(bool fForce)
{
    LogFlowFuncEnter();

#ifdef DEBUG
    DumpQueue();
#endif

    for (size_t i = 0; i < m_queueMsg.size(); i++)
    {
        if (   fForce
            || m_queueMsg[i]->RefCount() == 0)
        {
            m_queueMsg.removeAt(i);
            i = i > 0 ? i - 1 : 0;
        }
    }
}