From f424be980ad7e8f568a9a6caf2528e412ac19466 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Thu, 17 Oct 2013 08:44:52 +0200 Subject: [PATCH] move spice input/vdagent related code to input.c --- Makefile | 2 +- input.c | 645 +++++++++++++++++++++++++++++++++++++++++++++++++ spiceterm.c | 673 +++------------------------------------------------- spiceterm.h | 22 ++ 4 files changed, 699 insertions(+), 643 deletions(-) create mode 100644 input.c diff --git a/Makefile b/Makefile index a037d34..9d610d0 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ PROGRAMS=spiceterm HEADERS=translations.h event_loop.h glyphs.h spiceterm.h -SOURCES=screen.c event_loop.c spiceterm.c +SOURCES=screen.c event_loop.c input.c spiceterm.c #export G_MESSAGES_DEBUG=all #export SPICE_DEBUG=1 diff --git a/input.c b/input.c new file mode 100644 index 0000000..6c51279 --- /dev/null +++ b/input.c @@ -0,0 +1,645 @@ +/* + + Copyright (C) 2013 Proxmox Server Solutions GmbH + + Copyright: spiceterm is under GNU GPL, the GNU General Public License. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 dated June, 1991. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + + Author: Dietmar Maurer +*/ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +#include "spiceterm.h" + +#include +#include +#include +#include +#include + +#include "event_loop.h" + +static int debug = 0; + +#define DPRINTF(x, format, ...) { \ + if (x <= debug) { \ + printf("%s: " format "\n" , __FUNCTION__, ## __VA_ARGS__); \ + } \ +} + +static uint8_t +my_kbd_get_leds(SpiceKbdInstance *sin) +{ + return 0; +} + +#define KBD_MOD_CONTROL_L_FLAG (1<<0) +#define KBD_MOD_CONTROL_R_FLAG (1<<1) +#define KBD_MOD_SHIFT_L_FLAG (1<<2) +#define KBD_MOD_SHIFT_R_FLAG (1<<3) + +static int kbd_flags = 0; + +static void +my_kbd_push_key(SpiceKbdInstance *sin, uint8_t frag) +{ + spiceTerm *vt = SPICE_CONTAINEROF(sin, spiceTerm, keyboard_sin); + + char *esc = NULL; // used to send special keys + + static int e0_mode = 0; + + DPRINTF(1, "enter frag=%02x flags=%08x", frag, kbd_flags); + + if (e0_mode) { + e0_mode = 0; + switch (frag) { + case 0x1d: // press Control_R + kbd_flags |= KBD_MOD_CONTROL_R_FLAG; + break; + case 0x9d: // release Control_R + kbd_flags &= ~KBD_MOD_CONTROL_R_FLAG; + break; + case 0x47: // press Home + esc = "OH"; + break; + case 0x4f: // press END + esc = "OF"; + break; + case 0x48: // press UP + esc = "OA"; + break; + case 0x50: // press DOWN + esc = "OB"; + break; + case 0x4b: // press LEFT + esc = "OD"; + break; + case 0x4d: // press RIGHT + esc = "OC"; + break; + case 0x52: // press INSERT + esc = "[2~"; + break; + case 0x49: // press PAGE_UP + if (kbd_flags & (KBD_MOD_SHIFT_L_FLAG|KBD_MOD_SHIFT_R_FLAG)) { + spiceterm_virtual_scroll(vt, -vt->height/2); + } + break; + case 0x51: // press PAGE_DOWN + if (kbd_flags & (KBD_MOD_SHIFT_L_FLAG|KBD_MOD_SHIFT_R_FLAG)) { + spiceterm_virtual_scroll(vt, vt->height/2); + } + break; + } + } else { + switch (frag) { + case 0xe0: + e0_mode = 1; + break; + case 0x1d: // press Control_L + kbd_flags |= KBD_MOD_CONTROL_L_FLAG; + break; + case 0x9d: // release Control_L + kbd_flags &= ~KBD_MOD_CONTROL_L_FLAG; + break; + case 0x2a: // press Shift_L + kbd_flags |= KBD_MOD_SHIFT_L_FLAG; + break; + case 0xaa: // release Shift_L + kbd_flags &= ~KBD_MOD_SHIFT_L_FLAG; + break; + case 0x36: // press Shift_R + kbd_flags |= KBD_MOD_SHIFT_R_FLAG; + break; + case 0xb6: // release Shift_R + kbd_flags &= ~KBD_MOD_SHIFT_R_FLAG; + break; + case 0x52: // press KP_INSERT + esc = "[2~"; + break; + case 0x53: // press KP_Delete + esc = "[3~"; + break; + case 0x47: // press KP_Home + esc = "OH"; + break; + case 0x4f: // press KP_END + esc = "OF"; + break; + case 0x48: // press KP_UP + esc = "OA"; + break; + case 0x50: // press KP_DOWN + esc = "OB"; + break; + case 0x4b: // press KP_LEFT + esc = "OD"; + break; + case 0x4d: // press KP_RIGHT + esc = "OC"; + break; + case 0x3b: // press F1 + esc = "OP"; + break; + case 0x3c: // press F2 + esc = "OQ"; + break; + case 0x3d: // press F3 + esc = "OR"; + break; + case 0x3e: // press F4 + esc = "OS"; + break; + case 0x3f: // press F5 + esc = "[15~"; + break; + case 0x40: // press F6 + esc = "[17~"; + break; + case 0x41: // press F7 + esc = "[18~"; + break; + case 0x42: // press F8 + esc = "[19~"; + break; + case 0x43: // press F9 + esc = "[20~"; + break; + case 0x44: // press F10 + esc = "[21~"; + break; + case 0x57: // press F11 + esc = "[23~"; + break; + case 0x58: // press F12 + esc = "[24~"; + break; + } + } + + if (esc) { + DPRINTF(1, "escape=%s", esc); + spiceterm_respond_esc(vt, esc); + + if (vt->y_displ != vt->y_base) { + vt->y_displ = vt->y_base; + spiceterm_refresh(vt); + } + + spiceterm_update_watch_mask(vt, TRUE); + } + + DPRINTF(1, "leave frag=%02x flags=%08x", frag, kbd_flags); + return; +} + +static void +my_kbd_push_utf8(SpiceKbdInstance *sin, uint32_t size, uint8_t *data) +{ + spiceTerm *vt = SPICE_CONTAINEROF(sin, spiceTerm, keyboard_sin); + + DPRINTF(1, " size=%d data[0]=%02x", size, data[0]); + + if (kbd_flags & (KBD_MOD_CONTROL_L_FLAG|KBD_MOD_CONTROL_R_FLAG)) { + if (size != 1) return; + if (data[0] >= 'a' && data[0] <= 'z') { + uint8_t buf[1] = { data[0] - 'a' + 1 }; + spiceterm_respond_data(vt, 1, buf); + + } else if (data[0] >= 'A' && data[0] <= 'Z') { + uint8_t buf[1] = { data[0] - 'A' + 1 }; + spiceterm_respond_data(vt, 1, buf); + } + } else { + if (size == 1 && data[0] == 0x7f) { + /* use an escape sequence for DELETE, else it behaves like BACKSPACE */ + spiceterm_respond_esc(vt, "[3~"); + } else { + spiceterm_respond_data(vt, size, data); + } + } + + if (vt->y_displ != vt->y_base) { + vt->y_displ = vt->y_base; + spiceterm_refresh(vt); + } + + spiceterm_update_watch_mask(vt, TRUE); + + return; +} + +static SpiceKbdInterface my_keyboard_sif = { + .base.type = SPICE_INTERFACE_KEYBOARD, + .base.description = "spiceterm keyboard device", + .base.major_version = SPICE_INTERFACE_KEYBOARD_MAJOR, + .base.minor_version = SPICE_INTERFACE_KEYBOARD_MINOR, + .push_scan_freg = my_kbd_push_key, + .get_leds = my_kbd_get_leds, + .push_utf8 = my_kbd_push_utf8, +}; + + +/* vdagent interface - to get mouse/clipboard support */ + +#define VDAGENT_WBUF_SIZE (1024*50) +static unsigned char vdagent_write_buffer[VDAGENT_WBUF_SIZE]; +static int vdagent_write_buffer_pos = 0; +static int agent_owns_clipboard[256] = { 0, }; + +static void +vdagent_reply(spiceTerm *vt, uint32_t type, uint32_t error) +{ + uint32_t size; + + size = sizeof(VDAgentReply); + + int msg_size = sizeof(VDIChunkHeader) + sizeof(VDAgentMessage) + size; + g_assert((vdagent_write_buffer_pos + msg_size) < VDAGENT_WBUF_SIZE); + + unsigned char *buf = vdagent_write_buffer + vdagent_write_buffer_pos; + vdagent_write_buffer_pos += msg_size; + + memset(buf, 0, msg_size); + + VDIChunkHeader *hdr = (VDIChunkHeader *)buf; + VDAgentMessage *msg = (VDAgentMessage *)&hdr[1]; + VDAgentReply *reply = (VDAgentReply *)&msg[1]; + reply->type = type; + reply->error = error; + + hdr->port = VDP_CLIENT_PORT; + hdr->size = sizeof(VDAgentMessage) + size; + + msg->protocol = VD_AGENT_PROTOCOL; + msg->type = VD_AGENT_REPLY; + msg->opaque = 0; + msg->size = size; + + spice_server_char_device_wakeup(&vt->vdagent_sin); +} + +static void +dump_message(unsigned char *buf, int size) +{ + int i; + + for (i = 0; i < size; i++) { + printf("%d %02X\n", i, buf[i]); + } + + // exit(0); +} + +static void +vdagent_send_capabilities(spiceTerm *vt, uint32_t request) +{ + VDAgentAnnounceCapabilities *caps; + uint32_t size; + + size = sizeof(*caps) + VD_AGENT_CAPS_BYTES; + caps = calloc(1, size); + g_assert(caps != NULL); + + caps->request = request; + VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_MOUSE_STATE); + VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_MONITORS_CONFIG); + VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_REPLY); + VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND); + VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_CLIPBOARD_SELECTION); + VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_SPARSE_MONITORS_CONFIG); + VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_GUEST_LINEEND_LF); + + int msg_size = sizeof(VDIChunkHeader) + sizeof(VDAgentMessage) + size; + g_assert((vdagent_write_buffer_pos + msg_size) < VDAGENT_WBUF_SIZE); + + unsigned char *buf = vdagent_write_buffer + vdagent_write_buffer_pos; + vdagent_write_buffer_pos += msg_size; + + VDIChunkHeader *hdr = (VDIChunkHeader *)buf; + VDAgentMessage *msg = (VDAgentMessage *)&hdr[1]; + + hdr->port = VDP_CLIENT_PORT; + hdr->size = sizeof(VDAgentMessage) + size; + msg->protocol = VD_AGENT_PROTOCOL; + msg->type = VD_AGENT_ANNOUNCE_CAPABILITIES; + msg->opaque = 0; + msg->size = size; + + memcpy(buf + sizeof(VDIChunkHeader) + sizeof(VDAgentMessage), (uint8_t *)caps, size); + + if (0) dump_message(buf, msg_size); + + spice_server_char_device_wakeup(&vt->vdagent_sin); + + free(caps); +} + +gboolean +vdagent_owns_clipboard(spiceTerm *vt) +{ + return !!agent_owns_clipboard[VD_AGENT_CLIPBOARD_SELECTION_PRIMARY]; +} + +void +vdagent_grab_clipboard(spiceTerm *vt) +{ + uint32_t size; + + uint8_t selection = VD_AGENT_CLIPBOARD_SELECTION_PRIMARY; + + agent_owns_clipboard[selection] = 1; + + size = 8; + + int msg_size = sizeof(VDIChunkHeader) + sizeof(VDAgentMessage) + size; + g_assert((vdagent_write_buffer_pos + msg_size) < VDAGENT_WBUF_SIZE); + + unsigned char *buf = vdagent_write_buffer + vdagent_write_buffer_pos; + vdagent_write_buffer_pos += msg_size; + + memset(buf, 0, msg_size); + + VDIChunkHeader *hdr = (VDIChunkHeader *)buf; + VDAgentMessage *msg = (VDAgentMessage *)&hdr[1]; + uint8_t *grab = (uint8_t *)&msg[1]; + *((uint8_t *)grab) = selection; + *((uint32_t *)(grab + 4)) = VD_AGENT_CLIPBOARD_UTF8_TEXT; + + hdr->port = VDP_CLIENT_PORT; + hdr->size = sizeof(VDAgentMessage) + size; + + msg->protocol = VD_AGENT_PROTOCOL; + msg->type = VD_AGENT_CLIPBOARD_GRAB; + msg->opaque = 0; + msg->size = size; + + if (0) dump_message(buf, msg_size); + + spice_server_char_device_wakeup(&vt->vdagent_sin); +} + +void +vdagent_request_clipboard(spiceTerm *vt) +{ + uint32_t size; + + uint8_t selection = VD_AGENT_CLIPBOARD_SELECTION_PRIMARY; + + size = 4 + sizeof(VDAgentClipboardRequest); + + int msg_size = sizeof(VDIChunkHeader) + sizeof(VDAgentMessage) + size; + g_assert((vdagent_write_buffer_pos + msg_size) < VDAGENT_WBUF_SIZE); + + unsigned char *buf = vdagent_write_buffer + vdagent_write_buffer_pos; + vdagent_write_buffer_pos += msg_size; + + memset(buf, 0, msg_size); + + VDIChunkHeader *hdr = (VDIChunkHeader *)buf; + VDAgentMessage *msg = (VDAgentMessage *)&hdr[1]; + uint8_t *data = (uint8_t *)&msg[1]; + *((uint32_t *)data) = 0; + data[0] = selection; + ((uint32_t *)data)[1] = VD_AGENT_CLIPBOARD_UTF8_TEXT; + + hdr->port = VDP_CLIENT_PORT; + hdr->size = sizeof(VDAgentMessage) + size; + + msg->protocol = VD_AGENT_PROTOCOL; + msg->type = VD_AGENT_CLIPBOARD_REQUEST; + msg->opaque = 0; + msg->size = size; + + if (0) dump_message(buf, msg_size); + + spice_server_char_device_wakeup(&vt->vdagent_sin); +} + +static void +vdagent_send_clipboard(spiceTerm *vt, uint8_t selection) +{ + uint32_t size; + + if (selection != VD_AGENT_CLIPBOARD_SELECTION_PRIMARY) { + fprintf(stderr, "clipboard select %d is not supported\n", selection); + return; + } + + gchar *sel_data; + glong sel_len; + if (vt->utf8) { + sel_data = g_utf16_to_utf8(vt->selection, vt->selection_len, NULL, &sel_len, NULL); + } else { + sel_len = vt->selection_len; + sel_data = g_malloc(sel_len); + int i; + for (i = 0; i < sel_len; i++) { sel_data[i] = (char)vt->selection[i]; } + sel_data[sel_len] = 0; + } + + size = 8 + sel_len; + + int msg_size = sizeof(VDIChunkHeader) + sizeof(VDAgentMessage) + size; + g_assert((vdagent_write_buffer_pos + msg_size) < VDAGENT_WBUF_SIZE); + + unsigned char *buf = vdagent_write_buffer + vdagent_write_buffer_pos; + vdagent_write_buffer_pos += msg_size; + + memset(buf, 0, msg_size); + + VDIChunkHeader *hdr = (VDIChunkHeader *)buf; + VDAgentMessage *msg = (VDAgentMessage *)&hdr[1]; + uint8_t *data = (uint8_t *)&msg[1]; + *((uint8_t *)data) = selection; + data += 4; + *((uint32_t *)data) = VD_AGENT_CLIPBOARD_UTF8_TEXT; + data += 4; + + memcpy(data, sel_data, sel_len); + g_free(sel_data); + + hdr->port = VDP_CLIENT_PORT; + hdr->size = sizeof(VDAgentMessage) + size; + + msg->protocol = VD_AGENT_PROTOCOL; + msg->type = VD_AGENT_CLIPBOARD; + msg->opaque = 0; + msg->size = size; + + spice_server_char_device_wakeup(&vt->vdagent_sin); +} + +static int +vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len) +{ + spiceTerm *vt = SPICE_CONTAINEROF(sin, spiceTerm, vdagent_sin); + + VDIChunkHeader *hdr = (VDIChunkHeader *)buf; + VDAgentMessage *msg = (VDAgentMessage *)&hdr[1]; + + //g_assert(hdr->port == VDP_SERVER_PORT); + g_assert(msg->protocol == VD_AGENT_PROTOCOL); + + DPRINTF(1, "%d %d %d %d", len, hdr->port, msg->protocol, msg->type); + + switch (msg->type) { + case VD_AGENT_MOUSE_STATE: { + VDAgentMouseState *info = (VDAgentMouseState *)&msg[1]; + spiceterm_motion_event(vt, info->x, info->y, info->buttons); + break; + } + case VD_AGENT_ANNOUNCE_CAPABILITIES: { + VDAgentAnnounceCapabilities *caps = (VDAgentAnnounceCapabilities *)&msg[1]; + DPRINTF(1, "VD_AGENT_ANNOUNCE_CAPABILITIES %d", caps->request); + int i; + + int caps_size = VD_AGENT_CAPS_SIZE_FROM_MSG_SIZE(hdr->size); + for (i = 0; i < VD_AGENT_END_CAP; i++) { + DPRINTF(1, "CAPABILITIES %d %d", i, VD_AGENT_HAS_CAPABILITY(caps->caps, caps_size, i)); + } + + vdagent_send_capabilities(vt, 0); + break; + } + case VD_AGENT_CLIPBOARD_GRAB: { + VDAgentClipboardGrab *grab = (VDAgentClipboardGrab *)&msg[1]; + uint8_t selection = *((uint8_t *)grab); + DPRINTF(1, "VD_AGENT_CLIPBOARD_GRAB %d", selection); + agent_owns_clipboard[selection] = 0; + spiceterm_clear_selection(vt); + break; + } + case VD_AGENT_CLIPBOARD_REQUEST: { + uint8_t *req = (uint8_t *)&msg[1]; + uint8_t selection = *((uint8_t *)req); + uint32_t type = *((uint32_t *)(req + 4)); + + DPRINTF(1, "VD_AGENT_CLIPBOARD_REQUEST %d %d", selection, type); + + vdagent_send_clipboard(vt, selection); + + break; + } + case VD_AGENT_CLIPBOARD: { + uint8_t *data = (uint8_t *)&msg[1]; + uint8_t selection = data[0]; + uint32_t type = *(uint32_t *)(data + 4); + int size = msg->size - 8; + DPRINTF(1, "VD_AGENT_CLIPBOARD %d %d %d", selection, type, size); + + if (type == VD_AGENT_CLIPBOARD_UTF8_TEXT) { + spiceterm_respond_data(vt, size, data + 8); + spiceterm_update_watch_mask(vt, TRUE); + } + break; + } + case VD_AGENT_CLIPBOARD_RELEASE: { + uint8_t *data = (uint8_t *)&msg[1]; + uint8_t selection = data[0]; + + DPRINTF(1, "VD_AGENT_CLIPBOARD_RELEASE %d", selection); + + break; + } + case VD_AGENT_MONITORS_CONFIG: { + VDAgentMonitorsConfig *list = (VDAgentMonitorsConfig *)&msg[1]; + g_assert(list->num_of_monitors > 0); + DPRINTF(1, "VD_AGENT_MONITORS_CONFIG %d %d %d", list->num_of_monitors, + list->monitors[0].width, list->monitors[0].height); + + spiceterm_resize(vt, list->monitors[0].width, list->monitors[0].height); + + vdagent_reply(vt, VD_AGENT_MONITORS_CONFIG, VD_AGENT_SUCCESS); + break; + } + default: + DPRINTF(1, "got uknown vdagent message type %d\n", msg->type); + } + + return len; +} + +static int +vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) +{ + DPRINTF(1, "%d %d", len, vdagent_write_buffer_pos); + g_assert(len >= 8); + + if (!vdagent_write_buffer_pos) { + return 0; + } + + int size = (len >= vdagent_write_buffer_pos) ? vdagent_write_buffer_pos : len; + memcpy(buf, vdagent_write_buffer, size); + if (size < vdagent_write_buffer_pos) { + memmove(vdagent_write_buffer, vdagent_write_buffer + size, + vdagent_write_buffer_pos - size); + } + vdagent_write_buffer_pos -= size; + + DPRINTF(1, "RET %d %d", size, vdagent_write_buffer_pos); + return size; +} + +static void +vmc_state(SpiceCharDeviceInstance *sin, int connected) +{ + /* IGNORE */ +} + +static SpiceCharDeviceInterface my_vdagent_sif = { + .base.type = SPICE_INTERFACE_CHAR_DEVICE, + .base.description = "spice virtual channel char device", + .base.major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR, + .base.minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR, + .state = vmc_state, + .write = vmc_write, + .read = vmc_read, +}; + +spiceTerm * +create_spiceterm(int argc, char** argv, uint32_t maxx, uint32_t maxy, guint timeout) +{ + SpiceCoreInterface *core = basic_event_loop_init(); + SpiceScreen *spice_screen = spice_screen_new(core, maxx, maxy, timeout); + + //spice_server_set_image_compression(server, SPICE_IMAGE_COMPRESS_OFF); + + spice_screen->image_cache = g_hash_table_new(g_int_hash, g_int_equal); + + spiceTerm *vt = (spiceTerm *)calloc (sizeof(spiceTerm), 1); + + vt->keyboard_sin.base.sif = &my_keyboard_sif.base; + spice_server_add_interface(spice_screen->server, &vt->keyboard_sin.base); + + vt->vdagent_sin.base.sif = &my_vdagent_sif.base; + vt->vdagent_sin.subtype = "vdagent"; + spice_server_add_interface(spice_screen->server, &vt->vdagent_sin.base); + vt->screen = spice_screen; + + init_spiceterm(vt, maxx, maxy); + + return vt; +} diff --git a/spiceterm.c b/spiceterm.c index 3031606..8506790 100644 --- a/spiceterm.c +++ b/spiceterm.c @@ -78,12 +78,6 @@ static int debug = 0; unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7, 8,12,10,14, 9,13,11,15 }; - -static void spiceterm_resize(spiceTerm *vt, uint32_t width, uint32_t height); - -static void vdagent_grab_clipboard(spiceTerm *vt, uint8_t selection); -static void vdagent_request_clipboard(spiceTerm *vt, uint8_t selection); - static void print_usage(const char *msg) { @@ -184,7 +178,7 @@ spiceterm_show_cursor(spiceTerm *vt, int show) } } -static void +void spiceterm_refresh(spiceTerm *vt) { int x, y, y1; @@ -330,7 +324,7 @@ spiceterm_scroll_up(spiceTerm *vt, int top, int bottom, int lines, int moveattr) } } -static void +void spiceterm_virtual_scroll(spiceTerm *vt, int lines) { if (vt->altbuf || lines == 0) return; @@ -362,7 +356,7 @@ spiceterm_virtual_scroll(spiceTerm *vt, int lines) spiceterm_refresh(vt); } -static void +void spiceterm_respond_esc(spiceTerm *vt, const char *esc) { int len = strlen(esc); @@ -373,6 +367,24 @@ spiceterm_respond_esc(spiceTerm *vt, const char *esc) for (i = 0; i < len; i++) { vt->ibuf[vt->ibuf_count++] = esc[i]; } + } else { + fprintf(stderr, "input buffer oferflow\n"); + return; + } +} + +void +spiceterm_respond_data(spiceTerm *vt, int len, uint8_t *data) +{ + int i; + + if (vt->ibuf_count < (IBUFSIZE - len)) { + for (i = 0; i < len; i++) { + vt->ibuf[vt->ibuf_count++] = data[i]; + } + } else { + fprintf(stderr, "input buffer oferflow\n"); + return; } } @@ -1283,24 +1295,7 @@ spiceterm_puts(spiceTerm *vt, const char *buf, int len) return len; } -/* fixme: void -spiceterm_set_xcut_text(char* str, int len, struct _rfbClientRec* cl) -{ - spiceTerm *vt =(spiceTerm *)cl->screen->screenData; - - // seems str is Latin-1 encoded - if (vt->selection) free (vt->selection); - vt->selection = (gunichar2 *)malloc (len*sizeof (gunichar2)); - int i; - for (i = 0; i < len; i++) { - vt->selection[i] = str[i] & 0xff; - } - vt->selection_len = len; -} -*/ - -static void spiceterm_update_watch_mask(spiceTerm *vt, gboolean writable) { g_assert(vt != NULL); @@ -1335,252 +1330,15 @@ spiceterm_respond_unichar2(spiceTerm *vt, gunichar2 uc) gint len = g_unichar_to_utf8(uc, buf); if (len > 0) { - if ((vt->ibuf_count + len) < IBUFSIZE) { - int i; - for (i = 0; i < len; i++) { - vt->ibuf[vt->ibuf_count++] = buf[i]; - } - } else { - fprintf(stderr, "warning: input buffer overflow\n"); - } - } - } else { - if ((vt->ibuf_count + 1) < IBUFSIZE) { - vt->ibuf[vt->ibuf_count++] = (char)uc; - } else { - fprintf(stderr, "warning: input buffer overflow\n"); - } - } -} - -static uint8_t -my_kbd_get_leds(SpiceKbdInstance *sin) -{ - return 0; -} - -#define KBD_MOD_CONTROL_L_FLAG (1<<0) -#define KBD_MOD_CONTROL_R_FLAG (1<<1) -#define KBD_MOD_SHIFT_L_FLAG (1<<2) -#define KBD_MOD_SHIFT_R_FLAG (1<<3) - -static int kbd_flags = 0; -static void -my_kbd_push_key(SpiceKbdInstance *sin, uint8_t frag) -{ - spiceTerm *vt = SPICE_CONTAINEROF(sin, spiceTerm, keyboard_sin); - - char *esc = NULL; // used to send special keys - - static int e0_mode = 0; - - DPRINTF(1, "enter frag=%02x flags=%08x", frag, kbd_flags); - - if (e0_mode) { - e0_mode = 0; - switch (frag) { - case 0x1d: // press Control_R - kbd_flags |= KBD_MOD_CONTROL_R_FLAG; - break; - case 0x9d: // release Control_R - kbd_flags &= ~KBD_MOD_CONTROL_R_FLAG; - break; - case 0x47: // press Home - esc = "OH"; - break; - case 0x4f: // press END - esc = "OF"; - break; - case 0x48: // press UP - esc = "OA"; - break; - case 0x50: // press DOWN - esc = "OB"; - break; - case 0x4b: // press LEFT - esc = "OD"; - break; - case 0x4d: // press RIGHT - esc = "OC"; - break; - case 0x52: // press INSERT - esc = "[2~"; - break; - case 0x49: // press PAGE_UP - if (kbd_flags & (KBD_MOD_SHIFT_L_FLAG|KBD_MOD_SHIFT_R_FLAG)) { - spiceterm_virtual_scroll (vt, -vt->height/2); - } - break; - case 0x51: // press PAGE_DOWN - if (kbd_flags & (KBD_MOD_SHIFT_L_FLAG|KBD_MOD_SHIFT_R_FLAG)) { - spiceterm_virtual_scroll (vt, vt->height/2); - } - break; - } - } else { - switch (frag) { - case 0xe0: - e0_mode = 1; - break; - case 0x1d: // press Control_L - kbd_flags |= KBD_MOD_CONTROL_L_FLAG; - break; - case 0x9d: // release Control_L - kbd_flags &= ~KBD_MOD_CONTROL_L_FLAG; - break; - case 0x2a: // press Shift_L - kbd_flags |= KBD_MOD_SHIFT_L_FLAG; - break; - case 0xaa: // release Shift_L - kbd_flags &= ~KBD_MOD_SHIFT_L_FLAG; - break; - case 0x36: // press Shift_R - kbd_flags |= KBD_MOD_SHIFT_R_FLAG; - break; - case 0xb6: // release Shift_R - kbd_flags &= ~KBD_MOD_SHIFT_R_FLAG; - break; - case 0x52: // press KP_INSERT - esc = "[2~"; - break; - case 0x53: // press KP_Delete - esc = "[3~"; - break; - case 0x47: // press KP_Home - esc = "OH"; - break; - case 0x4f: // press KP_END - esc = "OF"; - break; - case 0x48: // press KP_UP - esc = "OA"; - break; - case 0x50: // press KP_DOWN - esc = "OB"; - break; - case 0x4b: // press KP_LEFT - esc = "OD"; - break; - case 0x4d: // press KP_RIGHT - esc = "OC"; - break; - case 0x3b: // press F1 - esc = "OP"; - break; - case 0x3c: // press F2 - esc = "OQ"; - break; - case 0x3d: // press F3 - esc = "OR"; - break; - case 0x3e: // press F4 - esc = "OS"; - break; - case 0x3f: // press F5 - esc = "[15~"; - break; - case 0x40: // press F6 - esc = "[17~"; - break; - case 0x41: // press F7 - esc = "[18~"; - break; - case 0x42: // press F8 - esc = "[19~"; - break; - case 0x43: // press F9 - esc = "[20~"; - break; - case 0x44: // press F10 - esc = "[21~"; - break; - case 0x57: // press F11 - esc = "[23~"; - break; - case 0x58: // press F12 - esc = "[24~"; - break; - } - } - - if (esc) { - DPRINTF(1, "escape=%s", esc); - spiceterm_respond_esc(vt, esc); - - if (vt->y_displ != vt->y_base) { - vt->y_displ = vt->y_base; - spiceterm_refresh(vt); - } - - spiceterm_update_watch_mask(vt, TRUE); - } - - DPRINTF(1, "leave frag=%02x flags=%08x", frag, kbd_flags); - return; -} - -static void -my_kbd_push_utf8(SpiceKbdInstance *sin, uint32_t size, uint8_t *data) -{ - spiceTerm *vt = SPICE_CONTAINEROF(sin, spiceTerm, keyboard_sin); - - DPRINTF(1, " size=%d data[0]=%02x", size, data[0]); - - if (vt->ibuf_count + size >= IBUFSIZE) { - fprintf(stderr, "input buffer oferflow\n"); - return; - } - - if (kbd_flags & (KBD_MOD_CONTROL_L_FLAG|KBD_MOD_CONTROL_R_FLAG)) { - if (size != 1) return; - if (data[0] >= 'a' && data[0] <= 'z') { - vt->ibuf[vt->ibuf_count++] = data[0] - 'a' + 1; - } else if (data[0] >= 'A' && data[0] <= 'Z') { - vt->ibuf[vt->ibuf_count++] = data[0] - 'A' + 1; + spiceterm_respond_data(vt, len, (uint8_t *)buf); } } else { - if (size == 1 && data[0] == 0x7f) { - /* use an escape sequence for DELETE, else it behaves - * like BACKSPACE - */ - spiceterm_respond_esc(vt, "[3~"); - } else { - int i; - for (i = 0; i < size; i++) { - vt->ibuf[vt->ibuf_count++] = data[i]; - } - } - } - - if (vt->y_displ != vt->y_base) { - vt->y_displ = vt->y_base; - spiceterm_refresh(vt); + uint8_t buf[1] = { (uint8_t)uc }; + spiceterm_respond_data(vt, 1, buf); } - - spiceterm_update_watch_mask(vt, TRUE); - - return; } -static SpiceKbdInterface my_keyboard_sif = { - .base.type = SPICE_INTERFACE_KEYBOARD, - .base.description = "spiceterm keyboard device", - .base.major_version = SPICE_INTERFACE_KEYBOARD_MAJOR, - .base.minor_version = SPICE_INTERFACE_KEYBOARD_MINOR, - .push_scan_freg = my_kbd_push_key, - .get_leds = my_kbd_get_leds, - .push_utf8 = my_kbd_push_utf8, -}; - - -/* vdagent interface - to get mouse/clipboarde support */ - -#define VDAGENT_WBUF_SIZE (1024*50) -static unsigned char vdagent_write_buffer[VDAGENT_WBUF_SIZE]; -static int vdagent_write_buffer_pos = 0; -static int agent_owns_clipboard[256] = { 0, }; - -static void +void spiceterm_clear_selection(spiceTerm *vt) { DPRINTF(1, "mark_active = %d", vt->mark_active); @@ -1592,7 +1350,7 @@ spiceterm_clear_selection(spiceTerm *vt) spiceterm_unselect_all(vt); } -static void +void spiceterm_motion_event(spiceTerm *vt, uint32_t x, uint32_t y, uint32_t buttons) { DPRINTF(1, "mask=%08x x=%d y=%d", buttons, x ,y); @@ -1631,7 +1389,7 @@ spiceterm_motion_event(spiceTerm *vt, uint32_t x, uint32_t y, uint32_t buttons) if(button2_released) { - if (agent_owns_clipboard[VD_AGENT_CLIPBOARD_SELECTION_PRIMARY]) { + if (vdagent_owns_clipboard(vt)) { if (vt->selection) { int i; for(i = 0; i < vt->selection_len; i++) { @@ -1644,7 +1402,7 @@ spiceterm_motion_event(spiceTerm *vt, uint32_t x, uint32_t y, uint32_t buttons) } } } else { - vdagent_request_clipboard(vt, VD_AGENT_CLIPBOARD_SELECTION_PRIMARY); + vdagent_request_clipboard(vt); } } @@ -1716,355 +1474,11 @@ spiceterm_motion_event(spiceTerm *vt, uint32_t x, uint32_t y, uint32_t buttons) DPRINTF(1, "selection length = %d", vt->selection_len); - vdagent_grab_clipboard(vt, VD_AGENT_CLIPBOARD_SELECTION_PRIMARY); - } -} - -static void -vdagent_reply(spiceTerm *vt, uint32_t type, uint32_t error) -{ - uint32_t size; - - size = sizeof(VDAgentReply); - - int msg_size = sizeof(VDIChunkHeader) + sizeof(VDAgentMessage) + size; - g_assert((vdagent_write_buffer_pos + msg_size) < VDAGENT_WBUF_SIZE); - - unsigned char *buf = vdagent_write_buffer + vdagent_write_buffer_pos; - vdagent_write_buffer_pos += msg_size; - - memset(buf, 0, msg_size); - - VDIChunkHeader *hdr = (VDIChunkHeader *)buf; - VDAgentMessage *msg = (VDAgentMessage *)&hdr[1]; - VDAgentReply *reply = (VDAgentReply *)&msg[1]; - reply->type = type; - reply->error = error; - - hdr->port = VDP_CLIENT_PORT; - hdr->size = sizeof(VDAgentMessage) + size; - - msg->protocol = VD_AGENT_PROTOCOL; - msg->type = VD_AGENT_REPLY; - msg->opaque = 0; - msg->size = size; - - spice_server_char_device_wakeup(&vt->vdagent_sin); -} - -static void -dump_message(unsigned char *buf, int size) -{ - int i; - - for (i = 0; i < size; i++) { - printf("%d %02X\n", i, buf[i]); - } - - // exit(0); -} - -static void vdagent_send_capabilities(spiceTerm *vt, uint32_t request) -{ - VDAgentAnnounceCapabilities *caps; - uint32_t size; - - size = sizeof(*caps) + VD_AGENT_CAPS_BYTES; - caps = calloc(1, size); - g_assert(caps != NULL); - - caps->request = request; - VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_MOUSE_STATE); - VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_MONITORS_CONFIG); - VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_REPLY); - VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND); - VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_CLIPBOARD_SELECTION); - VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_SPARSE_MONITORS_CONFIG); - VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_GUEST_LINEEND_LF); - - int msg_size = sizeof(VDIChunkHeader) + sizeof(VDAgentMessage) + size; - g_assert((vdagent_write_buffer_pos + msg_size) < VDAGENT_WBUF_SIZE); - - unsigned char *buf = vdagent_write_buffer + vdagent_write_buffer_pos; - vdagent_write_buffer_pos += msg_size; - - VDIChunkHeader *hdr = (VDIChunkHeader *)buf; - VDAgentMessage *msg = (VDAgentMessage *)&hdr[1]; - - hdr->port = VDP_CLIENT_PORT; - hdr->size = sizeof(VDAgentMessage) + size; - msg->protocol = VD_AGENT_PROTOCOL; - msg->type = VD_AGENT_ANNOUNCE_CAPABILITIES; - msg->opaque = 0; - msg->size = size; - - memcpy(buf + sizeof(VDIChunkHeader) + sizeof(VDAgentMessage), (uint8_t *)caps, size); - - if (0) dump_message(buf, msg_size); - - spice_server_char_device_wakeup(&vt->vdagent_sin); - - free(caps); -} - -static void vdagent_grab_clipboard(spiceTerm *vt, uint8_t selection) -{ - uint32_t size; - - agent_owns_clipboard[selection] = 1; - - size = 8; - - int msg_size = sizeof(VDIChunkHeader) + sizeof(VDAgentMessage) + size; - g_assert((vdagent_write_buffer_pos + msg_size) < VDAGENT_WBUF_SIZE); - - unsigned char *buf = vdagent_write_buffer + vdagent_write_buffer_pos; - vdagent_write_buffer_pos += msg_size; - - memset(buf, 0, msg_size); - - VDIChunkHeader *hdr = (VDIChunkHeader *)buf; - VDAgentMessage *msg = (VDAgentMessage *)&hdr[1]; - uint8_t *grab = (uint8_t *)&msg[1]; - *((uint8_t *)grab) = selection; - *((uint32_t *)(grab + 4)) = VD_AGENT_CLIPBOARD_UTF8_TEXT; - - hdr->port = VDP_CLIENT_PORT; - hdr->size = sizeof(VDAgentMessage) + size; - - msg->protocol = VD_AGENT_PROTOCOL; - msg->type = VD_AGENT_CLIPBOARD_GRAB; - msg->opaque = 0; - msg->size = size; - - if (0) dump_message(buf, msg_size); - - spice_server_char_device_wakeup(&vt->vdagent_sin); -} - -static void vdagent_request_clipboard(spiceTerm *vt, uint8_t selection) -{ - uint32_t size; - - size = 4 + sizeof(VDAgentClipboardRequest); - - int msg_size = sizeof(VDIChunkHeader) + sizeof(VDAgentMessage) + size; - g_assert((vdagent_write_buffer_pos + msg_size) < VDAGENT_WBUF_SIZE); - - unsigned char *buf = vdagent_write_buffer + vdagent_write_buffer_pos; - vdagent_write_buffer_pos += msg_size; - - memset(buf, 0, msg_size); - - VDIChunkHeader *hdr = (VDIChunkHeader *)buf; - VDAgentMessage *msg = (VDAgentMessage *)&hdr[1]; - uint8_t *data = (uint8_t *)&msg[1]; - *((uint32_t *)data) = 0; - data[0] = selection; - ((uint32_t *)data)[1] = VD_AGENT_CLIPBOARD_UTF8_TEXT; - - hdr->port = VDP_CLIENT_PORT; - hdr->size = sizeof(VDAgentMessage) + size; - - msg->protocol = VD_AGENT_PROTOCOL; - msg->type = VD_AGENT_CLIPBOARD_REQUEST; - msg->opaque = 0; - msg->size = size; - - if (0) dump_message(buf, msg_size); - - spice_server_char_device_wakeup(&vt->vdagent_sin); -} - -static void vdagent_send_clipboard(spiceTerm *vt, uint8_t selection) -{ - uint32_t size; - - if (selection != VD_AGENT_CLIPBOARD_SELECTION_PRIMARY) { - fprintf(stderr, "clipboard select %d is not supported\n", selection); - return; - } - - gchar *sel_data; - glong sel_len; - if (vt->utf8) { - sel_data = g_utf16_to_utf8(vt->selection, vt->selection_len, NULL, &sel_len, NULL); - } else { - sel_len = vt->selection_len; - sel_data = g_malloc(sel_len); - int i; - for (i = 0; i < sel_len; i++) { sel_data[i] = (char)vt->selection[i]; } - sel_data[sel_len] = 0; - } - - size = 8 + sel_len; - - int msg_size = sizeof(VDIChunkHeader) + sizeof(VDAgentMessage) + size; - g_assert((vdagent_write_buffer_pos + msg_size) < VDAGENT_WBUF_SIZE); - - unsigned char *buf = vdagent_write_buffer + vdagent_write_buffer_pos; - vdagent_write_buffer_pos += msg_size; - - memset(buf, 0, msg_size); - - VDIChunkHeader *hdr = (VDIChunkHeader *)buf; - VDAgentMessage *msg = (VDAgentMessage *)&hdr[1]; - uint8_t *data = (uint8_t *)&msg[1]; - *((uint8_t *)data) = selection; - data += 4; - *((uint32_t *)data) = VD_AGENT_CLIPBOARD_UTF8_TEXT; - data += 4; - - memcpy(data, sel_data, sel_len); - g_free(sel_data); - - hdr->port = VDP_CLIENT_PORT; - hdr->size = sizeof(VDAgentMessage) + size; - - msg->protocol = VD_AGENT_PROTOCOL; - msg->type = VD_AGENT_CLIPBOARD; - msg->opaque = 0; - msg->size = size; - - spice_server_char_device_wakeup(&vt->vdagent_sin); -} - -static int -vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len) -{ - spiceTerm *vt = SPICE_CONTAINEROF(sin, spiceTerm, vdagent_sin); - - VDIChunkHeader *hdr = (VDIChunkHeader *)buf; - VDAgentMessage *msg = (VDAgentMessage *)&hdr[1]; - - //g_assert(hdr->port == VDP_SERVER_PORT); - g_assert(msg->protocol == VD_AGENT_PROTOCOL); - - DPRINTF(1, "%d %d %d %d", len, hdr->port, msg->protocol, msg->type); - - switch (msg->type) { - case VD_AGENT_MOUSE_STATE: { - VDAgentMouseState *info = (VDAgentMouseState *)&msg[1]; - spiceterm_motion_event(vt, info->x, info->y, info->buttons); - break; - } - case VD_AGENT_ANNOUNCE_CAPABILITIES: { - VDAgentAnnounceCapabilities *caps = (VDAgentAnnounceCapabilities *)&msg[1]; - DPRINTF(1, "VD_AGENT_ANNOUNCE_CAPABILITIES %d", caps->request); - int i; - - int caps_size = VD_AGENT_CAPS_SIZE_FROM_MSG_SIZE(hdr->size); - for (i = 0; i < VD_AGENT_END_CAP; i++) { - DPRINTF(1, "CAPABILITIES %d %d", i, VD_AGENT_HAS_CAPABILITY(caps->caps, caps_size, i)); - } - - vdagent_send_capabilities(vt, 0); - break; - } - case VD_AGENT_CLIPBOARD_GRAB: { - VDAgentClipboardGrab *grab = (VDAgentClipboardGrab *)&msg[1]; - uint8_t selection = *((uint8_t *)grab); - DPRINTF(1, "VD_AGENT_CLIPBOARD_GRAB %d", selection); - agent_owns_clipboard[selection] = 0; - spiceterm_clear_selection(vt); - break; - } - case VD_AGENT_CLIPBOARD_REQUEST: { - uint8_t *req = (uint8_t *)&msg[1]; - uint8_t selection = *((uint8_t *)req); - uint32_t type = *((uint32_t *)(req + 4)); - - DPRINTF(1, "VD_AGENT_CLIPBOARD_REQUEST %d %d", selection, type); - - vdagent_send_clipboard(vt, selection); - - break; - } - case VD_AGENT_CLIPBOARD: { - uint8_t *data = (uint8_t *)&msg[1]; - uint8_t selection = data[0]; - uint32_t type = *(uint32_t *)(data + 4); - int size = msg->size - 8; - DPRINTF(1, "VD_AGENT_CLIPBOARD %d %d %d", selection, type, size); - - if (type == VD_AGENT_CLIPBOARD_UTF8_TEXT) { - int i; - for (i = 0; i < size; i++) { - if ((vt->ibuf_count + 1) < IBUFSIZE) { - vt->ibuf[vt->ibuf_count++] = *(char *)(data + 8 + i); - } else { - fprintf(stderr, "warning: input buffer overflow\n"); - } - } - spiceterm_update_watch_mask(vt, TRUE); - } - break; - } - case VD_AGENT_CLIPBOARD_RELEASE: { - uint8_t *data = (uint8_t *)&msg[1]; - uint8_t selection = data[0]; - - DPRINTF(1, "VD_AGENT_CLIPBOARD_RELEASE %d", selection); - - break; + vdagent_grab_clipboard(vt); } - case VD_AGENT_MONITORS_CONFIG: { - VDAgentMonitorsConfig *list = (VDAgentMonitorsConfig *)&msg[1]; - g_assert(list->num_of_monitors > 0); - DPRINTF(1, "VD_AGENT_MONITORS_CONFIG %d %d %d", list->num_of_monitors, - list->monitors[0].width, list->monitors[0].height); - - spiceterm_resize(vt, list->monitors[0].width, list->monitors[0].height); - - vdagent_reply(vt, VD_AGENT_MONITORS_CONFIG, VD_AGENT_SUCCESS); - break; - } - default: - DPRINTF(1, "got uknown vdagent message type %d\n", msg->type); - } - - return len; -} - -static int -vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) -{ - DPRINTF(1, "%d %d", len, vdagent_write_buffer_pos); - g_assert(len >= 8); - - if (!vdagent_write_buffer_pos) { - return 0; - } - - int size = (len >= vdagent_write_buffer_pos) ? vdagent_write_buffer_pos : len; - memcpy(buf, vdagent_write_buffer, size); - if (size < vdagent_write_buffer_pos) { - memmove(vdagent_write_buffer, vdagent_write_buffer + size, - vdagent_write_buffer_pos - size); - } - vdagent_write_buffer_pos -= size; - - DPRINTF(1, "RET %d %d", size, vdagent_write_buffer_pos); - return size; -} - -static void -vmc_state(SpiceCharDeviceInstance *sin, int connected) -{ - /* IGNORE */ } -static SpiceCharDeviceInterface my_vdagent_sif = { - .base.type = SPICE_INTERFACE_CHAR_DEVICE, - .base.description = "spice virtual channel char device", - .base.major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR, - .base.minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR, - .state = vmc_state, - .write = vmc_write, - .read = vmc_read, -}; - -static void +void init_spiceterm(spiceTerm *vt, uint32_t width, uint32_t height) { int i; @@ -2121,7 +1535,7 @@ init_spiceterm(spiceTerm *vt, uint32_t width, uint32_t height) vt->altcells = (TextCell *)calloc (sizeof (TextCell), vt->width*vt->height); } -static void +void spiceterm_resize(spiceTerm *vt, uint32_t width, uint32_t height) { width = (width/8)*8; @@ -2144,31 +1558,6 @@ spiceterm_resize(spiceTerm *vt, uint32_t width, uint32_t height) ioctl(vt->pty, TIOCSWINSZ, &dimensions); } -static spiceTerm * -create_spiceterm(int argc, char** argv, uint32_t maxx, uint32_t maxy, guint timeout) -{ - SpiceCoreInterface *core = basic_event_loop_init(); - SpiceScreen *spice_screen = spice_screen_new(core, maxx, maxy, timeout); - - //spice_server_set_image_compression(server, SPICE_IMAGE_COMPRESS_OFF); - - spice_screen->image_cache = g_hash_table_new(g_int_hash, g_int_equal); - - spiceTerm *vt = (spiceTerm *)calloc (sizeof(spiceTerm), 1); - - vt->keyboard_sin.base.sif = &my_keyboard_sif.base; - spice_server_add_interface(spice_screen->server, &vt->keyboard_sin.base); - - vt->vdagent_sin.base.sif = &my_vdagent_sif.base; - vt->vdagent_sin.subtype = "vdagent"; - spice_server_add_interface(spice_screen->server, &vt->vdagent_sin.base); - vt->screen = spice_screen; - - init_spiceterm(vt, maxx, maxy); - - return vt; -} - static gboolean master_error_callback(GIOChannel *channel, GIOCondition condition, gpointer data) diff --git a/spiceterm.h b/spiceterm.h index 6657186..7a42ad8 100644 --- a/spiceterm.h +++ b/spiceterm.h @@ -138,3 +138,25 @@ typedef struct spiceTerm { unsigned int report_mouse:1; } spiceTerm; + +void init_spiceterm(spiceTerm *vt, uint32_t width, uint32_t height); +void spiceterm_refresh(spiceTerm *vt); + +void spiceterm_resize(spiceTerm *vt, uint32_t width, uint32_t height); +void spiceterm_virtual_scroll(spiceTerm *vt, int lines); +void spiceterm_clear_selection(spiceTerm *vt); +void spiceterm_motion_event(spiceTerm *vt, uint32_t x, uint32_t y, + uint32_t buttons); + +void spiceterm_respond_esc(spiceTerm *vt, const char *esc); +void spiceterm_respond_data(spiceTerm *vt, int len, uint8_t *data); +void spiceterm_update_watch_mask(spiceTerm *vt, gboolean writable); + +spiceTerm *create_spiceterm(int argc, char** argv, uint32_t maxx, + uint32_t maxy, guint timeout); + +gboolean vdagent_owns_clipboard(spiceTerm *vt); +void vdagent_request_clipboard(spiceTerm *vt); +void vdagent_grab_clipboard(spiceTerm *vt); + + -- 2.39.2