[Spice-devel] [PATCH vdagent] vdagent: add image copy-paste support
Hans de Goede
hdegoede at redhat.com
Tue Nov 23 23:52:47 PST 2010
Also looks good, ack.
Regards,
Hans
On 11/23/2010 04:56 PM, Arnon Gilboa wrote:
> -currently png& bmp
> -using wspice libs cximage.lib& png.lib
> -jpg& tiff will follow
> ---
> vdagent/vdagent.cpp | 214 ++++++++++++++++++++++++++++++++---------------
> vdagent/vdagent.vcproj | 21 +++--
> 2 files changed, 159 insertions(+), 76 deletions(-)
>
> diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp
> index c210016..1ebf1e4 100644
> --- a/vdagent/vdagent.cpp
> +++ b/vdagent/vdagent.cpp
> @@ -18,25 +18,41 @@
> #include "vdcommon.h"
> #include "desktop_layout.h"
> #include "display_setting.h"
> +#include "ximage.h"
> #include<lmcons.h>
> +#include<set>
>
> #define VD_AGENT_LOG_PATH TEXT("%svdagent.log")
> #define VD_AGENT_WINCLASS_NAME TEXT("VDAGENT")
> #define VD_INPUT_INTERVAL_MS 20
> #define VD_TIMER_ID 1
> #define VD_CLIPBOARD_TIMEOUT_MS 10000
> +#define VD_CLIPBOARD_FORMAT_MAX_TYPES 16
>
> +//FIXME: extract format/type stuff to win_vdagent_common for use by windows\platform.cpp as well
> typedef struct VDClipboardFormat {
> uint32_t format;
> - uint32_t type;
> + uint32_t types[VD_CLIPBOARD_FORMAT_MAX_TYPES];
> } VDClipboardFormat;
>
> VDClipboardFormat clipboard_formats[] = {
> - {CF_UNICODETEXT, VD_AGENT_CLIPBOARD_UTF8_TEXT},
> - {0, 0}};
> + {CF_UNICODETEXT, {VD_AGENT_CLIPBOARD_UTF8_TEXT, 0}},
> + //FIXME: support more image types
> + {CF_DIB, {VD_AGENT_CLIPBOARD_IMAGE_PNG, VD_AGENT_CLIPBOARD_IMAGE_BMP, 0}},
> +};
>
> #define clipboard_formats_count (sizeof(clipboard_formats) / sizeof(clipboard_formats[0]))
>
> +typedef struct ImageType {
> + uint32_t type;
> + DWORD cximage_format;
> +} ImageType;
> +
> +static ImageType image_types[] = {
> + {VD_AGENT_CLIPBOARD_IMAGE_PNG, CXIMAGE_FORMAT_PNG},
> + {VD_AGENT_CLIPBOARD_IMAGE_BMP, CXIMAGE_FORMAT_BMP},
> +};
> +
> class VDAgent {
> public:
> static VDAgent* get();
> @@ -61,13 +77,15 @@ private:
> void on_clipboard_release();
> DWORD get_buttons_change(DWORD last_buttons_state, DWORD new_buttons_state,
> DWORD mask, DWORD down_flag, DWORD up_flag);
> + static HGLOBAL utf8_alloc(LPCSTR data, int size);
> static LRESULT CALLBACK wnd_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
> static VOID CALLBACK read_completion(DWORD err, DWORD bytes, LPOVERLAPPED overlap);
> static VOID CALLBACK write_completion(DWORD err, DWORD bytes, LPOVERLAPPED overlap);
> static DWORD WINAPI event_thread_proc(LPVOID param);
> static void dispatch_message(VDAgentMessage* msg, uint32_t port);
> - static uint32_t get_clipboard_format(uint32_t type);
> - static uint32_t get_clipboard_type(uint32_t format);
> + uint32_t get_clipboard_format(uint32_t type);
> + uint32_t get_clipboard_type(uint32_t format);
> + DWORD get_cximage_format(uint32_t type);
> enum { owner_none, owner_guest, owner_client };
> void set_clipboard_owner(int new_owner);
> uint8_t* write_lock(DWORD bytes = 0);
> @@ -113,6 +131,8 @@ private:
> uint32_t *_client_caps;
> uint32_t _client_caps_size;
>
> + std::set<uint32_t> _grab_types;
> +
> VDLog* _log;
> };
>
> @@ -162,6 +182,7 @@ VDAgent::VDAgent()
> ZeroMemory(&_input, sizeof(INPUT));
> ZeroMemory(&_pipe_state, sizeof(VDPipeState));
> MUTEX_INIT(_write_mutex);
> +
> _singleton = this;
> }
>
> @@ -498,10 +519,7 @@ bool VDAgent::handle_mon_config(VDAgentMonitorsConfig* mon_config, uint32_t port
>
> bool VDAgent::handle_clipboard(VDAgentClipboard* clipboard, uint32_t size)
> {
> - HGLOBAL clip_data;
> - LPVOID clip_buf;
> - int clip_size;
> - int clip_len;
> + HANDLE clip_data;
> UINT format;
> bool ret = false;
>
> @@ -514,40 +532,22 @@ bool VDAgent::handle_clipboard(VDAgentClipboard* clipboard, uint32_t size)
> SetEvent(_clipboard_event);
> return false;
> }
> - // Get the required clipboard size
> switch (clipboard->type) {
> case VD_AGENT_CLIPBOARD_UTF8_TEXT:
> - // Received utf8 string is not null-terminated
> - if (!(clip_len = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)clipboard->data, size, NULL, 0))) {
> - return false;
> - }
> - clip_len++;
> - clip_size = clip_len * sizeof(WCHAR);
> + clip_data = utf8_alloc((LPCSTR)clipboard->data, size);
> + break;
> + case VD_AGENT_CLIPBOARD_IMAGE_PNG:
> + case VD_AGENT_CLIPBOARD_IMAGE_BMP: {
> + DWORD cximage_format = get_cximage_format(clipboard->type);
> + ASSERT(cximage_format);
> + CxImage image(clipboard->data, size, cximage_format);
> + clip_data = image.CopyToHandle();
> break;
> + }
> default:
> vd_printf("Unsupported clipboard type %u", clipboard->type);
> return true;
> }
> - // Allocate and lock clipboard memory
> - if (!(clip_data = GlobalAlloc(GMEM_DDESHARE, clip_size))) {
> - return false;
> - }
> - if (!(clip_buf = GlobalLock(clip_data))) {
> - GlobalFree(clip_data);
> - return false;
> - }
> - // Translate data and set clipboard content
> - switch (clipboard->type) {
> - case VD_AGENT_CLIPBOARD_UTF8_TEXT:
> - ret = !!MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)clipboard->data, size, (LPWSTR)clip_buf,
> - clip_len);
> - ((LPWSTR)clip_buf)[clip_len - 1] = L'\0';
> - break;
> - }
> - GlobalUnlock(clip_data);
> - if (!ret) {
> - return false;
> - }
> format = get_clipboard_format(clipboard->type);
> if (SetClipboardData(format, clip_data)) {
> SetEvent(_clipboard_event);
> @@ -563,6 +563,36 @@ bool VDAgent::handle_clipboard(VDAgentClipboard* clipboard, uint32_t size)
> return ret;
> }
>
> +HGLOBAL VDAgent::utf8_alloc(LPCSTR data, int size)
> +{
> + HGLOBAL handle;
> + LPVOID buf;
> + int len;
> +
> + // Received utf8 string is not null-terminated
> + if (!(len = MultiByteToWideChar(CP_UTF8, 0, data, size, NULL, 0))) {
> + return NULL;
> + }
> + len++;
> + // Allocate and lock clipboard memory
> + if (!(handle = GlobalAlloc(GMEM_DDESHARE, len * sizeof(WCHAR)))) {
> + return NULL;
> + }
> + if (!(buf = GlobalLock(handle))) {
> + GlobalFree(handle);
> + return NULL;
> + }
> + // Translate data and set clipboard content
> + if (!(MultiByteToWideChar(CP_UTF8, 0, data, size, (LPWSTR)buf, len))) {
> + GlobalUnlock(handle);
> + GlobalFree(handle);
> + return NULL;
> + }
> + ((LPWSTR)buf)[len - 1] = L'\0';
> + GlobalUnlock(handle);
> + return handle;
> +}
> +
> void VDAgent::set_display_depth(uint32_t depth)
> {
> size_t display_count;
> @@ -798,16 +828,18 @@ bool VDAgent::write_message(uint32_t type, uint32_t size = 0, void* data = NULL)
>
> void VDAgent::on_clipboard_grab()
> {
> - uint32_t* types = new uint32_t[clipboard_formats_count];
> + uint32_t* types = new uint32_t[clipboard_formats_count * VD_CLIPBOARD_FORMAT_MAX_TYPES];
> int count = 0;
>
> if (!VD_AGENT_HAS_CAPABILITY(_client_caps, _client_caps_size,
> VD_AGENT_CAP_CLIPBOARD_BY_DEMAND)) {
> return;
> - }
> - for (VDClipboardFormat* iter = clipboard_formats; iter->format; iter++) {
> - if (IsClipboardFormatAvailable(iter->format)) {
> - types[count++] = iter->type;
> + }
> + for (int i = 0; i< clipboard_formats_count; i++) {
> + if (IsClipboardFormatAvailable(clipboard_formats[i].format)) {
> + for (uint32_t* ptype = clipboard_formats[i].types; *ptype; ptype++) {
> + types[count++] = *ptype;
> + }
> }
> }
> if (count) {
> @@ -865,14 +897,14 @@ void VDAgent::on_clipboard_release()
>
> bool VDAgent::handle_clipboard_grab(VDAgentClipboardGrab* clipboard_grab, uint32_t size)
> {
> - bool has_supported_type = false;
> - uint32_t format;
> + std::set<uint32_t> grab_formats;
>
> + _grab_types.clear();
> for (uint32_t i = 0; i< size / sizeof(clipboard_grab->types[0]); i++) {
> - format = get_clipboard_format(clipboard_grab->types[i]);
> + vd_printf("grab %u", clipboard_grab->types[i]);
> + uint32_t format = get_clipboard_format(clipboard_grab->types[i]);
> //On first supported type, open and empty the clipboard
> - if (format&& !has_supported_type) {
> - has_supported_type = true;
> + if (format&& grab_formats.empty()) {
> if (!OpenClipboard(_hwnd)) {
> return false;
> }
> @@ -880,10 +912,13 @@ bool VDAgent::handle_clipboard_grab(VDAgentClipboardGrab* clipboard_grab, uint32
> }
> //For all supported type set delayed rendering
> if (format) {
> - SetClipboardData(format, NULL);
> + _grab_types.insert(clipboard_grab->types[i]);
> + if (grab_formats.insert(format).second) {
> + SetClipboardData(format, NULL);
> + }
> }
> }
> - if (!has_supported_type) {
> + if (grab_formats.empty()) {
> vd_printf("No supported clipboard types in client grab");
> return true;
> }
> @@ -898,9 +933,10 @@ bool VDAgent::handle_clipboard_request(VDAgentClipboardRequest* clipboard_reques
> {
> UINT format;
> HANDLE clip_data;
> - LPVOID clip_buf;
> - int clip_size;
> + uint8_t* new_data = NULL;
> + long new_size;
> size_t len;
> + CxImage image;
>
> if (_clipboard_owner != owner_guest) {
> vd_printf("Received clipboard request from client while clipboard is not owned by guest");
> @@ -917,40 +953,60 @@ bool VDAgent::handle_clipboard_request(VDAgentClipboardRequest* clipboard_reques
> if (!IsClipboardFormatAvailable(format) || !OpenClipboard(_hwnd)) {
> return false;
> }
> - if (!(clip_data = GetClipboardData(format)) || !(clip_buf = GlobalLock(clip_data))) {
> + if (!(clip_data = GetClipboardData(format))) {
> CloseClipboard();
> return false;
> }
> switch (clipboard_request->type) {
> case VD_AGENT_CLIPBOARD_UTF8_TEXT:
> - len = wcslen((wchar_t*)clip_buf);
> - clip_size = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)clip_buf, (int)len, NULL, 0, NULL, NULL);
> + if (!(new_data = (uint8_t*)GlobalLock(clip_data))) {
> + break;
> + }
> + len = wcslen((LPCWSTR)new_data);
> + new_size = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)new_data, (int)len, NULL, 0, NULL, NULL);
> + break;
> + case VD_AGENT_CLIPBOARD_IMAGE_PNG:
> + case VD_AGENT_CLIPBOARD_IMAGE_BMP: {
> + DWORD cximage_format = get_cximage_format(clipboard_request->type);
> + ASSERT(cximage_format);
> + if (!image.CreateFromHANDLE(clip_data)) {
> + vd_printf("Image create from handle failed");
> + break;
> + }
> + if (!image.Encode(new_data, new_size, cximage_format)) {
> + vd_printf("Image encode to type %u failed", clipboard_request->type);
> + break;
> + }
> + vd_printf("Image encoded to %u bytes", new_size);
> break;
> }
> -
> - if (!clip_size) {
> - GlobalUnlock(clip_data);
> + }
> + if (!new_size) {
> CloseClipboard();
> return false;
> }
> _out_msg_pos = 0;
> - _out_msg_size = sizeof(VDAgentMessage) + sizeof(VDAgentClipboard) + clip_size;
> + _out_msg_size = sizeof(VDAgentMessage) + sizeof(VDAgentClipboard) + new_size;
> _out_msg = (VDAgentMessage*)new uint8_t[_out_msg_size];
> _out_msg->protocol = VD_AGENT_PROTOCOL;
> _out_msg->type = VD_AGENT_CLIPBOARD;
> _out_msg->opaque = 0;
> - _out_msg->size = (uint32_t)(sizeof(VDAgentClipboard) + clip_size);
> + _out_msg->size = (uint32_t)(sizeof(VDAgentClipboard) + new_size);
> VDAgentClipboard* clipboard = (VDAgentClipboard*)_out_msg->data;
> clipboard->type = clipboard_request->type;
>
> switch (clipboard_request->type) {
> case VD_AGENT_CLIPBOARD_UTF8_TEXT:
> - WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)clip_buf, (int)len, (LPSTR)clipboard->data,
> - clip_size, NULL, NULL);
> + WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)new_data, (int)len, (LPSTR)clipboard->data,
> + new_size, NULL, NULL);
> + GlobalUnlock(clip_data);
> + break;
> + case VD_AGENT_CLIPBOARD_IMAGE_PNG:
> + case VD_AGENT_CLIPBOARD_IMAGE_BMP:
> + memcpy(clipboard->data, new_data, new_size);
> + image.FreeMemory(new_data);
> break;
> }
> -
> - GlobalUnlock(clip_data);
> CloseClipboard();
> write_clipboard();
> return true;
> @@ -968,9 +1024,11 @@ void VDAgent::handle_clipboard_release()
>
> uint32_t VDAgent::get_clipboard_format(uint32_t type)
> {
> - for (VDClipboardFormat* iter = clipboard_formats; iter->format&& iter->type; iter++) {
> - if (iter->type == type) {
> - return iter->format;
> + for (int i = 0; i< clipboard_formats_count; i++) {
> + for (uint32_t* ptype = clipboard_formats[i].types; *ptype; ptype++) {
> + if (*ptype == type) {
> + return clipboard_formats[i].format;
> + }
> }
> }
> return 0;
> @@ -978,9 +1036,29 @@ uint32_t VDAgent::get_clipboard_format(uint32_t type)
>
> uint32_t VDAgent::get_clipboard_type(uint32_t format)
> {
> - for (VDClipboardFormat* iter = clipboard_formats; iter->format&& iter->type; iter++) {
> - if (iter->format == format) {
> - return iter->type;
> + uint32_t* types = NULL;
> +
> + for (int i = 0; i< clipboard_formats_count&& !types; i++) {
> + if (clipboard_formats[i].format == format) {
> + types = clipboard_formats[i].types;
> + }
> + }
> + if (!types) {
> + return 0;
> + }
> + for (uint32_t* ptype = types; *ptype; ptype++) {
> + if (_grab_types.find(*ptype) != _grab_types.end()) {
> + return *ptype;
> + }
> + }
> + return 0;
> +}
> +
> +DWORD VDAgent::get_cximage_format(uint32_t type)
> +{
> + for (int i = 0; i< sizeof(image_types) / sizeof(image_types[0]); i++) {
> + if (image_types[i].type == type) {
> + return image_types[i].cximage_format;
> }
> }
> return 0;
> diff --git a/vdagent/vdagent.vcproj b/vdagent/vdagent.vcproj
> index 0453c12..ee60f42 100644
> --- a/vdagent/vdagent.vcproj
> +++ b/vdagent/vdagent.vcproj
> @@ -44,7 +44,7 @@
> <Tool
> Name="VCCLCompilerTool"
> Optimization="0"
> - AdditionalIncludeDirectories="..\common;$(SPICE_COMMON_DIR)"
> + AdditionalIncludeDirectories="..\common;"$(SPICE_COMMON_DIR)";"$(SPICE_LIBS)\include\CxImage""
> PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS,_WIN32_WINNT=0x0501"
> MinimalRebuild="true"
> BasicRuntimeChecks="3"
> @@ -65,8 +65,9 @@
> />
> <Tool
> Name="VCLinkerTool"
> - AdditionalDependencies="Version.lib"
> + AdditionalDependencies="Version.lib zlibwapiD.lib png_d.lib cximage_d.lib"
> LinkIncremental="2"
> + AdditionalLibraryDirectories=""$(SPICE_LIBS)\lib""
> GenerateDebugInformation="true"
> SubSystem="2"
> RandomizedBaseAddress="1"
> @@ -121,7 +122,7 @@
> <Tool
> Name="VCCLCompilerTool"
> Optimization="0"
> - AdditionalIncludeDirectories="..\common;$(SPICE_COMMON_DIR)"
> + AdditionalIncludeDirectories="..\common;"$(SPICE_COMMON_DIR)";"$(SPICE_LIBS)\include\CxImage""
> PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS,_WIN32_WINNT=0x0501"
> MinimalRebuild="true"
> BasicRuntimeChecks="3"
> @@ -142,8 +143,10 @@
> />
> <Tool
> Name="VCLinkerTool"
> - AdditionalDependencies="Version.lib"
> + AdditionalDependencies="Version.lib zlibwapiD.lib png_d.lib cximage_d.lib"
> LinkIncremental="2"
> + AdditionalLibraryDirectories=""$(SPICE_LIBS)\lib64""
> + IgnoreDefaultLibraryNames=""
> GenerateDebugInformation="true"
> SubSystem="2"
> RandomizedBaseAddress="1"
> @@ -197,7 +200,7 @@
> />
> <Tool
> Name="VCCLCompilerTool"
> - AdditionalIncludeDirectories="..\common;$(SPICE_COMMON_DIR)"
> + AdditionalIncludeDirectories="..\common;"$(SPICE_COMMON_DIR)";"$(SPICE_LIBS)\include\CxImage""
> AdditionalUsingDirectories=""
> PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS,_WIN32_WINNT=0x0501"
> RuntimeLibrary="0"
> @@ -217,8 +220,9 @@
> />
> <Tool
> Name="VCLinkerTool"
> - AdditionalDependencies="Version.lib"
> + AdditionalDependencies="Version.lib zlibwapi.lib png.lib cximage.lib"
> LinkIncremental="1"
> + AdditionalLibraryDirectories=""$(SPICE_LIBS)\lib""
> GenerateDebugInformation="true"
> SubSystem="2"
> OptimizeReferences="2"
> @@ -275,7 +279,7 @@
> />
> <Tool
> Name="VCCLCompilerTool"
> - AdditionalIncludeDirectories="..\common;$(SPICE_COMMON_DIR)"
> + AdditionalIncludeDirectories="..\common;"$(SPICE_COMMON_DIR)";"$(SPICE_LIBS)\include\CxImage""
> AdditionalUsingDirectories=""
> PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS,_WIN32_WINNT=0x0501"
> RuntimeLibrary="0"
> @@ -295,8 +299,9 @@
> />
> <Tool
> Name="VCLinkerTool"
> - AdditionalDependencies="Version.lib"
> + AdditionalDependencies="Version.lib zlibwapi.lib png.lib cximage.lib"
> LinkIncremental="1"
> + AdditionalLibraryDirectories=""$(SPICE_LIBS)\lib64""
> GenerateDebugInformation="true"
> SubSystem="2"
> OptimizeReferences="2"
More information about the Spice-devel
mailing list