. Change GHI_GetBinaryInfo to return a string and vector of icons.
. Unity: Relocate and rename 'updateChannel'.
Signed-off-by: Marcelo Vanzin <mvanzin@vmware.com>
*
* GHI_GetBinaryInfo --
*
- * Get binary information. The returned DynBuf contains a formatted string
- * <name>\0<icon count>\0<width>\0<height>\0<size>\0<bgraData>\0...
- * consisting of the 'friendly name' (ie 'Microsoft Word') and the icons
- * in various sizes for the application.
+ * Get binary information. Returns the 'friendly name' of the application, and
+ * a list of various sized icons (depending on the icons provided by the app).
*
* Results:
* TRUE if everything is successful.
*/
Bool
-GHI_GetBinaryInfo(const char *pathUriUtf8, // IN: full path to the binary file
- DynBuf *buf) // OUT: binary information
+GHI_GetBinaryInfo(const char *pathUriUtf8, // IN: full path to the binary file
+ std::string &friendlyName, // OUT: friendly (long) name
+ std::list<GHIBinaryIconInfo> &iconList) // OUT: List of app icons
{
- return GHIPlatformGetBinaryInfo(ghiPlatformData, pathUriUtf8, buf);
+ return GHIPlatformGetBinaryInfo(ghiPlatformData, pathUriUtf8, friendlyName, iconList);
}
#ifndef _GH_INTEGRATION_H_
#define _GH_INTEGRATION_H_
-#if defined(__cplusplus) && !defined(OPEN_VM_TOOLS) && !defined(__FreeBSD__) && !defined(sun) && !defined(__APPLE__)
+#if defined(__cplusplus)
+#if !defined(OPEN_VM_TOOLS) && !defined(__FreeBSD__) && !defined(sun) && !defined(__APPLE__)
#include "appUtilFileTypes.h"
-#endif // __cplusplus && !OPEN_VM_TOOLS && !__FREEBSD__ && !sun && !__APPLE__
+#endif // !OPEN_VM_TOOLS && !__FREEBSD__ && !sun && !__APPLE__
+#include <vector>
+#include <string>
+#include <list>
+#endif // __cplusplus
#ifdef __cplusplus
extern "C" {
void GHI_Init(GMainLoop *mainLoop, const char **envp, GHIHostCallbacks hostCallbacks);
void GHI_Cleanup(void);
-Bool GHI_GetBinaryInfo(const char *pathUriUtf8, DynBuf *buf);
-
Bool GHI_OpenStartMenuTree(const char *rootUtf8, uint32 flags, DynBuf *buf);
Bool GHI_GetStartMenuItem(uint32 handle, uint32 itemIndex, DynBuf *buf);
Bool GHI_CloseStartMenuTree(uint32 handle);
const FileTypeList& GHI_GetBinaryHandlers(const char *pathUtf8);
#endif // !OPEN_VM_TOOLS && !__FreeBSD__ && !sun && !__APPLE__
+typedef struct GHIBinaryIconInfo {
+ uint32 width;
+ uint32 height;
+ std::vector<uint8> dataBGRA;
+} GHIBinaryIconInfo;
+
+Bool GHI_GetBinaryInfo(const char *pathUriUtf8, std::string &friendlyName, std::list<GHIBinaryIconInfo> &iconList);
#endif // __cplusplus
#endif // _GH_INTEGRATION_H_
Bool GHIPlatformIsSupported(void);
GHIPlatform *GHIPlatformInit(GMainLoop *mainLoop, const char **envp, GHIHostCallbacks hostcallbacks);
void GHIPlatformCleanup(GHIPlatform *ghip);
-Bool GHIPlatformGetBinaryInfo(GHIPlatform *ghip,
- const char *pathURIUtf8,
- DynBuf *buf);
Bool GHIPlatformOpenStartMenuTree(GHIPlatform *ghip,
const char *rootUtf8,
uint32 flags,
const FileTypeList& GHIPlatformGetBinaryHandlers(GHIPlatform *ghip, const char *pathUtf8);
#endif // !OPEN_VM_TOOLS && !__FreeBSD__ && !sun && !__APPLE__
+Bool GHIPlatformGetBinaryInfo(GHIPlatform *ghip, const char *pathUriUtf8, std::string &friendlyName, std::list<GHIBinaryIconInfo> &iconList);
+
#endif // __cplusplus
#endif // _GH_INTEGRATION_INT_H_
* GHIPlatformCollectIconInfo --
*
* Sucks all the icon information for a particular application from the system, and
- * appends it into the DynBuf for returning to the host.
+ * appends it into the icon list for returning to the host.
*
* Results:
* None.
*/
static void
-GHIPlatformCollectIconInfo(GHIPlatform *ghip, // IN
- GHIMenuItem *ghm, // IN
- unsigned long windowID, // IN
- DynBuf *buf) // IN/OUT
+GHIPlatformCollectIconInfo(GHIPlatform *ghip, // IN
+ GHIMenuItem *ghm, // IN
+ unsigned long windowID, // IN
+ std::list<GHIBinaryIconInfo> &iconList) // OUT: Icons
{
GPtrArray *pixbufs;
- char tbuf[1024];
- gsize totalIconBytes;
char *ctmp = NULL;
unsigned int i;
pixbufs = AppUtil_CollectIconArray(ctmp, windowID);
/*
- * Now see if all of these icons can fit into our reply.
+ * Now that we actually have all available icons loaded and checked, dump their
+ * contents into the list.
*/
- totalIconBytes = DynBuf_GetSize(buf);
- for (i = 0; i < pixbufs->len; i++) {
- gsize thisIconBytes;
- GdkPixbuf *pixbuf = (GdkPixbuf *) g_ptr_array_index(pixbufs, i);
-
- thisIconBytes = ICON_SPACE_PADDING; // Space used by the width/height/size strings, and breathing room
- thisIconBytes += gdk_pixbuf_get_width(pixbuf)
- * gdk_pixbuf_get_height(pixbuf)
- * 4 /* image will be BGRA */;
- if ((thisIconBytes + totalIconBytes) < GUESTMSG_MAX_IN_SIZE) {
- totalIconBytes += thisIconBytes;
- } else if (pixbufs->len == 1) {
- GdkPixbuf *newIcon;
- volatile double newWidth;
- volatile double newHeight;
- volatile double scaleFactor;
-
- newWidth = gdk_pixbuf_get_width(pixbuf);
- newHeight = gdk_pixbuf_get_height(pixbuf);
- scaleFactor = (GUESTMSG_MAX_IN_SIZE - totalIconBytes - ICON_SPACE_PADDING);
- scaleFactor /= (newWidth * newHeight * 4.0);
- if (scaleFactor > 0.95) {
- /*
- * Ensures that we remove at least a little bit of data from the icon.
- * Otherwise we can get things like scalefactors of '0.999385' which result
- * in an image of exactly the same size. A scaleFactor of 0.95 will remove at
- * least one row or column from any icon large enough to go past the limit.
- */
- scaleFactor = 0.95;
- }
-
- newWidth *= scaleFactor;
- newHeight *= scaleFactor;
-
- /*
- * If this is the only icon available, try scaling it down to the largest icon
- * that will comfortably fit in the reply.
- *
- * Adding 0.5 to newWidth & newHeight is an easy way of rounding to the closest
- * integer.
- */
- newIcon = gdk_pixbuf_scale_simple(pixbuf,
- (int)(newWidth + 0.5),
- (int)(newHeight + 0.5),
- GDK_INTERP_HYPER);
- g_object_unref(G_OBJECT(pixbuf));
- g_ptr_array_index(pixbufs, i) = newIcon;
- i--; // Try including the newly scaled-down icon
- } else {
- g_object_unref(G_OBJECT(pixbuf));
- g_ptr_array_remove_index_fast(pixbufs, i);
- i--;
- }
- }
-
- /*
- * Now that we actually have all available icons loaded and checked, dump their count
- * and contents into the reply.
- */
- Str_Sprintf(tbuf, sizeof tbuf, "%u", pixbufs->len);
- DynBuf_AppendString(buf, tbuf);
for (i = 0; i < pixbufs->len; i++) {
- int width;
- int height;
GdkPixbuf *pixbuf;
guchar *pixels;
int x, y;
+ int width, height;
int rowstride;
int n_channels;
+ GHIBinaryIconInfo iconInfo = { 0 };
+ unsigned char* bgra = NULL;
pixbuf = (GdkPixbuf *) g_ptr_array_index(pixbufs, i);
width = gdk_pixbuf_get_width(pixbuf);
height = gdk_pixbuf_get_height(pixbuf);
- Str_Sprintf(tbuf, sizeof tbuf, "%d", width);
- DynBuf_AppendString(buf, tbuf);
- Str_Sprintf(tbuf, sizeof tbuf, "%d", height);
- DynBuf_AppendString(buf, tbuf);
- Str_Sprintf(tbuf, sizeof tbuf, "%d", width * height * 4);
- DynBuf_AppendString(buf, tbuf);
+ iconInfo.width = width;
+ iconInfo.height = height;
ASSERT (gdk_pixbuf_get_colorspace (pixbuf) == GDK_COLORSPACE_RGB);
ASSERT (gdk_pixbuf_get_bits_per_sample (pixbuf) == 8);
rowstride = gdk_pixbuf_get_rowstride(pixbuf);
n_channels = gdk_pixbuf_get_n_channels(pixbuf);
pixels = gdk_pixbuf_get_pixels(pixbuf);
+
+ // Resize the destination BGRA vector to hold the pixel data.
+ iconInfo.dataBGRA.resize(iconInfo.width * iconInfo.height * 4);
+ bgra = &iconInfo.dataBGRA[0];
for (y = height - 1; y >= 0; y--) { // GetBinaryInfo icons are bottom-to-top. :(
for (x = 0; x < width; x++) {
- char bgra[4];
guchar *p; // Pointer to RGBA data in GdkPixbuf
p = pixels + (y * rowstride) + (x * n_channels);
} else {
bgra[3] = 0xFF;
}
- DynBuf_Append(buf, bgra, 4);
+ // Step on to the next pixel/group of bytes
+ bgra += 4;
}
}
-
- DynBuf_AppendString(buf, "");
-
+ iconList.push_back(iconInfo);
}
AppUtil_FreeIconArray(pixbufs);
Bool
GHIPlatformGetBinaryInfo(GHIPlatform *ghip, // IN: platform-specific state
const char *pathURIUtf8, // IN: full path to the binary file
- DynBuf *buf) // OUT: binary information
+ std::string &friendlyName, // OUT: Friendly name
+ std::list<GHIBinaryIconInfo> &iconList) // OUT: Icons
{
#ifdef GTK2
const char *realCmd = NULL;
ASSERT(ghip);
ASSERT(pathURIUtf8);
- ASSERT(buf);
memset(&state, 0, sizeof state);
memset(&uri, 0, sizeof uri);
}
}
/*
- * Stick the app name into 'buf'.
+ * Stick the app name into 'friendlyName'.
*/
if (ghm) {
ctmp = g_key_file_get_locale_string(ghm->keyfile, G_KEY_FILE_DESKTOP_GROUP,
if (!ctmp) {
ctmp = g_path_get_basename(realCmd);
}
- DynBuf_AppendString(buf, ctmp);
+ friendlyName = ctmp;
free(ctmp);
} else {
/*
} else {
ctmp = (char *) realCmd;
}
- DynBuf_AppendString(buf, ctmp);
+ friendlyName = ctmp;
}
free(freeMe);
ctmp = NULL;
freeMe = NULL;
- GHIPlatformCollectIconInfo(ghip, ghm, windowID, buf);
+ GHIPlatformCollectIconInfo(ghip, ghm, windowID, iconList);
return TRUE;
#else // !GTK2
static DynBuf gTcloUpdate;
+/*
+ * Overhead of encoding the icon data in a dynbuf - used to make sure we don't
+ * exceed GUEST_MSG_MAX_IN_SIZE when serializing the icons for an app.
+ */
+static const int GHI_ICON_OVERHEAD = 1024;
+
/*
*----------------------------------------------------------------------------
{
char *binaryPathUtf8;
DynBuf *buf = &gTcloUpdate;
+ DynBuf iconDataBuf;
unsigned int index = 0;
Bool ret = TRUE;
+ std::string friendlyName;
+ std::list<GHIBinaryIconInfo> iconList;
+ char temp[128]; // Used to hold sizes and indices as strings
+ uint32 serializedIconCount = 0;
/* Check our arguments. */
ASSERT(data);
}
DynBuf_SetSize(buf, 0);
- if (!GHI_GetBinaryInfo(binaryPathUtf8, buf)) {
+
+ if (!GHI_GetBinaryInfo(binaryPathUtf8, friendlyName, iconList)) {
Debug("%s: Could not get binary info.\n", __FUNCTION__);
ret = RPCIN_SETRETVALS(data,
"Could not get binary info",
goto exit;
}
+ /*
+ * Append the name to the output buffer now. If we fail to get the
+ * icons, we still want to return the app name. Then the UI can display
+ * the default icon and correct app name.
+ *
+ * The output buffer should look like this:
+ * <name>\0<icon count>\0<width>\0<height>\0<size>\0<bgraData>\0...
+ *
+ * Note that the icon data is in BGRA format. An alpha channel value of 255 means
+ * "fully opaque", and an alpha channel value of 0 means "fully transparent".
+ */
+
+ DynBuf_AppendString(buf, friendlyName.c_str());
+
+ if (iconList.size() <= 0) {
+ Debug("%s: Could not find any icons for path: %s", __FUNCTION__, binaryPathUtf8);
+ }
+
+ DynBuf_Init(&iconDataBuf);
+ /* Copy icon info to the output buffer. */
+ for (std::list<GHIBinaryIconInfo>::const_iterator it = iconList.begin();
+ it != iconList.end();
+ it++) {
+ /*
+ * XXX: The backdoor has a maximum RPC data size of 64K - don't attempt to send
+ * icons larger than this size.
+ */
+ if ((DynBuf_GetSize(&iconDataBuf) + it->dataBGRA.size()) <
+ GUESTMSG_MAX_IN_SIZE - GHI_ICON_OVERHEAD) {
+ Str_Sprintf(temp, sizeof temp, "%u", it->width);
+ DynBuf_AppendString(&iconDataBuf, temp);
+
+ Str_Sprintf(temp, sizeof temp, "%u", it->height);
+ DynBuf_AppendString(&iconDataBuf, temp);
+
+ Str_Sprintf(temp, sizeof temp, "%u", (int32) it->dataBGRA.size());
+ DynBuf_AppendString(&iconDataBuf, temp);
+
+ DynBuf_Append(&iconDataBuf, &(it->dataBGRA[0]),
+ it->dataBGRA.size());
+ DynBuf_AppendString(&iconDataBuf, "");
+
+ serializedIconCount++;
+ }
+ }
+
+ Str_Sprintf(temp, sizeof temp, "%d", serializedIconCount);
+ DynBuf_AppendString(buf, temp);
+
+ /* Append the icon data */
+ DynBuf_Append(buf, DynBuf_Get(&iconDataBuf), DynBuf_GetSize(&iconDataBuf));
+ DynBuf_Destroy(&iconDataBuf);
+
/*
* Write the final result into the result out parameters and return!
*/
Warning("%s: Unable to initialize Unity update channel.\n", __FUNCTION__);
return;
}
+ unityHostCallbacks.updateCbCtx = mUnityUpdateChannel;
- Unity_Init(NULL, mUnityUpdateChannel, unityHostCallbacks, ctx->serviceObj);
+ Unity_Init(NULL, unityHostCallbacks, ctx->serviceObj);
GHITcloInit();
GHIHostCallbacks ghiHostCallbacks;
void
Unity_Init(GuestApp_Dict *conf, // IN
- void *updateChannel, // IN
UnityHostCallbacks hostCallbacks, // IN
gpointer serviceObj) // IN
{
Debug("Unity_Init\n");
- ASSERT(updateChannel);
ASSERT(hostCallbacks.updateCB);
ASSERT(hostCallbacks.buildUpdateCB);
ASSERT(hostCallbacks.sendWindowContents);
ASSERT(hostCallbacks.shouldShowTaskbar);
unity.hostCallbacks = hostCallbacks;
- unity.updateChannel = updateChannel;
/*
* Initialize the UnityWindowTracker object. The uwt does all the actual work
* Initialize the platform-specific portion of the unity service.
*/
unity.up = UnityPlatformInit(&unity.tracker,
- unity.updateChannel,
unity.hostCallbacks);
unity.virtDesktopArray.desktopCount = 0;
break;
}
- unity.hostCallbacks.updateCB(unity.updateChannel, update);
+ unity.hostCallbacks.updateCB(unity.hostCallbacks.updateCbCtx, update);
}
UnitySendWindowContentsFn sendWindowContents;
UnitySendRequestMinimizeOperationFn sendRequestMinimizeOperation;
UnityShouldShowTaskbarFn shouldShowTaskbar;
+
+ // Context/Cookie passed to buildUpdateCB and updateCB
+ void *updateCbCtx;
} UnityHostCallbacks;
#ifdef __cplusplus
#endif // __cplusplus
void Unity_Init(GuestApp_Dict *conf,
- void *updateChannel,
UnityHostCallbacks hostCallbacks,
gpointer serviceObj);
Bool Unity_IsActive(void);
Bool isEnabled;
uint32 currentOptions; // Last feature mask received via 'set.options'
UnityVirtualDesktopArray virtDesktopArray; // Virtual desktop configuration
- void *updateChannel; // Unity update transmission channel.
UnityHostCallbacks hostCallbacks; // Callbacks to the host for unity updates
UnityPlatform *up; // Platform-specific state
gpointer serviceObj; // 'Plugin' Host service object - used for signaling Unity state
Bool UnityPlatformIsSupported(void);
UnityPlatform *UnityPlatformInit(UnityWindowTracker *tracker,
- void *updateChannel,
UnityHostCallbacks hostCallbacks);
void UnityPlatformCleanup(UnityPlatform *up);
Bool UnityPlatformUpdateWindowState(UnityPlatform *up,
UnityPlatform *
UnityPlatformInit(UnityWindowTracker *tracker, // IN
- void *updateChannel, // IN
UnityHostCallbacks hostCallbacks) // IN:
{
UnityPlatform *up;
char *displayName;
ASSERT(tracker);
- ASSERT(updateChannel);
Debug("UnityPlatformInit: Running\n");
up = Util_SafeCalloc(1, sizeof *up);
up->tracker = tracker;
- up->updateChannel = updateChannel;
up->hostCallbacks = hostCallbacks;
up->savedScreenSaverTimeout = -1;
int flags = 0;
ASSERT(up);
- ASSERT(up->updateChannel);
if (incremental) {
flags |= UNITY_UPDATE_INCREMENTAL;
UnityPlatformUpdateWindowState(up, up->tracker);
}
- up->hostCallbacks.buildUpdateCB(up->updateChannel, flags);
+ up->hostCallbacks.buildUpdateCB(up->hostCallbacks.updateCbCtx, flags);
}
UnityWindowTracker *tracker;
UnityHostCallbacks hostCallbacks;
- void *updateChannel;
/*
* This tracks all toplevel windows, whether or not they are showing through to the