diff options
Diffstat (limited to '')
-rw-r--r-- | src/VBox/HostServices/DragAndDrop/dndmanager.cpp | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/src/VBox/HostServices/DragAndDrop/dndmanager.cpp b/src/VBox/HostServices/DragAndDrop/dndmanager.cpp new file mode 100644 index 00000000..137df6cc --- /dev/null +++ b/src/VBox/HostServices/DragAndDrop/dndmanager.cpp @@ -0,0 +1,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; + } + } +} + |