1
/*********************************************************
2
* Copyright (C) 2010 VMware, Inc. All rights reserved.
4
* This program is free software; you can redistribute it and/or modify it
5
* under the terms of the GNU Lesser General Public License as published
6
* by the Free Software Foundation version 2.1 and no later version.
8
* This program is distributed in the hope that it will be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10
* or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
11
* License for more details.
13
* You should have received a copy of the GNU Lesser General Public License
14
* along with this program; if not, write to the Free Software Foundation, Inc.,
15
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17
*********************************************************/
22
* Implementation of common layer GuestDnDSrc object for guest.
25
#include "guestDnD.hh"
28
#include "dndClipboard.h"
32
#include "cpNameUtil.h"
40
* @param[in] mgr guest DnD manager
43
GuestDnDSrc::GuestDnDSrc(GuestDnDMgr *mgr)
47
mMgr->GetRpc()->srcDropChanged.connect(
48
sigc::mem_fun(this, &GuestDnDSrc::OnRpcDrop));
49
mMgr->GetRpc()->srcCancelChanged.connect(
50
sigc::mem_fun(this, &GuestDnDSrc::OnRpcCancel));
51
mMgr->GetRpc()->getFilesDoneChanged.connect(
52
sigc::mem_fun(this, &GuestDnDSrc::OnRpcGetFilesDone));
54
CPClipboard_Init(&mClipboard);
62
GuestDnDSrc::~GuestDnDSrc(void)
65
CPClipboard_Destroy(&mClipboard);
66
/* Reset current session id after finished. */
67
mMgr->SetSessionId(0);
72
* Rpc got dragBegin with valid data. Ask UI to show the detection window and
73
* start host->guest DnD inside guest.
75
* @param[in] clip cross-platform clipboard data.
79
GuestDnDSrc::OnRpcDragBegin(const CPClipboard *clip)
84
Debug("%s: state is %d\n", __FUNCTION__, mMgr->GetState());
85
/* Setup staging directory. */
86
mStagingDir = SetupDestDir("");
87
if (mStagingDir.empty()) {
88
Debug("%s: SetupDestDir failed.\n", __FUNCTION__);
92
/* Show detection window in (0, 0). */
93
mMgr->ShowDetWnd(0, 0);
95
CPClipboard_Clear(&mClipboard);
96
CPClipboard_Copy(&mClipboard, clip);
98
mMgr->SetState(GUEST_DND_SRC_DRAGBEGIN_PENDING);
99
Debug("%s: state changed to DRAGBEGIN_PENDING\n", __FUNCTION__);
101
mMgr->srcDragBeginChanged.emit(&mClipboard, mStagingDir);
106
* Guest UI got dragBeginDone. Send dragBeginDone cmd to controller.
110
GuestDnDSrc::UIDragBeginDone(void)
114
Debug("%s: state is %d\n", __FUNCTION__, mMgr->GetState());
115
if (mMgr->GetState() != GUEST_DND_SRC_DRAGBEGIN_PENDING) {
116
/* Reset DnD for any wrong state. */
117
Debug("%s: Bad state: %d\n", __FUNCTION__, mMgr->GetState());
121
if (!mMgr->GetRpc()->SrcDragBeginDone(mMgr->GetSessionId())) {
122
Debug("%s: SrcDragBeginDone failed\n", __FUNCTION__);
126
mMgr->SetState(GUEST_DND_SRC_DRAGGING);
127
Debug("%s: state changed to DRAGGING\n", __FUNCTION__);
136
* Guest UI got DnD feedback. Send updateFeedback cmd to controller.
138
* @param[in] feedback
142
GuestDnDSrc::UIUpdateFeedback(DND_DROPEFFECT feedback)
146
Debug("%s: state is %d\n", __FUNCTION__, mMgr->GetState());
148
/* This operation needs a valid session id from controller. */
149
if (0 == mMgr->GetSessionId()) {
150
Debug("%s: can not get a valid session id from controller.\n",
154
if (!mMgr->GetRpc()->UpdateFeedback(mMgr->GetSessionId(), feedback)) {
155
Debug("%s: UpdateFeedback failed\n", __FUNCTION__);
162
* Got drop cmd from rpc. Ask UI to simulate the drop at (x, y).
164
* @param[in] sessionId active DnD session id
165
* @param[in] x mouse position x.
166
* @param[in] y mouse position y.
170
GuestDnDSrc::OnRpcDrop(uint32 sessionId,
174
char cpName[FILE_MAXPATH];
179
Debug("%s: state is %d\n", __FUNCTION__, mMgr->GetState());
180
if (mMgr->GetState() != GUEST_DND_SRC_DRAGGING) {
181
/* Reset DnD for any wrong state. */
182
Debug("%s: Bad state: %d\n", __FUNCTION__, mMgr->GetState());
185
mMgr->srcDropChanged.emit();
187
if (CPClipboard_ItemExists(&mClipboard, CPFORMAT_FILELIST)) {
188
/* Convert staging name to CP format. */
189
cpNameSize = CPNameUtil_ConvertToRoot(mStagingDir.c_str(),
192
if (cpNameSize < 0) {
193
Debug("%s: Error, could not convert to CPName.\n", __FUNCTION__);
197
if (!mMgr->GetRpc()->SrcDropDone(sessionId,
198
(const uint8 *)cpName,
200
Debug("%s: SrcDropDone failed\n", __FUNCTION__);
204
/* For non-file formats, the DnD is done. Hide detection window. */
206
mMgr->SetState(GUEST_DND_READY);
207
Debug("%s: state changed to READY\n", __FUNCTION__);
217
* Got cancel cmd from rpc. Ask UI to cancel the DnD as source.
219
* @param[in] sessionId active DnD session id
223
GuestDnDSrc::OnRpcCancel(uint32 sessionId)
227
Debug("%s: state is %d\n", __FUNCTION__, mMgr->GetState());
228
mMgr->srcCancelChanged.emit();
229
mMgr->DelayHideDetWnd();
230
mMgr->SetState(GUEST_DND_READY);
231
Debug("%s: state changed to READY\n", __FUNCTION__);
236
* Got getFileDone cmd from rpc. Reset state machine and hide detection window.
238
* @param[in] sessionId active DnD session id
239
* @param[in] success if the file transfer is successful or not
240
* @param[in] stagingCP staging dir name in cross-platform format
241
* @param[in] sz the staging dir name size
245
GuestDnDSrc::OnRpcGetFilesDone(uint32 sessionId,
247
const uint8 *stagingDirCP,
250
if (!success && !mStagingDir.empty()) {
251
/* Delete all files if host canceled the file transfer. */
252
DnD_DeleteStagingFiles(mStagingDir.c_str(), FALSE);
255
/* UI should remove block with this signal. */
256
mMgr->getFilesDoneChanged.emit(success);
258
mMgr->SetState(GUEST_DND_READY);
259
Debug("%s: state changed to READY\n", __FUNCTION__);
264
* Creates a directory for file transfer. If the destination dir is provided,
265
* we will attempt to copy files to that directory.
267
* @param[in] destDir the preferred destination directory
269
* @return the destination directory on success, an empty string on failure.
273
GuestDnDSrc::SetupDestDir(const std::string &destDir)
277
if (!destDir.empty() && File_Exists(destDir.c_str())) {
278
mStagingDir = destDir;
279
const char *lastSep = Str_Strrchr(mStagingDir.c_str(), DIRSEPC);
280
if (lastSep && lastSep[1] != '\0') {
281
mStagingDir += DIRSEPS;
288
newDir = DnD_CreateStagingDirectory();
289
if (newDir != NULL) {
290
mStagingDir = newDir;
292
char *lastSep = Str_Strrchr(newDir, DIRSEPC);
293
if (lastSep && lastSep[1] != '\0') {
294
mStagingDir += DIRSEPS;
297
Debug("%s: destdir: %s", __FUNCTION__, mStagingDir.c_str());
301
Debug("%s: destdir not created", __FUNCTION__);