. Unity: 'Interlock' minimize operations through the host.
. Close up va_list before exiting.
. Shutdown Linux Copy Paste and DnD on X IO error properly.
Signed-off-by: Marcelo Vanzin <mvanzin@vmware.com>
#define PRODUCT_VERSION_WORKSTATION_5 PRODUCT_WORKSTATION_BRIEF_NAME " 5.x"
#define PRODUCT_VERSION_WORKSTATION_6 PRODUCT_WORKSTATION_BRIEF_NAME " 6.0"
#define PRODUCT_VERSION_WORKSTATION_65 PRODUCT_WORKSTATION_BRIEF_NAME " 6.5"
-#define PRODUCT_VERSION_WORKSTATION_70 PRODUCT_WORKSTATION_BRIEF_NAME " 7.0"
+#define PRODUCT_VERSION_WORKSTATION_7 PRODUCT_WORKSTATION_BRIEF_NAME " 7.x"
#define PRODUCT_VERSION_WORKSTATION_80 PRODUCT_WORKSTATION_BRIEF_NAME " 8.0"
#define PRODUCT_VERSION_WORKSTATION_ENTERPRISE_1 "ACE 1.x"
#define PRODUCT_VERSION_WORKSTATION_ENTERPRISE_2 "ACE 2.0"
va_start(vl, arg0);
for (i = 1; i < count; i++) {
if (!PosixConvertToCurrent(va_arg(vl, char *), &argv[i])) {
+ va_end(vl);
goto exit;
}
}
va_start(vl, arg0);
for (i = 1; i < count; i++) {
if (!PosixConvertToCurrent(va_arg(vl, char *), &argv[i])) {
+ va_end(vl);
goto exit;
}
}
const char *args,
size_t argsSize,
void *clientData);
+static Bool UnityTcloConfirmOperation(char const **result,
+ size_t *resultLen,
+ const char *name,
+ const char *args,
+ size_t argsSize,
+ void *clientData);
static void UnitySetAddHiddenWindows(Bool enabled);
static void UnitySetInterlockMinimizeOperation(Bool enabled);
UnityTcloSetDesktopActive, NULL);
RpcIn_RegisterCallback(rpcIn, UNITY_RPC_WINDOW_DESKTOP_SET,
UnityTcloSetWindowDesktop, NULL);
+ RpcIn_RegisterCallback(rpcIn, UNITY_RPC_CONFIRM_OPERATION,
+ UnityTcloConfirmOperation, NULL);
RpcIn_RegisterCallbackEx(rpcIn, UNITY_RPC_SET_OPTIONS,
UnityTcloSetUnityOptions, NULL);
}
+/*
+ *----------------------------------------------------------------------------
+ *
+ * UnityTcloConfirmOperation --
+ *
+ * RPC handler for 'unity.operation.confirm'.
+ *
+ * Results:
+ * TRUE if the confirmation could be handled sucessfully.
+ * FALSE otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+UnityTcloConfirmOperation(char const **result, // OUT
+ size_t *resultLen, // OUT
+ const char *name, // IN
+ const char *args, // IN
+ size_t argsSize, // IN
+ void *clientData) // ignored
+{
+ UnityConfirmOperation unityConfirmOpMsg = {0};
+ UnityConfirmOperationV1 *confirmV1 = NULL;
+ Bool retVal = FALSE;
+ unsigned int ret;
+ Debug("%s: Enter.\n", __FUNCTION__);
+
+ /*
+ * Deserialize the XDR data. Note that the data begins with args + 1 since
+ * there is a space between the RPC name and the XDR serialization.
+ */
+ if (!XdrUtil_Deserialize((char *)args + 1, argsSize - 1,
+ xdr_UnityConfirmOperation, &unityConfirmOpMsg)) {
+ ret = RpcIn_SetRetVals(result, resultLen, "Failed to deserialize data", FALSE);
+ goto exit;
+ }
+
+ confirmV1 = unityConfirmOpMsg.UnityConfirmOperation_u.unityConfirmOpV1;
+ if (MINIMIZE == confirmV1->details.op) {
+ retVal = UnityPlatformConfirmMinimizeOperation(unity.up,
+ confirmV1->windowId,
+ confirmV1->sequence,
+ confirmV1->allow);
+ } else {
+ Debug("%s: Confirmation for unknown operation ID = %d\n", __FUNCTION__,
+ confirmV1->details.op);
+ }
+ /* Free any memory allocated by XDR - we're done with unityConfirmOpMsg */
+ VMX_XDR_FREE(xdr_UnityConfirmOperation, &unityConfirmOpMsg);
+ ret = RpcIn_SetRetVals(result, resultLen, "", retVal);
+
+exit:
+ Debug("%s: Exit.\n", __FUNCTION__);
+ return ret;
+}
+
+
/*
*----------------------------------------------------------------------------
*
break;
case UNITY_UPDATE_REMOVE_WINDOW:
+ /*
+ * Let the platform know that this window has been removed. This is
+ * useful on platforms that must poll for window changes.
+ */
+ UnityPlatformWillRemoveWindow(unity.up, update->u.removeWindow.id);
+
Str_Sprintf(data, sizeof data, "remove %u", update->u.removeWindow.id);
DynBuf_AppendString(buf, data);
break;
while (unityFeatureTable[featureIndex].featureBit != 0) {
if (featuresChanged & unityFeatureTable[featureIndex].featureBit) {
unityFeatureTable[featureIndex].setter(
- optionsMsg.UnityOptions_u.unityOptionsV1->featureMask &
- unityFeatureTable[featureIndex].featureBit);
+ (optionsMsg.UnityOptions_u.unityOptionsV1->featureMask &
+ unityFeatureTable[featureIndex].featureBit) != 0);
}
featureIndex++;
}
}
+/*
+ *----------------------------------------------------------------------------
+ *
+ * UnityXdrRequestOperation --
+ *
+ * XDR encoder function for UnityRequestOperation.
+ *
+ * See UnityXdrSendRpc().
+ *
+ * Results:
+ * Returns true if the XDR struct was encoded successfully.
+ *
+ * Side-effects:
+ * None.
+ *------------------------------------------------------------------------------
+ */
+
+Bool
+UnityXdrRequestOperation(XDR *xdrs, // IN
+ void *arg) // IN
+{
+ ASSERT(xdrs);
+ ASSERT(arg);
+ return xdr_UnityRequestOperation(xdrs, (UnityRequestOperation *) arg);
+}
+
+
+/*
+ *------------------------------------------------------------------------------
+ *
+ * UnitySendRequestMinimizeOperation --
+ *
+ * Send a request for a minimize operation to the host.
+ *
+ * Results:
+ * TRUE if everything is successful.
+ * FALSE otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+Bool
+UnitySendRequestMinimizeOperation(UnityWindowId windowId, // IN
+ uint32 sequence) // IN
+{
+ Bool ret = FALSE;
+ UnityRequestOperation msg = { 0 };
+ UnityRequestOperationV1 v1 = { 0 };
+
+ Debug("%s: Enter.\n", __FUNCTION__);
+
+ v1.windowId = windowId;
+ v1.sequence = sequence;
+ v1.details.op = MINIMIZE;
+
+ msg.ver = UNITY_OP_V1;
+ msg.UnityRequestOperation_u.unityRequestOpV1 = &v1;
+
+ ret = UnityXdrSendRpc(UNITY_RPC_REQUEST_OPERATION,
+ &UnityXdrRequestOperation,
+ &msg);
+
+ Debug("%s: Exit.\n", __FUNCTION__);
+ return ret;
+}
+
+
/*
*----------------------------------------------------------------------------
*
Debug("%s: Do not interlock minimize operations through the host\n",
__FUNCTION__);
}
+ UnityPlatformSetInterlockMinimizeOperation(unity.up, enabled);
}
#include "unityWindowTracker.h"
#include "unity.h"
-
/**
* Container used to store and send Unity updates.
*/
UnityWindowId windowId);
Bool UnityPlatformUnstickWindow(UnityPlatform *up,
UnityWindowId windowId);
+void UnityPlatformSetInterlockMinimizeOperation(UnityPlatform *up,Bool enabled);
+Bool UnityPlatformConfirmMinimizeOperation(UnityPlatform *up,
+ UnityWindowId windowId,
+ uint32 sequence,
+ Bool allow);
Bool UnityPlatformIsUnityRunning(UnityPlatform *up);
Bool UnityPlatformStartHelperThreads(UnityPlatform *up);
void UnityPlatformKillHelperThreads(UnityPlatform *up);
UnityWindowId windowIds[],
uint32 numWindowIds);
+/*
+ * Function called by UnityUpdateCallbackFn whenever a window is removed from
+ * the tracker.
+ *
+ * NOTE: This function is called with the platform lock held.
+ */
+void UnityPlatformWillRemoveWindow(UnityPlatform *up, UnityWindowId windowId);
+
/* Functions implemented in unity.c for use by the platform-specific code. */
void UnityGetUpdateCommon(int flags, DynBuf *buf);
Bool UnityUpdateChannelInit(UnityUpdateChannel *updateChannel);
void UnityUpdateChannelCleanup(UnityUpdateChannel *updateChannel);
Bool UnitySendUpdates(UnityUpdateChannel *updateChannel);
+Bool UnitySendRequestMinimizeOperation(UnityWindowId windowId, uint32 sequence);
/* Sends the provided window contents to the host. */
Bool UnitySendWindowContents(UnityWindowId windowID,
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * UnityPlatformConfirmMinimizeOperation --
+ *
+ * Minimize a window (if allowed) by the host.
+ *
+ * Results:
+ * Returns TRUE if successful, and FALSE otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+Bool
+UnityPlatformConfirmMinimizeOperation(UnityPlatform *up, // IN
+ UnityWindowId windowId, // IN
+ uint32 sequence, // IN
+ Bool allow) // IN
+{
+ ASSERT(up);
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * UnityPlatformSetInterlockMinimizeOperation --
+ *
+ * Enable (or Disable) the interlocking (relaying) of minimize operations
+ * through the host.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+void UnityPlatformSetInterlockMinimizeOperation(UnityPlatform *up, // IN
+ Bool enabled) // IN
+{
+ ASSERT(up);
+}
+
+
+/*
+ *------------------------------------------------------------------------------
+ *
+ * UnityPlatformWillRemoveWindow --
+ *
+ * Called when a window is removed from the UnityWindowTracker.
+ *
+ * NOTE: This function is called with the platform lock held.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *------------------------------------------------------------------------------
+ */
+
+void
+UnityPlatformWillRemoveWindow(UnityPlatform *up, // IN
+ UnityWindowId windowId) // IN
+{
+ ASSERT(up);
+}
+
+
/*
******************************************************************************
* Begin file-scope functions.
}
+/**
+ *
+ * Cancel DnD and copy paste.
+ */
+
+void
+CopyPasteDnDWrapper::Cancel()
+{
+#if defined(HAVE_GTKMM)
+ if (m_dndUI) {
+ m_dndUI->Cancel();
+ }
+ if (m_copyPasteUI) {
+ m_copyPasteUI->Cancel();
+ }
+#endif
+}
+
+
/**
*
* Register DnD capabilities with the VMX. Try newest version
void SetDnDIsRegistered(bool isRegistered);
bool IsDnDRegistered();
void OnReset();
+ void Cancel();
void SetBlockControl(DnDBlockControl *blockCtrl);
void SetUserData(const void *userData);
void SetHGWnd(GtkWidget *wnd) {m_hgWnd = wnd;};
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPasteUI::Cancel --
+ *
+ * Cancel file transfer and remove block.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+CopyPasteUI::Cancel()
+{
+ Debug("%s: enter\n", __FUNCTION__);
+ if (mBlockAdded) {
+ DnD_DeleteStagingFiles(mHGStagingDir.c_str(), FALSE);
+ Debug("%s: removing block for %s\n", __FUNCTION__, mHGStagingDir.c_str());
+ mBlockCtrl->RemoveBlock(mBlockCtrl->fd, mHGStagingDir.c_str());
+ mBlockAdded = false;
+ }
+
+ mFileTransferDone = true;
+}
+
+
/*
*-----------------------------------------------------------------------------
*
void SetCopyPasteAllowed(bool isCopyPasteAllowed)
{ mCP.SetCopyPasteAllowed(isCopyPasteAllowed); }
void Reset(void);
+ void Cancel(void);
void SetBlockControl(DnDBlockControl *blockCtrl)
{ Debug("Setting mBlockCtrl to %p\n", blockCtrl);
mBlockCtrl = blockCtrl; }
}
+/**
+ *
+ * Cancel any DnD file transfers and reset.
+ */
+
+void
+DnDUI::Cancel()
+{
+ Debug("%s: enter\n", __FUNCTION__);
+ if (m_blockAdded) {
+ /*
+ * If we don't do this, the destination will have something to
+ * copy, and likely truncated. So remove it.
+ */
+ DnD_DeleteStagingFiles(m_HGStagingDir.c_str(), false);
+ }
+ CommonResetCB();
+}
+
+
/* Source functions for HG DnD. */
/**
int32 x,
int32 y)
{
+ Debug("%s: enter 0x%lx show %d x %d y %d\n",
+ __FUNCTION__,
+ (unsigned long) m_detWnd->get_window()->gobj(), bShow, x, y);
+
/* If the window is being shown, move it to the right place. */
if (bShow) {
x = MAX(x - DRAG_DET_WINDOW_WIDTH / 2, 0);
uint32 unityWndId,
bool bottom)
{
+ Debug("%s: enter 0x%lx unityID 0x%x\n",
+ __FUNCTION__,
+ (unsigned long) m_detWnd->get_window()->gobj(),
+ unityWndId);
if (bShow && ((unityWndId > 0) || bottom)) {
int width = m_detWnd->GetScreenWidth();
int height = m_detWnd->GetScreenHeight();
/*
* If this is a Host to Guest drag, we are done here, so return.
*/
- Debug("%s: enter", __FUNCTION__);
-
unsigned long curTime = GetTimeInMillis();
+ Debug("%s: enter dc %p, m_dc %p\n", __FUNCTION__,
+ dc ? dc->gobj() : NULL, m_dc ? m_dc : NULL);
if (curTime - m_destDropTime <= 1000) {
Debug("%s: ignored %ld %ld %ld\n", __FUNCTION__,
curTime, m_destDropTime, curTime - m_destDropTime);
DnDUI::GtkDestDragLeaveCB(const Glib::RefPtr<Gdk::DragContext> &dc,
guint time)
{
- Debug("%s: enter\n", __FUNCTION__);
+ Debug("%s: enter dc %p, m_dc %p\n", __FUNCTION__,
+ dc ? dc->gobj() : NULL, m_dc ? m_dc : NULL);
+
+ /*
+ * If we reach here after reset DnD, or we are getting a late
+ * DnD drag leave signal (we have started another DnD), then
+ * finish the old DnD. Otherwise, Gtk will not reset and a new
+ * DnD will not start until Gtk+ times out (which appears to
+ * be 5 minutes).
+ * See http://bugzilla.eng.vmware.com/show_bug.cgi?id=528320
+ */
+ if (!m_dc || dc->gobj() != m_dc) {
+ Debug("%s: calling drag_finish\n", __FUNCTION__);
+ dc->drag_finish(true, false, time);
+ }
}
selection_data.set(target.c_str(), "");
- Debug("%s: enter with target %s\n", __FUNCTION__, target.c_str());
+ Debug("%s: enter dc %p, m_dc %p with target %s\n", __FUNCTION__,
+ dc ? dc->gobj() : NULL, m_dc ? m_dc : NULL,
+ target.c_str());
if (!m_inHGDrag) {
Debug("%s: not in drag, return\n", __FUNCTION__);
guint info,
guint time)
{
- Debug("%s: enter\n", __FUNCTION__);
+ Debug("%s: enter dc %p, m_dc %p\n", __FUNCTION__,
+ dc ? dc->gobj() : NULL, m_dc ? m_dc : NULL);
/* The GH DnD may already finish before we got response. */
if (!m_GHDnDInProgress) {
Debug("%s: not valid\n", __FUNCTION__);
int y,
guint time)
{
- Debug("%s: enter x %d y %d\n", __FUNCTION__, x, y);
+ Debug("%s: enter dc %p, m_dc %p x %d y %d\n", __FUNCTION__,
+ (dc ? dc->gobj() : NULL), (m_dc ? m_dc : NULL), x, y);
Glib::ustring target;
void SetBlockControl(DnDBlockControl *blockCtrl);
void SetUnityMode(Bool mode)
{m_unityMode = mode;};
+ void Cancel();
DragDetWnd *GetFullDetWnd() {return m_detWnd;}
GtkWidget *GetDetWndAsWidget();
*-----------------------------------------------------------------------------
*/
-void VMwareUserCleanupRpc(void)
+void VMwareUserCleanupRpc(Bool isXError) // IN
{
+ Debug("%s: enter\n", __FUNCTION__);
if (gRpcIn) {
Unity_UnregisterCaps();
GHI_Cleanup();
}
if (!RpcIn_stop(gRpcIn)) {
- Debug("Failed to stop RpcIn loop\n");
+ Debug("%s: failed to stop RpcIn loop\n", __FUNCTION__);
}
if (gOpenUrlRegistered) {
FoundryToolsDaemon_UnregisterOpenUrl();
}
CopyPasteDnDWrapper *p = CopyPasteDnDWrapper::GetInstance();
+
+ /*
+ * We can't call the normal APIs to tear down DnD/CP because they
+ * involve Xlib calls that can't be made after X IO error. So, use
+ * an entry point that performs a subset of the cleanup we normally
+ * do on a reset, to ensure that any file transfers in flight get
+ * failed properly. See bug 458626.
+ */
if (p) {
- p->UnregisterDnD();
- p->UnregisterCP();
+ if (!isXError) {
+ p->UnregisterDnD();
+ p->UnregisterCP();
+ } else {
+ p->Cancel();
+ }
}
+
RpcIn_Destruct(gRpcIn);
gRpcIn = NULL;
}
}
if (gSigExit) {
- VMwareUserCleanupRpc();
+ VMwareUserCleanupRpc(FALSE);
}
#if defined(HAVE_GTKMM)
VMwareUser_OnDestroy(GtkWidget *widget, // IN: Unused
gpointer data) // IN: Unused
{
- VMwareUserCleanupRpc();
+ VMwareUserCleanupRpc(FALSE);
#if defined(HAVE_GTKMM)
Gtk::Main::quit();
#else
* watching the process being run. When it dies, it will come
* through here, so we don't want to let it shut down the Rpc
*/
- Debug("> VMwareUserXIOErrorHandler\n");
+ Debug("> %s\n", __FUNCTION__);
if (my_pid == gParentPid) {
- VMwareUserCleanupRpc();
+ VMwareUserCleanupRpc(TRUE);
ReloadSelf();
exit(EXIT_FAILURE);
} else {
- Debug("VMwareUserXIOErrorHandler hit from forked() child, not cleaning Rpc\n");
+ Debug("%s hit from forked() child, not cleaning Rpc\n", __FUNCTION__);
_exit(EXIT_FAILURE);
}