[client] spice: added clipboard callbacks to decouple spice from SDL

This commit is contained in:
Geoffrey McRae 2019-02-22 18:59:45 +11:00
parent 0dfa7425c1
commit 689a1de69b
3 changed files with 91 additions and 28 deletions

View File

@ -486,6 +486,27 @@ static inline const uint32_t mapScancode(SDL_Scancode scancode)
return ps2; return ps2;
} }
bool spiceClipboardNotice(const SpiceDataType type)
{
// we only support text data for now
return (type == SPICE_DATA_TEXT);
}
void spiceClipboardData(const SpiceDataType type, uint8_t * buffer, uint32_t size)
{
// dos2unix
uint8_t * p = buffer;
for(uint32_t i = 0; i < size; ++i)
{
uint8_t c = buffer[i];
if (c != '\r')
*p++ = c;
}
*p = '\0';
SDL_SetClipboardText((char *)buffer);
}
int eventFilter(void * userdata, SDL_Event * event) int eventFilter(void * userdata, SDL_Event * event)
{ {
static bool serverMode = false; static bool serverMode = false;
@ -951,6 +972,7 @@ int run()
if (params.useSpice) if (params.useSpice)
{ {
spice_set_on_clipboard_cb(spiceClipboardNotice, spiceClipboardData);
if (!spice_connect(params.spiceHost, params.spicePort, "")) if (!spice_connect(params.spiceHost, params.spicePort, ""))
{ {
DEBUG_ERROR("Failed to connect to spice server"); DEBUG_ERROR("Failed to connect to spice server");

View File

@ -39,8 +39,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include <spice/protocol.h> #include <spice/protocol.h>
#include <spice/vd_agent.h> #include <spice/vd_agent.h>
#include <SDL2/SDL.h>
#include "messages.h" #include "messages.h"
#include "rsa.h" #include "rsa.h"
@ -118,9 +116,12 @@ struct Spice
bool cbSupported; bool cbSupported;
bool cbSelection; bool cbSelection;
char *cbBuffer; SpiceDataType cbType;
uint32_t cbRemain; uint8_t * cbBuffer;
uint32_t cbSize; uint32_t cbRemain;
uint32_t cbSize;
SpiceClipboardNotice cbNoticeFn;
SpiceClipboardData cbDataFn;
}; };
// globals // globals
@ -146,7 +147,7 @@ bool spice_on_inputs_channel_read();
bool spice_agent_process (uint32_t dataSize); bool spice_agent_process (uint32_t dataSize);
bool spice_agent_connect (); bool spice_agent_connect ();
bool spice_agent_send_caps(bool request); bool spice_agent_send_caps(bool request);
bool spice_agent_on_clipboard(); void spice_agent_on_clipboard();
// thread safe read/write methods // thread safe read/write methods
bool spice_write_msg (struct SpiceChannel * channel, uint32_t type, const void * buffer, const ssize_t size); bool spice_write_msg (struct SpiceChannel * channel, uint32_t type, const void * buffer, const ssize_t size);
@ -199,6 +200,12 @@ void spice_disconnect()
spice_disconnect_channel(&spice.scInputs); spice_disconnect_channel(&spice.scInputs);
spice.sessionID = 0; spice.sessionID = 0;
if (spice.cbBuffer)
free(spice.cbBuffer);
spice.cbBuffer = NULL;
spice.cbRemain = 0;
spice.cbSize = 0;
} }
// ============================================================================ // ============================================================================
@ -919,7 +926,7 @@ bool spice_agent_process(uint32_t dataSize)
spice.cbSize += r; spice.cbSize += r;
if (spice.cbRemain == 0) if (spice.cbRemain == 0)
return spice_agent_on_clipboard(); spice_agent_on_clipboard();
return true; return true;
} }
@ -1031,7 +1038,7 @@ bool spice_agent_process(uint32_t dataSize)
spice.cbSize = 0; spice.cbSize = 0;
spice.cbRemain = remaining; spice.cbRemain = remaining;
spice.cbBuffer = (char *)malloc(remaining); spice.cbBuffer = (uint8_t *)malloc(remaining);
const uint32_t r = remaining > dataSize ? dataSize : remaining; const uint32_t r = remaining > dataSize ? dataSize : remaining;
if (!spice_read_nl(&spice.scMain, spice.cbBuffer, r)) if (!spice_read_nl(&spice.scMain, spice.cbBuffer, r))
@ -1048,7 +1055,7 @@ bool spice_agent_process(uint32_t dataSize)
spice.cbSize += r; spice.cbSize += r;
if (spice.cbRemain == 0) if (spice.cbRemain == 0)
return spice_agent_on_clipboard(); spice_agent_on_clipboard();
return true; return true;
} }
@ -1074,8 +1081,19 @@ bool spice_agent_process(uint32_t dataSize)
// there is zero documentation on the types field, it might be a bitfield // there is zero documentation on the types field, it might be a bitfield
// but for now we are going to assume it's not. // but for now we are going to assume it's not.
// for now we only support text switch(types[0])
if (types[0] == VD_AGENT_CLIPBOARD_UTF8_TEXT) {
case VD_AGENT_CLIPBOARD_UTF8_TEXT : spice.cbType = SPICE_DATA_TEXT; break;
case VD_AGENT_CLIPBOARD_IMAGE_PNG : spice.cbType = SPICE_DATA_PNG ; break;
case VD_AGENT_CLIPBOARD_IMAGE_BMP : spice.cbType = SPICE_DATA_BMP ; break;
case VD_AGENT_CLIPBOARD_IMAGE_TIFF: spice.cbType = SPICE_DATA_TIFF; break;
case VD_AGENT_CLIPBOARD_IMAGE_JPG : spice.cbType = SPICE_DATA_JPG ; break;
default:
DEBUG_WARN("Unknown clipboard data type: %u", types[0]);
return true;
}
if (spice.cbNoticeFn && spice.cbNoticeFn(spice.cbType))
{ {
if (spice.cbSelection) if (spice.cbSelection)
{ {
@ -1085,7 +1103,7 @@ bool spice_agent_process(uint32_t dataSize)
} }
VDAgentClipboardRequest req; VDAgentClipboardRequest req;
req.type = VD_AGENT_CLIPBOARD_UTF8_TEXT; req.type = types[0];
if (!spice_agent_write_msg(VD_AGENT_CLIPBOARD_REQUEST, &req, sizeof(req))) if (!spice_agent_write_msg(VD_AGENT_CLIPBOARD_REQUEST, &req, sizeof(req)))
{ {
@ -1111,25 +1129,15 @@ bool spice_agent_process(uint32_t dataSize)
// ============================================================================ // ============================================================================
bool spice_agent_on_clipboard() void spice_agent_on_clipboard()
{ {
// dos2unix if (spice.cbDataFn)
char * p = spice.cbBuffer; spice.cbDataFn(spice.cbType, spice.cbBuffer, spice.cbSize);
for(uint32_t i = 0; i < spice.cbSize; ++i)
{
char c = spice.cbBuffer[i];
if (c != '\r')
*p++ = c;
}
*p = '\0';
SDL_SetClipboardText(spice.cbBuffer);
free(spice.cbBuffer); free(spice.cbBuffer);
spice.cbBuffer = NULL; spice.cbBuffer = NULL;
spice.cbSize = 0; spice.cbSize = 0;
spice.cbRemain = 0; spice.cbRemain = 0;
return true;
} }
// ============================================================================ // ============================================================================
@ -1458,4 +1466,22 @@ bool spice_mouse_release(uint32_t button)
msg.button_state = spice.mouse.buttonState; msg.button_state = spice.mouse.buttonState;
return spice_write_msg(&spice.scInputs, SPICE_MSGC_INPUTS_MOUSE_RELEASE, &msg, sizeof(msg)); return spice_write_msg(&spice.scInputs, SPICE_MSGC_INPUTS_MOUSE_RELEASE, &msg, sizeof(msg));
} }
// ============================================================================
bool spice_set_on_clipboard_cb(SpiceClipboardNotice cbNoticeFn, SpiceClipboardData cbDataFn)
{
if ((cbNoticeFn && !cbDataFn) || (cbDataFn && !cbNoticeFn))
{
DEBUG_ERROR("Clipboard callback notice and data callbacks must be specified");
return false;
}
spice.cbNoticeFn = cbNoticeFn;
spice.cbDataFn = cbDataFn;
return true;
}
// ============================================================================

View File

@ -21,10 +21,22 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
typedef enum SpiceDataType
{
SPICE_DATA_TEXT,
SPICE_DATA_PNG,
SPICE_DATA_BMP,
SPICE_DATA_TIFF,
SPICE_DATA_JPG
}
SpiceDataType;
typedef bool (*SpiceClipboardNotice)(const SpiceDataType type);
typedef void (*SpiceClipboardData )(const SpiceDataType type, uint8_t * buffer, uint32_t size);
bool spice_connect(const char * host, const unsigned short port, const char * password); bool spice_connect(const char * host, const unsigned short port, const char * password);
void spice_disconnect(); void spice_disconnect();
bool spice_process(); bool spice_process();
bool spice_agent_process();
bool spice_ready(); bool spice_ready();
bool spice_key_down (uint32_t code); bool spice_key_down (uint32_t code);
@ -33,4 +45,7 @@ bool spice_mouse_mode (bool server);
bool spice_mouse_position(uint32_t x, uint32_t y); bool spice_mouse_position(uint32_t x, uint32_t y);
bool spice_mouse_motion ( int32_t x, int32_t y); bool spice_mouse_motion ( int32_t x, int32_t y);
bool spice_mouse_press (uint32_t button); bool spice_mouse_press (uint32_t button);
bool spice_mouse_release (uint32_t button); bool spice_mouse_release (uint32_t button);
/* events */
bool spice_set_on_clipboard_cb(SpiceClipboardNotice cbNoticeFn, SpiceClipboardData cbDataFn);