From 8f53ae816c9d9a1ddc4e3e2bef99f482855805a6 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Tue, 17 Sep 2013 12:57:23 +0200 Subject: [PATCH] implement resize --- screen.c | 26 ++++++++-- spiceterm.c | 138 ++++++++++++++++++++++++++++++++++++++++------------ spiceterm.h | 6 +-- 3 files changed, 130 insertions(+), 40 deletions(-) diff --git a/screen.c b/screen.c index 34ba4c6..ff36f18 100644 --- a/screen.c +++ b/screen.c @@ -90,9 +90,6 @@ spice_screen_destroy_update(SimpleSpiceUpdate *update) g_free(update); } -#define DEFAULT_WIDTH 640 -#define DEFAULT_HEIGHT 320 - static int unique = 0x0ffff + 1; static void @@ -350,6 +347,22 @@ create_primary_surface(SpiceScreen *spice_screen, uint32_t width, qxl_worker->create_primary_surface(qxl_worker, 0, &surface); } +void +spice_screen_resize(SpiceScreen *spice_screen, uint32_t width, + uint32_t height) +{ + QXLWorker *qxl_worker = spice_screen->qxl_worker; + + if (spice_screen->width == width && spice_screen->height == height) { + return; + } + + qxl_worker->destroy_primary_surface(qxl_worker, 0); + + create_primary_surface(spice_screen, width, height); +} + + QXLDevMemSlot slot = { .slot_group_id = MEM_SLOT_GROUP_ID, .slot_id = 0, @@ -371,7 +384,7 @@ attache_worker(QXLInstance *qin, QXLWorker *_qxl_worker) spice_screen->qxl_worker = _qxl_worker; spice_screen->qxl_worker->add_memslot(spice_screen->qxl_worker, &slot); - create_primary_surface(spice_screen, DEFAULT_WIDTH, DEFAULT_HEIGHT); + create_primary_surface(spice_screen, spice_screen->width, spice_screen->height); spice_screen->qxl_worker->start(spice_screen->qxl_worker); } @@ -668,12 +681,15 @@ spice_screen_draw_char(SpiceScreen *spice_screen, int x, int y, gunichar2 ch, } SpiceScreen * -spice_screen_new(SpiceCoreInterface *core, guint timeout) +spice_screen_new(SpiceCoreInterface *core, uint32_t width, uint32_t height, guint timeout) { int port = 5912; SpiceScreen *spice_screen = g_new0(SpiceScreen, 1); SpiceServer* server = spice_server_new(); + spice_screen->width = width; + spice_screen->height = height; + spice_screen->command_cond = g_cond_new(); spice_screen->command_mutex = g_mutex_new(); diff --git a/spiceterm.c b/spiceterm.c index afbda2b..31f719f 100644 --- a/spiceterm.c +++ b/spiceterm.c @@ -79,6 +79,8 @@ 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); @@ -1444,7 +1446,7 @@ my_kbd_push_keyval(SpiceKbdInstance *sin, uint32_t keySym, int flags) if (vt->y_displ != vt->y_base) { vt->y_displ = vt->y_base; - spiceterm_refresh (vt); + spiceterm_refresh(vt); } if (esc) { @@ -1621,6 +1623,38 @@ spiceterm_motion_event(spiceTerm *vt, uint32_t x, uint32_t y, uint32_t buttons) } } +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 vdagent_send_capabilities(spiceTerm *vt, uint32_t request) { VDAgentAnnounceCapabilities *caps; @@ -1876,9 +1910,17 @@ vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len) break; } - case VD_AGENT_MONITORS_CONFIG: - /* ignore for now */ + case VD_AGENT_MONITORS_CONFIG: { + VDAgentMonitorsConfig *list = (VDAgentMonitorsConfig *)&msg[1]; + g_assert(list->num_of_monitors > 0); + DPRINTF(0, "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(0, "got uknown vdagent message type %d\n", msg->type); } @@ -1889,7 +1931,7 @@ vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len) static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) { - DPRINTF(0, "%d %d", len, vdagent_write_buffer_pos); + DPRINTF(1, "%d %d", len, vdagent_write_buffer_pos); g_assert(len >= 8); if (!vdagent_write_buffer_pos) { @@ -1899,13 +1941,12 @@ vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) int size = (len >= vdagent_write_buffer_pos) ? vdagent_write_buffer_pos : len; memcpy(buf, vdagent_write_buffer, size); if (size < vdagent_write_buffer_pos) { - DPRINTF(0, "MOVE %d", size); memmove(vdagent_write_buffer, vdagent_write_buffer + size, vdagent_write_buffer_pos - size); } vdagent_write_buffer_pos -= size; - DPRINTF(0, "RET %d %d", size, vdagent_write_buffer_pos); + DPRINTF(1, "RET %d %d", size, vdagent_write_buffer_pos); return size; } @@ -1925,36 +1966,16 @@ static SpiceCharDeviceInterface my_vdagent_sif = { .read = vmc_read, }; -static spiceTerm * -create_spiceterm(int argc, char** argv, int maxx, int maxy, guint timeout) +static void +init_spiceterm(spiceTerm *vt, uint32_t width, uint32_t height) { int i; - SpiceScreen *spice_screen; - - SpiceCoreInterface *core = basic_event_loop_init(); - spice_screen = spice_screen_new(core, timeout); - //spice_server_set_image_compression(server, SPICE_IMAGE_COMPRESS_OFF); - - 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); - - // screen->setXCutText = spiceterm_set_xcut_text; - // screen->ptrAddEvent = spiceterm_pointer_event; - // screen->newClientHook = new_client; - // screen->desktopName = "SPICE Command Terminal"; - - vt->maxx = spice_screen->width; - vt->maxy = spice_screen->height; + g_assert(vt != NULL); + g_assert(vt->screen != NULL); - vt->width = vt->maxx / 8; - vt->height = vt->maxy / 16; + vt->width = width / 8; + vt->height = height / 16; vt->total_height = vt->height * 20; vt->scroll_height = 0; @@ -1980,17 +2001,68 @@ create_spiceterm(int argc, char** argv, int maxx, int maxy, guint timeout) vt->cur_attrib = vt->default_attrib; + if (vt->cells) { + vt->cx = 0; + vt->cy = 0; + vt->cx_saved = 0; + vt->cy_saved = 0; + g_free(vt->cells); + } + vt->cells = (TextCell *)calloc (sizeof (TextCell), vt->width*vt->total_height); for (i = 0; i < vt->width*vt->total_height; i++) { vt->cells[i].ch = ' '; vt->cells[i].attrib = vt->default_attrib; } + + if (vt->altcells) { + g_free(vt->altcells); + } vt->altcells = (TextCell *)calloc (sizeof (TextCell), vt->width*vt->height); +} + +static void +spiceterm_resize(spiceTerm *vt, uint32_t width, uint32_t height) +{ + DPRINTF(0, "width=%u height=%u", width, height); + + if (vt->screen->width == width && vt->screen->height == height) { + return; + } + + spice_screen_resize(vt->screen, width, height); + + init_spiceterm(vt, width, height); + + struct winsize dimensions; + dimensions.ws_col = vt->width; + dimensions.ws_row = vt->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); + 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; } @@ -2110,6 +2182,8 @@ main (int argc, char** argv) exit (-1); } + vt->pty = master; + /* watch for errors - we need to use glib directly because spice * does not have SPICE_WATCH_EVENT for this */ GIOChannel *channel = g_io_channel_unix_new(master); diff --git a/spiceterm.h b/spiceterm.h index c2454f8..0fb3f3c 100644 --- a/spiceterm.h +++ b/spiceterm.h @@ -58,8 +58,9 @@ struct SpiceScreen { void (*on_client_disconnected)(SpiceScreen *spice_screen); }; -SpiceScreen* spice_screen_new(SpiceCoreInterface* core, guint timeout); +SpiceScreen* spice_screen_new(SpiceCoreInterface* core, uint32_t width, uint32_t height, guint timeout); +void spice_screen_resize(SpiceScreen *spice_screen, uint32_t width, uint32_t height); void spice_screen_draw_char(SpiceScreen *spice_screen, int x, int y, gunichar2 ch, TextAttributes attrib); void spice_screen_scroll(SpiceScreen *spice_screen, int x1, int y1, int x2, int y2, int src_x, int src_y); void spice_screen_clear(SpiceScreen *spice_screen, int x1, int y1, int x2, int y2); @@ -67,8 +68,7 @@ uint32_t spice_screen_get_width(void); uint32_t spice_screen_get_height(void); typedef struct spiceTerm { - int maxx; - int maxy; + int pty; // pty file descriptor int width; int height; -- 2.39.2