--- /dev/null
+/*********************************************************
+ * Copyright (C) 2010 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * 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 Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * capsProvider.h --
+ *
+ * Interface implemented by dnd manager objects to obtain their
+ * capabilities. Mainly needed by Windows host and guest code.
+ */
+
+#ifndef __CAPS_PROVIDER_H__
+#define __CAPS_PROVIDER_H__
+
+#if defined VMX86_TOOLS || COMPILE_WITHOUT_CUI
+# ifdef LIB_EXPORT
+# undef LIB_EXPORT
+# endif
+#define LIB_EXPORT
+#else
+#include "libExport.hh"
+#endif
+
+#if defined(SWIG)
+class CapsProvider
+#else
+class LIB_EXPORT CapsProvider
+#endif
+{
+public:
+ virtual ~CapsProvider() {};
+ virtual Bool CheckCapability(uint32 caps) = 0;
+};
+
+#endif
+
virtual void DnDVersionChanged(const int version) = 0;
virtual void SetCopyPasteAllowed(bool allowed) = 0;
virtual void SetDnDAllowed(bool allowed) = 0;
+ virtual uint32 GetCaps() = 0;
};
#endif // __COPYPASTEDNDIMPL_H__
/*
* We only support DnD/CP V3 and greater.
*/
+ GuestDnDCPMgr *p = GuestDnDCPMgr::GetInstance();
+ ASSERT(p);
if (GetDnDVersion() >= 3 && GetCPVersion() >= 3 || GetCPVersion() == 1) {
- GuestDnDCPMgr *p = GuestDnDCPMgr::GetInstance();
- ASSERT(p);
p->Init(ctx);
}
#endif
if (m_pimpl) {
m_pimpl->Init(ctx);
+ /*
+ * Tell the Guest DnD Manager what capabilities we support.
+ */
+ p->SetCaps(m_pimpl->GetCaps());
}
}
}
return ret;
}
+
+
+/**
+ * Get capabilities by calling platform implementation.
+ *
+ * @return 32-bit mask of DnD/CP capabilities.
+ */
+
+uint32
+CopyPasteDnDWrapper::GetCaps()
+{
+ ASSERT(m_pimpl);
+
+ return m_pimpl->GetCaps();
+}
void Init(ToolsAppCtx *ctx);
void PointerInit(void);
ToolsAppCtx *GetToolsAppCtx() {return m_ctx;};
+ uint32 GetCaps();
private:
/*
* We're a singleton, so it is a compile time error to call these.
Pointer_Init(ctx);
}
+
+
+/**
+ * Return platform DnD/CP caps.
+ *
+ * @return 32-bit caps vector.
+ */
+
+uint32
+CopyPasteDnDX11::GetCaps()
+{
+ return DND_CP_CAP_VALID |
+ DND_CP_CAP_DND |
+ DND_CP_CAP_CP |
+ DND_CP_CAP_FORMATS_ALL |
+ DND_CP_CAP_ACTIVE_CP |
+ DND_CP_CAP_BIG_BUFFER;
+}
virtual void UnregisterDnD();
virtual void DnDVersionChanged(int version);
virtual void CopyPasteVersionChanged(int version);
+ virtual uint32 GetCaps();
void SetUnityMode(Bool mode) {m_dndUI->SetUnityMode(mode);};
void SetDnDAllowed(bool allowed);
void SetCopyPasteAllowed(bool allowed);
/* First check for URIs. This must always be done first */
bool haveURIs = false;
std::string format;
- if (refClipboard->wait_is_target_available(FCP_TARGET_NAME_GNOME_COPIED_FILES)) {
+ if (mCP->CheckCapability(DND_CP_CAP_FILE_CP) && refClipboard->wait_is_target_available(FCP_TARGET_NAME_GNOME_COPIED_FILES)) {
format = FCP_TARGET_NAME_GNOME_COPIED_FILES;
haveURIs = true;
- } else if (refClipboard->wait_is_target_available(FCP_TARGET_NAME_URI_LIST)) {
+ } else if (mCP->CheckCapability(DND_CP_CAP_FILE_CP) && refClipboard->wait_is_target_available(FCP_TARGET_NAME_URI_LIST)) {
format = FCP_TARGET_NAME_URI_LIST;
haveURIs = true;
}
/* Try to get image data from clipboard. */
Glib::RefPtr<Gdk::Pixbuf> img = refClipboard->wait_for_image();
gsize bufSize;
- if (img) {
+ if (mCP->CheckCapability(DND_CP_CAP_IMAGE_CP) && img) {
gchar *buf = NULL;
img->save_to_buffer(buf, bufSize, Glib::ustring("png"));
haveRTF = true;
}
- if (haveRTF) {
+ if (mCP->CheckCapability(DND_CP_CAP_RTF_CP) && haveRTF) {
/*
* There is a function for waiting for rtf data, but that was leading
* to crashes. It's use required we instantiate a class that implements
}
/* Try to get Text data from clipboard. */
- if (refClipboard->wait_is_text_available()) {
+ if (mCP->CheckCapability(DND_CP_CAP_PLAIN_TEXT_CP) &&
+ refClipboard->wait_is_text_available()) {
g_debug("%s: ask for text\n", __FUNCTION__);
Glib::ustring str = refClipboard->wait_for_text();
bufSize = str.bytes();
g_debug("%s: enter", __FUNCTION__);
const utf::string target = sd.get_target().c_str();
+ if (!mCP->CheckCapability(DND_CP_CAP_FILE_CP)) {
+ /*
+ * Disallowed based on caps settings, return.
+ */
+ return;
+ }
if (target == FCP_TARGET_NAME_GNOME_COPIED_FILES ||
target == FCP_TARGET_NAME_URI_LIST) {
LocalGetSelectionFileList(sd);
utf::string pre;
utf::string post;
+ if (!mCP->CheckCapability(DND_CP_CAP_FILE_CONTENT_CP)) {
+ /*
+ * Disallowed based on caps settings, return.
+ */
+ return;
+ }
+
sd.set(sd.get_target().c_str(), "");
/* Provide URIs for each path in the guest's file list. */
sigc::signal<void, uint32, const uint8 *, uint32> requestFilesChanged;
sigc::signal<void, uint32, bool, const uint8 *, uint32> getFilesDoneChanged;
- /* sigc signals for CopyPaste destination callback. */
+ /* sigc signal for CopyPaste destination callback. */
sigc::signal<void, uint32, bool> destRequestClipChanged;
+ /* sigc signal for ping reply callback. */
+ sigc::signal<void, uint32> pingReplyChanged;
+
+ /* sigc signal for rpc command reply received. */
+ sigc::signal<void, uint32, uint32> cmdReplyChanged;
+
virtual void Init(void) = 0;
+ virtual void SendPing(uint32 caps) = 0;
/* CopyPaste Rpc functions. */
virtual bool SrcRequestClip(uint32 sessionId,
{
public:
CopyPasteRpcV4(DnDCPTransport *transport);
-
virtual void Init(void);
+ virtual void SendPing(uint32 caps);
/* CopyPaste Rpc functions. */
virtual bool SrcRequestClip(uint32 sessionId,
#define DND_CP_CAP_GUEST_PROGRESS (1 << 14)
#define DND_CP_CAP_BIG_BUFFER (1 << 15)
+#define DND_CP_CAP_FORMATS_CP (DND_CP_CAP_PLAIN_TEXT_CP | \
+ DND_CP_CAP_RTF_CP | \
+ DND_CP_CAP_IMAGE_CP | \
+ DND_CP_CAP_FILE_CP | \
+ DND_CP_CAP_FILE_CONTENT_CP)
+
+#define DND_CP_CAP_FORMATS_DND (DND_CP_CAP_PLAIN_TEXT_DND | \
+ DND_CP_CAP_RTF_DND | \
+ DND_CP_CAP_IMAGE_DND | \
+ DND_CP_CAP_FILE_DND | \
+ DND_CP_CAP_FILE_CONTENT_DND)
+
+#define DND_CP_CAP_FORMATS_ALL (DND_CP_CAP_FORMATS_CP | \
+ DND_CP_CAP_FORMATS_DND)
+
/*
* Header definition for DnD version 4 packet. Any DnD version 4 packet has 2
* parts: fixed header and payload. payload is optional.
#include "dndClipboard.h"
#include "dndInt.h"
+#include "dndCPMsgV4.h"
#define CPFormatToIndex(x) ((unsigned int)(x) - 1)
CPClipboard_Destroy(clip);
return FALSE;
}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CPClipboard_Strip --
+ *
+ * Remove clipboard items based on the passed in capabilities mask.
+ * Introduced in DnDV4.
+ *
+ * XXX This function assumes that the bits in mask are such that if the
+ * check is being made for copy paste, that the corresponding bit for
+ * DnD is set to zero. Otherwise, the format cleared by copy paste will
+ * not be removed. Similar for the other case. A way to make this clearer
+ * would be to pass a flag to this function that tells it which bits
+ * to check, with no dependencies on the other bits being in proper
+ * state.
+ *
+ * Results:
+ * TRUE if clipboard is empty as a result, else FALSE.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+Bool
+CPClipboard_Strip(CPClipboard *clip, // IN/OUT: the clipboard
+ uint32 mask) // IN: if TRUE, DnD.
+{
+ if (!(mask & DND_CP_CAP_PLAIN_TEXT_DND) &&
+ !(mask & DND_CP_CAP_PLAIN_TEXT_CP)) {
+ CPClipboard_ClearItem(clip, CPFORMAT_TEXT);
+ }
+ if (!(mask & DND_CP_CAP_RTF_DND) && !(mask & DND_CP_CAP_RTF_CP)) {
+ CPClipboard_ClearItem(clip, CPFORMAT_RTF);
+ }
+ if (!(mask & DND_CP_CAP_IMAGE_DND) && !(mask & DND_CP_CAP_IMAGE_CP)) {
+ CPClipboard_ClearItem(clip, CPFORMAT_IMG_PNG);
+ }
+ if (!(mask & DND_CP_CAP_FILE_DND) && !(mask & DND_CP_CAP_FILE_CP)) {
+ CPClipboard_ClearItem(clip, CPFORMAT_FILELIST);
+ CPClipboard_ClearItem(clip, CPFORMAT_FILELIST_URI);
+ }
+ if (!(mask & DND_CP_CAP_FILE_CONTENT_DND) &&
+ !(mask & DND_CP_CAP_FILE_CONTENT_CP)) {
+ CPClipboard_ClearItem(clip, CPFORMAT_FILECONTENTS);
+ }
+ return CPClipboard_IsEmpty(clip);
+}
Bool CPClipboard_Copy(CPClipboard *dest, const CPClipboard *src);
Bool CPClipboard_Serialize(const CPClipboard *clip, DynBuf *buf);
Bool CPClipboard_Unserialize(CPClipboard *clip, const void *buf, size_t len);
+Bool CPClipboard_Strip(CPClipboard *clip, uint32 caps);
#endif // _DND_CLIPBOARD_H_
sigc::signal<void, uint32, const uint8 *, uint32> requestFileChanged;
sigc::signal<void, uint32, bool, const uint8 *, uint32> getFilesDoneChanged;
+ /* sigc signal for responding to ping reply */
+ sigc::signal<void, uint32> pingReplyChanged;
+
+ /* sigc signal for rpc cmd reply received. */
+ sigc::signal<void, uint32, uint32> cmdReplyChanged;
+
/* DnD source. */
virtual bool SrcDragBeginDone(uint32 sessionId) = 0;
virtual bool SrcDrop(uint32 sessionId, int32 x, int32 y) = 0;
/* Common. */
virtual void Init(void) = 0;
+ virtual void SendPing(uint32 caps) = 0;
virtual bool UpdateFeedback(uint32 sessionId, DND_DROPEFFECT feedback) = 0;
virtual bool MoveMouse(uint32 sessionId,
int32 x,
DnDRpcV4(DnDCPTransport *transport);
virtual void Init(void);
+ virtual void SendPing(uint32 caps);
/* DnD source. */
virtual bool SrcDragBeginDone(uint32 sessionId);
}
+/**
+ * Not needed for version 3.
+ *
+ * @param[ignored] caps capabilities mask
+ */
+
+void
+CopyPasteRpcV3::SendPing(uint32 caps)
+{
+ Debug("%s: entering.\n", __FUNCTION__);
+}
+
+
/**
* Not needed for version 3.
*
virtual ~CopyPasteRpcV3(void);
virtual void Init(void);
+ virtual void SendPing(uint32 caps);
/* CopyPaste Rpc functions. */
virtual bool SrcRequestClip(uint32 sessionId,
*/
void
-CopyPasteRpcV4::Init(void)
+CopyPasteRpcV4::Init()
{
ASSERT(mTransport);
mTransport->RegisterRpc(this, mTransportInterface);
- mUtil.SendPingMsg(DEFAULT_CONNECTION_ID, 0);
+}
+
+
+/**
+ * Send Ping message to controller.
+ *
+ * @param[in] caps capabilities value.
+ */
+
+void
+CopyPasteRpcV4::SendPing(uint32 caps)
+{
+ mUtil.SendPingMsg(DEFAULT_CONNECTION_ID, caps);
}
binary,
binarySize);
break;
+ case DNDCP_CMD_PING_REPLY:
+ pingReplyChanged.emit(params->optional.version.capability);
+ break;
+ case DNDCP_CMP_REPLY:
+ LOG(0, ("%s: Got cmp reply command %d.\n", __FUNCTION__, params->cmd));
+ cmdReplyChanged.emit(params->cmd, params->status);
+ break;
default:
LOG(0, ("%s: Got unknown command %d.\n", __FUNCTION__, params->cmd));
break;
virtual ~DnDRpcV3(void);
virtual void Init(void);
+ virtual void SendPing(uint32 caps) {};
/* DnD source. */
virtual bool SrcDragBeginDone(uint32 sessionId);
*/
void
-DnDRpcV4::Init(void)
+DnDRpcV4::Init()
{
ASSERT(mTransport);
mTransport->RegisterRpc(this, mTransportInterface);
- mUtil.SendPingMsg(DEFAULT_CONNECTION_ID, 0);
+}
+
+
+/**
+ * Send Ping message to controller.
+ *
+ * @param[in] caps capabilities value.
+ */
+
+void
+DnDRpcV4::SendPing(uint32 caps)
+{
+ mUtil.SendPingMsg(DEFAULT_CONNECTION_ID, caps);
}
binarySize);
break;
case DNDCP_CMD_PING_REPLY:
+ pingReplyChanged.emit(params->optional.version.capability);
break;
case DNDCP_CMD_TEST_BIG_BINARY:
{
break;
}
+ case DNDCP_CMP_REPLY:
+ LOG(0, ("%s: Got cmp reply command %d.\n", __FUNCTION__, params->cmd));
+ cmdReplyChanged.emit(params->cmd, params->status);
+ break;
default:
LOG(0, ("%s: Got unknown command %d.\n", __FUNCTION__, params->cmd));
break;
void SetCopyPasteAllowed(bool isCopyPasteAllowed)
{ mCopyPasteAllowed = isCopyPasteAllowed; }
void VmxCopyPasteVersionChanged(uint32 version);
-
+ Bool CheckCapability(uint32 capsRequest);
private:
void OnRpcSrcRecvClip(uint32 sessionId,
bool isActive,
const CPClipboard *clip);
void OnRpcDestRequestClip(uint32 sessionId,
bool isActive);
+ void OnPingReply(uint32 capabilities);
GuestCopyPasteSrc *mSrc;
GuestCopyPasteDest *mDest;
CopyPasteRpc *mRpc;
DnDCPTransport *mTransport;
uint32 mSessionId;
bool mCopyPasteAllowed;
+ uint32 mResolvedCaps; // caps as returned in ping reply, or default.
};
#include "guestCopyPaste.hh"
#include "copyPasteRpcV3.hh"
#include "copyPasteRpcV4.hh"
+#include "guestDnDCPMgr.hh"
extern "C" {
#include "debug.h"
mCPState(GUEST_CP_READY),
mTransport(transport),
mSessionId(0),
- mCopyPasteAllowed(false)
+ mCopyPasteAllowed(false),
+ mResolvedCaps(0xffffffff)
{
ASSERT(transport);
}
break;
}
if (mRpc) {
- mRpc->Init();
+ Debug("GuestCopyPasteMgr::%s: register ping reply changed %d\n",
+ __FUNCTION__, version);
+ mRpc->pingReplyChanged.connect(
+ sigc::mem_fun(this, &GuestCopyPasteMgr::OnPingReply));
mRpc->srcRecvClipChanged.connect(
sigc::mem_fun(this, &GuestCopyPasteMgr::OnRpcSrcRecvClip));
mRpc->destRequestClipChanged.connect(
sigc::mem_fun(this, &GuestCopyPasteMgr::OnRpcDestRequestClip));
+ mRpc->Init();
+ mRpc->SendPing(GuestDnDCPMgr::GetInstance()->GetCaps() &
+ (DND_CP_CAP_CP | DND_CP_CAP_FORMATS_CP | DND_CP_CAP_VALID));
}
ResetCopyPaste();
}
+
+
+/**
+ * Check if a request is allowed based on resolved capabilities.
+ *
+ * @param[in] capsRequest requested capabilities.
+ *
+ * @return TRUE if allowed, FALSE otherwise.
+ */
+
+Bool
+GuestCopyPasteMgr::CheckCapability(uint32 capsRequest)
+{
+ Bool allowed = FALSE;
+
+ if ((mResolvedCaps & capsRequest) == capsRequest) {
+ allowed = TRUE;
+ }
+ return allowed;
+}
+
+
+/**
+ * Got pingReplyChanged message. Update capabilities.
+ *
+ * @param[in] capability modified capabilities from VMX controller.
+ */
+
+void
+GuestCopyPasteMgr::OnPingReply(uint32 capabilities)
+{
+ Debug("%s: copypaste ping reply caps are %x\n", __FUNCTION__, capabilities);
+ mResolvedCaps = capabilities;
+}
+
#include "dndRpcV4.hh"
#include "guestFileTransfer.hh"
+#include "capsProvider.h"
+
#include <string>
extern "C" {
class GuestDnDDest;
class GuestDnDMgr
- : public sigc::trackable
+ : public sigc::trackable, public CapsProvider
{
public:
GuestDnDMgr(DnDCPTransport *transport,
{ mDnDAllowed = isDnDAllowed;}
void VmxDnDVersionChanged(uint32 version);
bool IsDragEnterAllowed(void);
-
+ Bool CheckCapability(uint32 capsRequest);
private:
void OnRpcSrcDragBegin(uint32 sessionId,
const CPClipboard *clip);
void OnRpcMoveMouse(uint32 sessionId,
int32 x,
int32 y);
+ void OnPingReply(uint32 capabilities);
+
GuestDnDSrc *mSrc;
GuestDnDDest *mDest;
DnDRpc *mRpc;
bool mDnDAllowed;
uint32 mVmxDnDVersion;
DnDCPTransport *mDnDTransport;
+ uint32 mCapabilities;
};
mCPMgr(NULL),
mFileTransfer(NULL),
mTransport(NULL),
- mToolsAppCtx(NULL)
+ mToolsAppCtx(NULL),
+ mLocalCaps(0xffffffff)
{
}
mTransport->EndLoop();
}
}
-
void EndLoop();
void IterateLoop();
void Init(ToolsAppCtx *ctx);
-
+ void SetCaps(uint32 caps) {mLocalCaps = caps;};
+ uint32 GetCaps() {return mLocalCaps;};
private:
/* We're a singleton, so it is a compile time error to call these. */
GuestDnDCPMgr(void);
GuestFileTransfer *mFileTransfer;
DnDCPTransport *mTransport;
ToolsAppCtx *mToolsAppCtx;
+ uint32 mLocalCaps;
};
#endif // GUEST_DND_CP_HH
#include "guestDnD.hh"
#include "dndRpcV4.hh"
#include "dndRpcV3.hh"
+#include "guestDnDCPMgr.hh"
extern "C" {
#include "debug.h"
mUngrabTimeout(NULL),
mToolsAppCtx(ctx),
mDnDAllowed(false),
- mDnDTransport(transport)
+ mDnDTransport(transport),
+ mCapabilities(0xffffffff)
{
ASSERT(transport);
ASSERT(mToolsAppCtx);
break;
}
if (mRpc) {
- mRpc->Init();
+ mRpc->pingReplyChanged.connect(
+ sigc::mem_fun(this, &GuestDnDMgr::OnPingReply));
mRpc->srcDragBeginChanged.connect(
sigc::mem_fun(this, &GuestDnDMgr::OnRpcSrcDragBegin));
mRpc->queryExitingChanged.connect(
sigc::mem_fun(this, &GuestDnDMgr::OnRpcUpdateUnityDetWnd));
mRpc->moveMouseChanged.connect(
sigc::mem_fun(this, &GuestDnDMgr::OnRpcMoveMouse));
+ mRpc->Init();
+ mRpc->SendPing(GuestDnDCPMgr::GetInstance()->GetCaps() &
+ (DND_CP_CAP_DND | DND_CP_CAP_FORMATS_DND |
+ DND_CP_CAP_VALID));
}
ResetDnD();
}
+
+
+/**
+ * Check if a request is allowed based on resolved capabilities.
+ *
+ * @param[in] capsRequest requested capabilities.
+ *
+ * @return TRUE if allowed, FALSE otherwise.
+ */
+
+Bool
+GuestDnDMgr::CheckCapability(uint32 capsRequest)
+{
+ Bool allowed = FALSE;
+
+ if ((mCapabilities & capsRequest) == capsRequest) {
+ allowed = TRUE;
+ }
+ return allowed;
+}
+
+
+/**
+ * Got pingReplyChanged message. Update capabilities.
+ *
+ * @param[in] capability modified capabilities from VMX controller.
+ */
+
+void
+GuestDnDMgr::OnPingReply(uint32 capabilities)
+{
+ Debug("%s: dnd ping reply caps are %x\n", __FUNCTION__, capabilities);
+ mCapabilities = capabilities;
+}
+
const utf::string target = sd.get_target().c_str();
/* Try to get file list. */
- if (target == DRAG_TARGET_NAME_URI_LIST) {
+ if (m_DnD->CheckCapability(DND_CP_CAP_FILE_DND) && target == DRAG_TARGET_NAME_URI_LIST) {
/*
* Turn the uri list into two \0 delimited lists. One for full paths and
* one for just the last path component.
}
/* Try to get plain text. */
- if (target == TARGET_NAME_STRING ||
+ if (m_DnD->CheckCapability(DND_CP_CAP_PLAIN_TEXT_DND) && (
+ target == TARGET_NAME_STRING ||
target == TARGET_NAME_TEXT_PLAIN ||
target == TARGET_NAME_UTF8_STRING ||
- target == TARGET_NAME_COMPOUND_TEXT) {
+ target == TARGET_NAME_COMPOUND_TEXT)) {
utf::string source = sd.get_data_as_string().c_str();
if (source.bytes() > 0 &&
source.bytes() < DNDMSG_MAX_ARGSZ &&
}
/* Try to get RTF string. */
- if (target == TARGET_NAME_APPLICATION_RTF ||
- target == TARGET_NAME_TEXT_RICHTEXT) {
+ if (m_DnD->CheckCapability(DND_CP_CAP_RTF_DND) && (
+ target == TARGET_NAME_APPLICATION_RTF ||
+ target == TARGET_NAME_TEXT_RICHTEXT)) {
utf::string source = sd.get_data_as_string().c_str();
if (source.bytes() > 0 &&
source.bytes() < DNDMSG_MAX_ARGSZ &&
/**
- * Update version information in mDnD.
+ * Update version information in m_DnD.
*
* @param[ignored] chan RpcChannel pointer
* @param[in] version the version negotiated with host.