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
*********************************************************/
20
* @file copyPasteDnDWrapper.cpp
22
* This singleton class implements a wrapper around various versions of
23
* copy and paste and dnd protocols, and provides some convenience functions
24
* that help to make VMwareUser a bit cleaner.
27
#define G_LOG_DOMAIN "dndcp"
29
#if defined(HAVE_GTKMM)
30
#include "copyPasteDnDX11.h"
34
#include "copyPasteDnDWin32.h"
37
#if defined(__APPLE__)
38
#include "copyPasteDnDMac.h"
41
#include "copyPasteDnDWrapper.h"
42
#include "guestDnDCPMgr.hh"
47
#include "vmware/guestrpc/tclodefs.h"
48
#include "vmware/tools/plugin.h"
49
#include "vmware/tools/utils.h"
54
* CopyPasteDnDWrapper is a singleton, here is a pointer to its only instance.
57
CopyPasteDnDWrapper *CopyPasteDnDWrapper::m_instance = NULL;
61
* Get an instance of CopyPasteDnDWrapper, which is an application singleton.
63
* @return a pointer to the singleton CopyPasteDnDWrapper object, or NULL if
64
* for some reason it could not be allocated.
68
CopyPasteDnDWrapper::GetInstance()
71
m_instance = new CopyPasteDnDWrapper;
80
* Destroy the singleton object.
84
CopyPasteDnDWrapper::Destroy()
87
g_debug("%s: destroying self\n", __FUNCTION__);
99
CopyPasteDnDWrapper::CopyPasteDnDWrapper() :
100
m_isCPEnabled(FALSE),
101
m_isDnDEnabled(FALSE),
102
m_isCPRegistered(FALSE),
103
m_isDnDRegistered(FALSE),
114
* Call the implementation class pointer/grab initialization code. See
115
* the implementation code for further details.
119
CopyPasteDnDWrapper::PointerInit()
123
m_pimpl->PointerInit();
129
* Initialize the wrapper by instantiating the platform specific impl
130
* class. Effectively, this function is a factory that produces a
131
* platform implementation of the DnD/Copy Paste UI layer.
133
* @param[in] ctx tools app context.
137
CopyPasteDnDWrapper::Init(ToolsAppCtx *ctx)
142
* We only support DnD/CP V3 and greater.
144
GuestDnDCPMgr *p = GuestDnDCPMgr::GetInstance();
146
if (GetDnDVersion() >= 3 && GetCPVersion() >= 3 || GetCPVersion() == 1) {
151
#if defined(HAVE_GTKMM)
152
m_pimpl = new CopyPasteDnDX11();
155
m_pimpl = new CopyPasteDnDWin32();
157
#if defined(__APPLE__)
158
m_pimpl = new CopyPasteDnDMac();
163
* Tell the Guest DnD Manager what capabilities we support.
165
p->SetCaps(m_pimpl->GetCaps());
176
CopyPasteDnDWrapper::~CopyPasteDnDWrapper()
178
g_debug("%s: enter\n", __FUNCTION__);
180
if (IsCPRegistered()) {
181
m_pimpl->UnregisterCP();
183
if (IsDnDRegistered()) {
184
m_pimpl->UnregisterDnD();
188
GuestDnDCPMgr::Destroy();
194
* Register copy and paste capabilities with the VMX. Try newest version
195
* first, then fall back to the legacy implementation.
197
* @return TRUE on success, FALSE on failure
201
CopyPasteDnDWrapper::RegisterCP()
203
g_debug("%s: enter\n", __FUNCTION__);
206
return m_pimpl->RegisterCP();
214
* Register DnD capabilities with the VMX. Handled by the platform layer.
216
* @return TRUE on success, FALSE on failure
220
CopyPasteDnDWrapper::RegisterDnD()
222
g_debug("%s: enter\n", __FUNCTION__);
224
if (IsDnDEnabled()) {
225
return m_pimpl->RegisterDnD();
233
* Unregister copy paste capabilities. Handled by platform layer.
237
CopyPasteDnDWrapper::UnregisterCP()
239
g_debug("%s: enter\n", __FUNCTION__);
241
return m_pimpl->UnregisterCP();
247
* Unregister DnD capabilities. Handled by platform layer.
251
CopyPasteDnDWrapper::UnregisterDnD()
253
g_debug("%s: enter\n", __FUNCTION__);
255
return m_pimpl->UnregisterDnD();
261
* Get the version of the copy paste protocol being wrapped.
263
* @return copy paste protocol version.
267
CopyPasteDnDWrapper::GetCPVersion()
269
g_debug("%s: enter\n", __FUNCTION__);
270
if (IsCPRegistered()) {
274
ToolsAppCtx *ctx = GetToolsAppCtx();
275
if (!RpcChannel_Send(ctx->rpc, QUERY_VMX_COPYPASTE_VERSION,
276
strlen(QUERY_VMX_COPYPASTE_VERSION), &reply, &replyLen)) {
277
g_debug("%s: could not get VMX copyPaste "
278
"version capability: %s\n", __FUNCTION__, reply ? reply : "NULL");
281
m_cpVersion = atoi(reply);
285
g_debug("%s: got version %d\n", __FUNCTION__, m_cpVersion);
292
* Get the version of the DnD protocol being wrapped.
294
* @return DnD protocol version.
298
CopyPasteDnDWrapper::GetDnDVersion()
300
g_debug("%s: enter\n", __FUNCTION__);
301
if (IsDnDRegistered()) {
305
ToolsAppCtx *ctx = GetToolsAppCtx();
306
if (!RpcChannel_Send(ctx->rpc, QUERY_VMX_DND_VERSION,
307
strlen(QUERY_VMX_DND_VERSION), &reply, &replyLen)) {
308
g_debug("%s: could not get VMX dnd "
309
"version capability: %s\n", __FUNCTION__, reply ? reply : "NULL");
312
m_dndVersion = atoi(reply);
316
g_debug("%s: got version %d\n", __FUNCTION__, m_dndVersion);
323
* Set a flag indicating that we are wrapping an initialized and registered
324
* copy paste implementation, or not.
326
* @param[in] isRegistered If TRUE, protocol is registered, otherwise FALSE.
330
CopyPasteDnDWrapper::SetCPIsRegistered(gboolean isRegistered)
332
g_debug("%s: enter\n", __FUNCTION__);
333
m_isCPRegistered = isRegistered;
339
* Get the flag indicating that we are wrapping an initialized and registered
340
* copy paste implementation, or not.
342
* @return TRUE if copy paste is initialized, otherwise FALSE.
346
CopyPasteDnDWrapper::IsCPRegistered()
348
g_debug("%s: enter\n", __FUNCTION__);
349
return m_isCPRegistered;
355
* Set a flag indicating that we are wrapping an initialized and registered
356
* DnD implementation, or not.
358
* @param[in] isRegistered If TRUE, protocol is registered, otherwise FALSE.
362
CopyPasteDnDWrapper::SetDnDIsRegistered(gboolean isRegistered)
364
m_isDnDRegistered = isRegistered;
370
* Get the flag indicating that we are wrapping an initialized and registered
371
* DnD implementation, or not.
373
* @return TRUE if DnD is initialized, otherwise FALSE.
377
CopyPasteDnDWrapper::IsDnDRegistered()
379
return m_isDnDRegistered;
385
* Set a flag indicating that copy paste is enabled, or not. This is called
386
* in response to SetOption RPC being received.
388
* @param[in] isEnabled If TRUE, copy paste is enabled, otherwise FALSE.
392
CopyPasteDnDWrapper::SetCPIsEnabled(gboolean isEnabled)
394
g_debug("%s: enter\n", __FUNCTION__);
395
m_isCPEnabled = isEnabled;
396
if (!isEnabled && IsCPRegistered()) {
398
} else if (isEnabled && !IsCPRegistered()) {
406
* Get the flag indicating that copy paste was enabled (via SetOption RPC).
408
* @return TRUE if copy paste is enabled, otherwise FALSE.
412
CopyPasteDnDWrapper::IsCPEnabled()
414
return m_isCPEnabled;
420
* Set a flag indicating that DnD is enabled, or not. This is called
421
* in response to SetOption RPC being received.
423
* @param[in] isEnabled If TRUE, DnD is enabled, otherwise FALSE.
427
CopyPasteDnDWrapper::SetDnDIsEnabled(gboolean isEnabled)
429
m_isDnDEnabled = isEnabled;
430
if (!isEnabled && IsDnDRegistered()) {
432
} else if (isEnabled && !IsDnDRegistered()) {
440
* Get the flag indicating that DnD was enabled (via SetOption) or not.
442
* @return TRUE if DnD is enabled, otherwise FALSE.
446
CopyPasteDnDWrapper::IsDnDEnabled()
448
return m_isDnDEnabled;
454
* Timer callback for reset. Handle it by calling the member function
455
* that handles reset.
457
* @param[in] clientData pointer to the CopyPasteDnDWrapper instance that
460
* @return FALSE always.
464
DnDPluginResetSent(void *clientData)
466
CopyPasteDnDWrapper *p = reinterpret_cast<CopyPasteDnDWrapper *>(clientData);
469
p->OnResetInternal();
480
CopyPasteDnDWrapper::OnResetInternal()
482
g_debug("%s: enter\n", __FUNCTION__);
483
if (IsDnDRegistered()) {
486
if (IsCPRegistered()) {
489
if (IsCPEnabled() && !IsCPRegistered()) {
492
if (IsDnDEnabled() && !IsDnDRegistered()) {
494
* Reset DnD/Copy/Paste only if vmx said we can. The reason is that
495
* we may also get reset request from vmx when user is taking snapshot
496
* or recording. If there is an ongoing DnD/copy/paste, we should not
497
* reset here. For details please refer to bug 375928.
502
ToolsAppCtx *ctx = GetToolsAppCtx();
503
if (!RpcChannel_Send(ctx->rpc, "dnd.is.active",
504
strlen("dnd.is.active"), &reply, &replyLen) ||
505
(0 == atoi(reply))) {
509
if (!IsDnDRegistered() || !IsCPRegistered()) {
510
g_debug("%s: unable to reset fully DnD %d CP %d!\n",
511
__FUNCTION__, IsDnDRegistered(), IsCPRegistered());
520
* Schedule the post-reset actions to happen a little after one cycle of the
521
* RpcIn loop. This will give vmware a chance to receive the ATR
522
* reinitialize the channel if appropriate.
526
CopyPasteDnDWrapper::OnReset()
530
g_debug("%s: enter\n", __FUNCTION__);
531
src = VMTools_CreateTimer(RPC_POLL_TIME * 30);
533
VMTOOLSAPP_ATTACH_SOURCE(m_ctx, src, DnDPluginResetSent, this, NULL);
541
* Handle cap reg. This is cross-platform so handle here instead of the
542
* platform implementation.
546
CopyPasteDnDWrapper::OnCapReg(gboolean set)
548
g_debug("%s: enter\n", __FUNCTION__);
551
const char *toolsDnDVersion = TOOLS_DND_VERSION_4;
552
char *toolsCopyPasteVersion = NULL;
555
ToolsAppCtx *ctx = GetToolsAppCtx();
560
if (!RpcChannel_Send(ctx->rpc, toolsDnDVersion, strlen(toolsDnDVersion),
562
g_debug("%s: could not set guest dnd version capability\n",
565
SetDnDVersion(version);
567
char const *vmxDnDVersion = QUERY_VMX_DND_VERSION;
569
if (!RpcChannel_Send(ctx->rpc, vmxDnDVersion,
570
strlen(vmxDnDVersion), &reply, &replyLen)) {
571
g_debug("%s: could not get VMX dnd version capability, assuming v1\n",
574
SetDnDVersion(version);
576
int version = atoi(reply);
577
ASSERT(version >= 1);
578
SetDnDVersion(version);
579
g_debug("%s: VMX is dnd version %d\n", __FUNCTION__, GetDnDVersion());
582
* VMDB still has version 4 in it, which will cause a V3
583
* host to fail. So, change to version 3. Since we don't
584
* support any other version, we only do this for V3.
586
toolsDnDVersion = TOOLS_DND_VERSION_3;
587
if (!RpcChannel_Send(ctx->rpc, toolsDnDVersion,
588
strlen(toolsDnDVersion), NULL, NULL)) {
590
g_debug("%s: could not set VMX dnd version capability, assuming v1\n",
593
SetDnDVersion(version);
604
toolsCopyPasteVersion = g_strdup_printf(TOOLS_COPYPASTE_VERSION" %d", 4);
605
if (!RpcChannel_Send(ctx->rpc, toolsCopyPasteVersion,
606
strlen(toolsCopyPasteVersion),
608
g_debug("%s: could not set guest copypaste version capability\n",
611
SetCPVersion(version);
613
char const *vmxCopyPasteVersion = QUERY_VMX_COPYPASTE_VERSION;
615
if (!RpcChannel_Send(ctx->rpc, vmxCopyPasteVersion,
616
strlen(vmxCopyPasteVersion), &reply, &replyLen)) {
617
g_debug("%s: could not get VMX copypaste version capability, assuming v1\n",
620
SetCPVersion(version);
622
version = atoi(reply);
623
ASSERT(version >= 1);
624
SetCPVersion(version);
625
g_debug("%s: VMX is copypaste version %d\n", __FUNCTION__,
629
* VMDB still has version 4 in it, which will cause a V3
630
* host to fail. So, change to version 3. Since we don't
631
* support any other version, we only do this for V3.
633
g_free(toolsCopyPasteVersion);
634
toolsCopyPasteVersion = g_strdup_printf(TOOLS_COPYPASTE_VERSION" %d", 3);
635
if (!RpcChannel_Send(ctx->rpc, toolsCopyPasteVersion,
636
strlen(toolsCopyPasteVersion), NULL, NULL)) {
638
g_debug("%s: could not set VMX copypaste version, assuming v1\n",
641
SetCPVersion(version);
647
g_free(toolsCopyPasteVersion);
658
CopyPasteDnDWrapper::OnSetOption(const char *option, const char *value)
660
gboolean ret = false;
666
bEnable = strcmp(value, "1") ? false : true;
667
g_debug("%s: setting option '%s' to '%s'\n", __FUNCTION__, option, value);
668
if (strcmp(option, TOOLSOPTION_ENABLEDND) == 0) {
669
SetDnDIsEnabled(bEnable);
671
} else if (strcmp(option, TOOLSOPTION_COPYPASTE) == 0) {
672
SetCPIsEnabled(bEnable);
681
* Get capabilities by calling platform implementation.
683
* @return 32-bit mask of DnD/CP capabilities.
687
CopyPasteDnDWrapper::GetCaps()
691
return m_pimpl->GetCaps();