From: VMware, Inc <> Date: Thu, 15 Oct 2009 21:12:51 +0000 (-0700) Subject: Handle capabilities in VMwareUser on Vista/Win7. We can't set the guest X-Git-Tag: 2009.10.15-201664~19 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=79601f9f54d79c102aee9f28de0e47cbea17f3c2;p=thirdparty%2Fopen-vm-tools.git Handle capabilities in VMwareUser on Vista/Win7. We can't set the guest resolution without a user session attached to the console in Vista/Win7 because of session 0 isolation. Signed-off-by: Marcelo Vanzin --- diff --git a/open-vm-tools/lib/include/system.h b/open-vm-tools/lib/include/system.h index 8049af0a0..8f11c45ec 100644 --- a/open-vm-tools/lib/include/system.h +++ b/open-vm-tools/lib/include/system.h @@ -49,12 +49,6 @@ char *System_GetEnv(Bool global, const char *valueName); int System_SetEnv(Bool global, const char *valueName, const char *value); #ifdef _WIN32 -typedef void (*DesktopSwitchNotifyCB)(void *); -typedef struct { - DesktopSwitchNotifyCB cb; // callback to invoke. - void *cbdata; // data to pass to callback -} DesktopSwitchThreadArgs; - /* * Representation of monitors gathered by System_GetMonitors. */ @@ -82,11 +76,11 @@ Bool System_IsLoginScreenActive(void); Bool System_IsProcessElevated(void); Bool System_IsScreenSaverActive(void); Bool System_IsScreenSaverRunning(void); -Bool System_StartDesktopSwitchThread(DesktopSwitchThreadArgs *args); -Bool System_KillDesktopSwitchThread(void); +Bool System_IsSecureDesktopActive(void); Bool System_DisableAndKillScreenSaver(void); DWORD System_GetServiceState(LPCWSTR szServiceName); DblLnkLst_Links *System_GetMonitors(); +void System_SetFocusedWindow(HWND windowToFocus, Bool force); #endif diff --git a/open-vm-tools/lib/include/unity.h b/open-vm-tools/lib/include/unity.h index 2bf17c7a2..d81b6f536 100644 --- a/open-vm-tools/lib/include/unity.h +++ b/open-vm-tools/lib/include/unity.h @@ -69,8 +69,8 @@ typedef struct UnityPoint { int32 y; } UnityPoint; -/* - * Represents a virtual desktop configuration. +/* + * Represents a virtual desktop configuration. */ typedef struct UnityVirtualDesktopArray { @@ -78,8 +78,12 @@ typedef struct UnityVirtualDesktopArray { UnityVirtualDesktop desktops[MAX_VIRT_DESK]; // array of desktops } UnityVirtualDesktopArray; +/* Forward reference. */ +typedef struct DesktopSwitchCallbackManager DesktopSwitchCallbackManager; -void Unity_Init(GuestApp_Dict *conf, int* blockedWnd); +void Unity_Init(GuestApp_Dict *conf, + int *blockedWnd, + DesktopSwitchCallbackManager *desktopSwitchCallbackMgr); void Unity_InitBackdoor(struct RpcIn *rpcIn); Bool Unity_IsActive(void); Bool Unity_IsSupported(void); @@ -95,4 +99,3 @@ HWND Unity_GetHwndFromUnityId(UnityWindowId id); #endif #endif - diff --git a/open-vm-tools/lib/unity/unity.c b/open-vm-tools/lib/unity/unity.c index caeff0d01..990f5e05b 100644 --- a/open-vm-tools/lib/unity/unity.c +++ b/open-vm-tools/lib/unity/unity.c @@ -259,8 +259,9 @@ Unity_IsActive(void) */ void -Unity_Init(GuestApp_Dict *conf, // IN - int* blockedWnd) // IN +Unity_Init(GuestApp_Dict *conf, // IN + int *blockedWnd, // IN + DesktopSwitchCallbackManager *desktopSwitchCallbackMgr) // IN { Debug("Unity_Init\n"); @@ -284,7 +285,10 @@ Unity_Init(GuestApp_Dict *conf, // IN /* * Initialize the host-specific portion of the unity service. */ - unity.up = UnityPlatformInit(&unity.tracker, &unity.updateChannel, blockedWnd); + unity.up = UnityPlatformInit(&unity.tracker, + &unity.updateChannel, + blockedWnd, + desktopSwitchCallbackMgr); /* * Init our global dynbuf used to send results back. diff --git a/open-vm-tools/lib/unity/unityPlatform.h b/open-vm-tools/lib/unity/unityPlatform.h index c3748d808..a01c4d456 100644 --- a/open-vm-tools/lib/unity/unityPlatform.h +++ b/open-vm-tools/lib/unity/unityPlatform.h @@ -57,7 +57,8 @@ typedef struct _UnityPlatform UnityPlatform; Bool UnityPlatformIsSupported(void); UnityPlatform *UnityPlatformInit(UnityWindowTracker *tracker, UnityUpdateChannel *updateChannel, - int* blockedWnd); + int *blockedWnd, + DesktopSwitchCallbackManager *desktopSwitchCallbackMgr); void UnityPlatformCleanup(UnityPlatform *up); void UnityPlatformRegisterCaps(UnityPlatform *up); void UnityPlatformUnregisterCaps(UnityPlatform *up); diff --git a/open-vm-tools/lib/unity/unityPlatformX11.c b/open-vm-tools/lib/unity/unityPlatformX11.c index 440e24beb..338f144e3 100644 --- a/open-vm-tools/lib/unity/unityPlatformX11.c +++ b/open-vm-tools/lib/unity/unityPlatformX11.c @@ -137,9 +137,10 @@ UnityPlatformIsSupported(void) */ UnityPlatform * -UnityPlatformInit(UnityWindowTracker *tracker, // IN - UnityUpdateChannel *updateChannel, // IN - int *blockedWnd) // UNUSED +UnityPlatformInit(UnityWindowTracker *tracker, // IN + UnityUpdateChannel *updateChannel, // IN + int *blockedWnd, // IN, not used + DesktopSwitchCallbackManager *desktopSwitchCallbackMgr) // IN, not used { UnityPlatform *up; char *displayName; @@ -1883,9 +1884,6 @@ UnityPlatformSetTopWindowGroup(UnityPlatform *up, // IN: Platform data UnityWindowId *windows, // IN: array of window ids unsigned int windowCount) // IN: # of windows in the array { - UnityPlatformWindow *upw; - Atom data[5] = {0,0,0,0,0}; - XWindowChanges winch; Window sibling = None; int i; @@ -1896,11 +1894,10 @@ UnityPlatformSetTopWindowGroup(UnityPlatform *up, // IN: Platform data /* * Restack everything bottom to top. */ - data[0] = 2; // Magic source indicator to give full control - winch.stack_mode = data[2] = Above; // First window will go at the top of everything for (i = 0; i < windowCount; i++) { - unsigned int valueMask = CWStackMode; + UnityPlatformWindow *upw; Window curWindow; + Atom data[5] = {0,0,0,0,0}; upw = UPWindow_Lookup(up, windows[i]); if (!upw) { @@ -1910,26 +1907,49 @@ UnityPlatformSetTopWindowGroup(UnityPlatform *up, // IN: Platform data curWindow = upw->clientWindow ? upw->clientWindow : upw->toplevelWindow; UPWindow_SetUserTime(up, upw); - winch.sibling = data[1] = sibling; - - if (sibling != None) { - valueMask |= CWSibling; - } - if (UnityPlatformWMProtocolSupported(up, UNITY_X11_WM__NET_RESTACK_WINDOW)) { + data[0] = 2; // Magic source indicator to give full control + data[1] = sibling; + data[2] = Above; + UnityPlatformSendClientMessage(up, up->rootWindows->windows[0], curWindow, up->atoms._NET_RESTACK_WINDOW, 32, 5, data); } else { - XReconfigureWMWindow(up->display, - curWindow, - 0, valueMask, &winch); + XWindowChanges winch = { + .stack_mode = Above, + .sibling = sibling + }; + unsigned int valueMask = CWStackMode; + + if (sibling != None) { + valueMask |= CWSibling; + } + + /* + * As of writing, Metacity doesn't support _NET_RESTACK_WINDOW and + * will block our attempt to raise a window unless it's active, so + * we activate the window first. + */ + if (UnityPlatformWMProtocolSupported(up, UNITY_X11_WM__NET_ACTIVE_WINDOW)) { + data[0] = 2; // Magic source indicator to give full control + data[1] = UnityPlatformGetServerTime(up); + data[2] = None; + UnityPlatformSendClientMessage(up, up->rootWindows->windows[0], + curWindow, + up->atoms._NET_ACTIVE_WINDOW, + 32, 5, data); + } + + XReconfigureWMWindow(up->display, upw->toplevelWindow, 0, valueMask, &winch); } - sibling = curWindow; + sibling = upw->toplevelWindow; } + XSync(up->display, False); + return TRUE; } @@ -2778,7 +2798,7 @@ UnityPlatformSetDesktopConfig(UnityPlatform *up, // * * UnityPlatformSetInitialDesktop -- * - * Set a desktop specified by the desktop id as the initial state. + * Set a desktop specified by the desktop id as the initial state. * * Results: * Returns TRUE if successful, and FALSE otherwise. @@ -2822,6 +2842,12 @@ UnityPlatformSetDesktopActive(UnityPlatform *up, // IN { ASSERT(up); + /* + * Update the uwt with the new active desktop info. + */ + + UnityWindowTracker_ChangeActiveDesktop(up->tracker, desktopId); + if (desktopId >= up->desktopInfo.numDesktops) { return FALSE; } diff --git a/open-vm-tools/lib/unityStub/unityStub.c b/open-vm-tools/lib/unityStub/unityStub.c index 1601bd094..e92ec359d 100644 --- a/open-vm-tools/lib/unityStub/unityStub.c +++ b/open-vm-tools/lib/unityStub/unityStub.c @@ -44,7 +44,8 @@ void Unity_Init(GuestApp_Dict *conf, - int* blockingWndList) + int *blockingWndList, + DesktopSwitchCallbackManager *desktopSwitchCallbackMgr) { } @@ -83,5 +84,3 @@ void Unity_UnregisterCaps(void) { } - - diff --git a/open-vm-tools/services/plugins/resolutionSet/resolutionSet.c b/open-vm-tools/services/plugins/resolutionSet/resolutionSet.c index 03a1e73c8..f78f4b1b1 100644 --- a/open-vm-tools/services/plugins/resolutionSet/resolutionSet.c +++ b/open-vm-tools/services/plugins/resolutionSet/resolutionSet.c @@ -39,10 +39,23 @@ #include "xdrutil.h" #include "vmware/guestrpc/tclodefs.h" +/* + * The maximum number of capabilities we can set. + * + * See ResolutionSetCapabilities(). + */ +#define RESOLUTION_SET_CAPABILITIES_MAX 5 + /* * Internal global variables */ +/** + * The name of the RPC channel we're using, e.g. TOOLS_DAEMON_NAME. Used by + * ResolutionSet_SetServerCapability() to determine which capability to set. + */ +static const char *rpcChannelName = NULL; + /** * Describes current state of the library. */ @@ -54,11 +67,11 @@ ResolutionInfoType resolutionInfo; static Bool ResolutionResolutionSetCB(RpcInData *data); static Bool ResolutionDisplayTopologySetCB(RpcInData *data); +static void ResolutionSetServerCapability(unsigned int value); #if defined(RESOLUTION_WIN32) static Bool ResolutionDisplayTopologyModesSetCB(RpcInData *data); static Bool ResolutionChangeHost3DAvailabilityHintCB(RpcInData *data); -void ResolutionSetSessionChangeCB(gpointer src, ToolsAppCtx *ctx, DWORD code, DWORD sessionID); #endif /* @@ -111,29 +124,6 @@ ResolutionCleanup(void) } -#if defined(RESOLUTION_WIN32) -/** - * - * Handle WTS session state changes sent from Win32 SCM. - * - * @param[in] src unused src object - * @param[in] ctx unused tools app context - * @param[in] code state change code - * @param[in] session ID - */ - -static void -ResolutionSetSessionChangeCB(gpointer src, - ToolsAppCtx *ctx, - DWORD code, - DWORD sessionID) -{ - Debug("%s: enter code %d sessionID %d\n", __FUNCTION__, code, sessionID); - ResolutionSetSessionChange(code, sessionID); -} -#endif - - /** * * Handler for TCLO 'Resolution_Set'. @@ -160,12 +150,6 @@ ResolutionResolutionSetCB(RpcInData *data) return RPCIN_SETRETVALS(data, "Invalid guest state: resolution set not initialized", FALSE); } - if (!resInfo->canSetResolution) { - Debug("%s: FAIL! Request for resolution set but res set is not enabled\n", - __FUNCTION__); - return RPCIN_SETRETVALS(data, "Invalid guest state: resolution set not enabled", FALSE); - } - /* parse the width and height */ if (!StrUtil_GetNextUintToken(&width, &index, data->args, " ")) { goto invalid_arguments; @@ -330,13 +314,6 @@ ResolutionDisplayTopologySetCB(RpcInData *data) goto out; } - if (!resInfo->canSetTopology) { - Debug("%s: FAIL! Request for topology set but topology set not enabled\n", - __FUNCTION__); - RPCIN_SETRETVALS(data, "Invalid guest state: topology set not enabled", FALSE); - goto out; - } - /* * The argument string will look something like: * [ , ] * count. @@ -406,40 +383,26 @@ ResolutionSetShutdown(gpointer src, /** - * Sends the resolution_server capability to the VMX. + * Sends the tools.capability.resolution_server RPC to the VMX. * - * @param[in] src The source object. - * @param[in] ctx The app context. - * @param[in] plugin Plugin registration data. - * @param[in] set Whether setting or unsetting the capability. - * - * @return NULL. The function sends the capability directly. + * @param[in] value The value to send for the capability bit. */ - -static void -ResolutionServerCapReg(ToolsAppCtx *ctx, - gint set) +void +ResolutionSetServerCapability(unsigned int value) { - gchar *msg; - const char *appName = NULL; - - if (strcmp(ctx->name, VMTOOLS_GUEST_SERVICE) == 0) { - appName = TOOLS_DAEMON_NAME; - } else if (strcmp(ctx->name, VMTOOLS_USER_SERVICE) == 0) { - appName = TOOLS_DND_NAME; - } else { - NOT_REACHED(); + if (!rpcChannelName) { + g_debug("Channel name is null, RPC not sent.\n"); + return; } - msg = g_strdup_printf("tools.capability.resolution_server %s %d", - appName, - set); - - if (ctx->rpc && !RpcChannel_Send(ctx->rpc, msg, strlen(msg) + 1, NULL, NULL)) { - g_warning("Setting resolution_server capability failed!\n"); + if (!RpcOut_sendOne(NULL, + NULL, + "tools.capability.resolution_server %s %d", + rpcChannelName, + value)) { + g_warning("%s: Unable to set tools.capability.resolution_server\n", + __FUNCTION__); } - - g_free(msg); } @@ -461,53 +424,92 @@ ResolutionSetCapabilities(gpointer src, gboolean set, gpointer data) { - enum { - RES_SET_IDX = 0, - DPY_TOPO_SET_IDX = 1, - DPY_GLOBAL_OFFSET_IDX = 2, - DPY_TOPO_MODES_SET_IDX = 3, - CHANGE_3D_HINT_IDX = 4 - }; + /* The array of capabilities to return to the tools service. */ + ToolsAppCapability capabilityArray[RESOLUTION_SET_CAPABILITIES_MAX]; - ToolsAppCapability caps[] = { - { TOOLS_CAP_OLD, "resolution_set", 0, 0 }, - { TOOLS_CAP_OLD, "display_topology_set", 0, 0 }, - { TOOLS_CAP_OLD, "display_global_offset", 0, 0 }, - { TOOLS_CAP_NEW, NULL, CAP_SET_TOPO_MODES, 0 }, - { TOOLS_CAP_NEW, NULL, CAP_CHANGE_HOST_3D_AVAILABILITY_HINT, 0}, - }; + /* The next unused entry in the capabilities array. */ + unsigned int capabilityCount = 0; ResolutionInfoType *resInfo = &resolutionInfo; - int resServerCap = 0; -Debug("%s: enter\n", __FUNCTION__); - if (set) { - if (!resInfo->initialized) { - return FALSE; - } + Debug("%s: enter\n", __FUNCTION__); - if (resInfo->canSetResolution) { - caps[RES_SET_IDX].value = 1; - resServerCap = 1; - } + if (!resInfo->initialized) { + return FALSE; + } - if (resInfo->canSetTopology) { + /* + * If we can set the guest resolution, add the resolution_set capability to + * our array. + */ + if (resInfo->canSetResolution) { + capabilityArray[capabilityCount].type = TOOLS_CAP_OLD; + capabilityArray[capabilityCount].name = "resolution_set"; + capabilityArray[capabilityCount].index = 0; + capabilityArray[capabilityCount].value = set ? 1 : 0; + capabilityCount++; + + /* + * Send the resolution_server RPC to the VMX. + * + * XXX: We need to send this ourselves, instead of including it in the + * capability array, because the resolution_server RPC includes the + * name of the RPC channel that the VMX should use when sending + * resolution set RPCs as an argument. + */ + ResolutionSetServerCapability(set ? 1 : 0); + } - caps[DPY_TOPO_SET_IDX].value = 2; - caps[DPY_GLOBAL_OFFSET_IDX].value = 1; -#if defined(RESOLUTION_WIN32) -Debug("%s: setting DPY_TOPO_MODES_SET_IDX to 1\n", __FUNCTION__); - caps[DPY_TOPO_MODES_SET_IDX].value = 1; -#endif - } + /* + * If we can set the guest topology, add the display_topology_set and + * display_global_offset capabilities to our array. + */ + if (resInfo->canSetTopology) { + /* + * XXX: We use a value of '2' here because, for historical reasons, the + * Workstation/Fusion UI will treat a value of 1 for this capability + * as unsupported. See bug 149541. + */ + capabilityArray[capabilityCount].type = TOOLS_CAP_OLD; + capabilityArray[capabilityCount].name = "display_topology_set"; + capabilityArray[capabilityCount].index = 0; + capabilityArray[capabilityCount].value = set ? 2 : 0; + capabilityCount++; + + capabilityArray[capabilityCount].type = TOOLS_CAP_OLD; + capabilityArray[capabilityCount].name = "display_global_offset"; + capabilityArray[capabilityCount].index = 0; + capabilityArray[capabilityCount].value = set ? 1 : 0; + capabilityCount++; } #if defined(RESOLUTION_WIN32) - caps[CHANGE_3D_HINT_IDX].value = 1; + /* + * XXX: I believe we can always handle these RPCs from the service, even on + * Vista, so we always set the capabilities here, regardless of the + * value of resInfo->canSetTopology. + */ + Debug("%s: setting DPY_TOPO_MODES_SET_IDX to %u\n", __FUNCTION__, + set ? 1 : 0); + + capabilityArray[capabilityCount].type = TOOLS_CAP_NEW; + capabilityArray[capabilityCount].name = NULL; + capabilityArray[capabilityCount].index = CAP_SET_TOPO_MODES; + capabilityArray[capabilityCount].value = set ? 1 : 0; + capabilityCount++; + + capabilityArray[capabilityCount].type = TOOLS_CAP_NEW; + capabilityArray[capabilityCount].name = NULL; + capabilityArray[capabilityCount].index = CAP_CHANGE_HOST_3D_AVAILABILITY_HINT; + capabilityArray[capabilityCount].value = set ? 1 : 0; + capabilityCount++; #endif - ResolutionServerCapReg(ctx, resServerCap); - return VMTools_WrapArray(caps, sizeof *caps, ARRAYSIZE(caps)); + ASSERT(capabilityCount <= RESOLUTION_SET_CAPABILITIES_MAX); + + return VMTools_WrapArray(capabilityArray, + sizeof *capabilityArray, + capabilityCount); } @@ -522,6 +524,15 @@ Debug("%s: setting DPY_TOPO_MODES_SET_IDX to 1\n", __FUNCTION__); TOOLS_MODULE_EXPORT ToolsPluginData * ToolsOnLoad(ToolsAppCtx *ctx) { + RpcChannelCallback rpcs[] = { + { "Resolution_Set", &ResolutionResolutionSetCB }, + { "DisplayTopology_Set", &ResolutionDisplayTopologySetCB }, +#if defined(RESOLUTION_WIN32) + { "DisplayTopologyModes_Set", &ResolutionDisplayTopologyModesSetCB }, + { "ChangeHost3DAvailabilityHint", &ResolutionChangeHost3DAvailabilityHintCB } +#endif + }; + InitHandle handle; static ToolsPluginData regData = { @@ -532,11 +543,9 @@ ToolsOnLoad(ToolsAppCtx *ctx) ToolsPluginSignalCb sigs[] = { { TOOLS_CORE_SIG_CAPABILITIES, ResolutionSetCapabilities, ®Data }, -#if defined(RESOLUTION_WIN32) - { TOOLS_CORE_SIG_SESSION_CHANGE, ResolutionSetSessionChangeCB, ®Data }, -#endif { TOOLS_CORE_SIG_SHUTDOWN, ResolutionSetShutdown, ®Data } }; + ToolsAppReg regs[] = { { TOOLS_APP_GUESTRPC, NULL }, { TOOLS_APP_SIGNALS, VMTools_WrapArray(sigs, sizeof *sigs, ARRAYSIZE(sigs)) } @@ -544,6 +553,18 @@ ToolsOnLoad(ToolsAppCtx *ctx) ResolutionInfoType *resInfo = &resolutionInfo; + /* + * Save the RPC channel name from the ToolsAppCtx so that we can use it later + * in calls to ResolutionSetServerCapability(). + */ + if (strcmp(ctx->name, VMTOOLS_GUEST_SERVICE) == 0) { + rpcChannelName = TOOLS_DAEMON_NAME; + } else if (strcmp(ctx->name, VMTOOLS_USER_SERVICE) == 0) { + rpcChannelName = TOOLS_DND_NAME; + } else { + NOT_REACHED(); + } + resInfo->initialized = FALSE; /* @@ -553,39 +574,7 @@ ToolsOnLoad(ToolsAppCtx *ctx) ResolutionInit(handle); - /* - * Add one or both of the callbacks based on capabilities. - */ - if (resInfo->canSetResolution || resInfo->canSetTopology) { - int index = 0; - RpcChannelCallback rpcs[4]; - - memset(rpcs, '\0', sizeof rpcs); - - if (resInfo->canSetResolution) { - rpcs[index].name = "Resolution_Set"; - rpcs[index].callback = ResolutionResolutionSetCB; - index++; - } - - if (resInfo->canSetTopology) { - rpcs[index].name = "DisplayTopology_Set"; - rpcs[index].callback = ResolutionDisplayTopologySetCB; - index++; -#if defined(RESOLUTION_WIN32) - rpcs[index].name = "DisplayTopologyModes_Set"; - rpcs[index].callback = ResolutionDisplayTopologyModesSetCB; - index++; - rpcs[index].name = "ChangeHost3DAvailabilityHint"; - rpcs[index].callback = ResolutionChangeHost3DAvailabilityHintCB; - index++; -#endif - } - - regs[0].data = VMTools_WrapArray(rpcs, sizeof *rpcs, index); - regData.regs = VMTools_WrapArray(regs, sizeof *regs, ARRAYSIZE(regs)); - } - - + regs[0].data = VMTools_WrapArray(rpcs, sizeof *rpcs, ARRAYSIZE(rpcs)); + regData.regs = VMTools_WrapArray(regs, sizeof *regs, ARRAYSIZE(regs)); return ®Data; } diff --git a/open-vm-tools/vmware-user/vmware-user.cpp b/open-vm-tools/vmware-user/vmware-user.cpp index cc774d563..c6a5bd617 100644 --- a/open-vm-tools/vmware-user/vmware-user.cpp +++ b/open-vm-tools/vmware-user/vmware-user.cpp @@ -921,7 +921,7 @@ main(int argc, // IN EventManager_Add(gEventQueue, CONF_POLL_TIME, VMwareUserConfFileLoop, &confDict); - Unity_Init(confDict, NULL); + Unity_Init(confDict, NULL, NULL); GHI_Init(NULL, NULL); Resolution_Init(TOOLS_DND_NAME, gXDisplay);