From 5643fc012c2b7335eda43db90bd1e64d912428b0 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Sat, 7 Jun 2014 13:03:10 +0200 Subject: [PATCH] spice: add mouse cursor support So you'll have a mouse pointer when running non-qxl gfx cards with mouse pointer support (virtio-gpu, IIRC vmware too). Signed-off-by: Gerd Hoffmann --- hw/display/qxl.c | 6 ++- include/ui/spice-display.h | 14 +++++ ui/spice-display.c | 129 +++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 137 insertions(+), 12 deletions(-) diff --git a/hw/display/qxl.c b/hw/display/qxl.c index 7fb83e4..736fd3c 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -710,7 +710,11 @@ static void interface_release_resource(QXLInstance *sin, if (ext.group_id == MEMSLOT_GROUP_HOST) { /* host group -> vga mode update request */ - qemu_spice_destroy_update(&qxl->ssd, (void *)(intptr_t)ext.info->id); + QXLCommandExt *cmdext = (void *)(ext.info->id); + SimpleSpiceUpdate *update; + g_assert(cmdext->cmd.type == QXL_CMD_DRAW); + update = container_of(cmdext, SimpleSpiceUpdate, ext); + qemu_spice_destroy_update(&qxl->ssd, update); return; } diff --git a/include/ui/spice-display.h b/include/ui/spice-display.h index a46bc80..4252ab8 100644 --- a/include/ui/spice-display.h +++ b/include/ui/spice-display.h @@ -69,6 +69,7 @@ QXLCookie *qxl_cookie_new(int type, uint64_t io); typedef struct SimpleSpiceDisplay SimpleSpiceDisplay; typedef struct SimpleSpiceUpdate SimpleSpiceUpdate; +typedef struct SimpleSpiceCursor SimpleSpiceCursor; struct SimpleSpiceDisplay { DisplaySurface *ds; @@ -92,6 +93,13 @@ struct SimpleSpiceDisplay { */ QemuMutex lock; QTAILQ_HEAD(, SimpleSpiceUpdate) updates; + + /* cursor (without qxl): displaychangelistener -> spice server */ + SimpleSpiceCursor *ptr_define; + SimpleSpiceCursor *ptr_move; + uint16_t ptr_x, ptr_y; + + /* cursor (with qxl): qxl local renderer -> displaychangelistener */ QEMUCursor *cursor; int mouse_x, mouse_y; }; @@ -104,6 +112,12 @@ struct SimpleSpiceUpdate { QTAILQ_ENTRY(SimpleSpiceUpdate) next; }; +struct SimpleSpiceCursor { + QXLCursorCmd cmd; + QXLCommandExt ext; + QXLCursor cursor; +}; + int qemu_spice_rect_is_empty(const QXLRect* r); void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r); diff --git a/ui/spice-display.c b/ui/spice-display.c index ce6b220..03040b1 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -153,7 +153,7 @@ static void qemu_spice_create_one_update(SimpleSpiceDisplay *ssd, drawable->bbox = *rect; drawable->clip.type = SPICE_CLIP_TYPE_NONE; drawable->effect = QXL_EFFECT_OPAQUE; - drawable->release_info.id = (uintptr_t)update; + drawable->release_info.id = (uintptr_t)(&update->ext); drawable->type = QXL_DRAW_COPY; drawable->surfaces_dest[0] = -1; drawable->surfaces_dest[1] = -1; @@ -264,6 +264,49 @@ static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) memset(&ssd->dirty, 0, sizeof(ssd->dirty)); } +static SimpleSpiceCursor* +qemu_spice_create_cursor_update(SimpleSpiceDisplay *ssd, + QEMUCursor *c) +{ + size_t size = c ? c->width * c->height * 4 : 0; + SimpleSpiceCursor *update; + QXLCursorCmd *ccmd; + QXLCursor *cursor; + QXLCommand *cmd; + + update = g_malloc0(sizeof(*update) + size); + ccmd = &update->cmd; + cursor = &update->cursor; + cmd = &update->ext.cmd; + + if (c) { + ccmd->type = QXL_CURSOR_SET; + ccmd->u.set.position.x = ssd->ptr_x; + ccmd->u.set.position.y = ssd->ptr_y; + ccmd->u.set.visible = true; + ccmd->u.set.shape = (uintptr_t)cursor; + cursor->header.unique = ssd->unique++; + cursor->header.type = SPICE_CURSOR_TYPE_ALPHA; + cursor->header.width = c->width; + cursor->header.height = c->height; + cursor->header.hot_spot_x = c->hot_x; + cursor->header.hot_spot_y = c->hot_y; + cursor->data_size = size; + cursor->chunk.data_size = size; + memcpy(cursor->chunk.data, c->data, size); + } else { + ccmd->type = QXL_CURSOR_MOVE; + ccmd->u.position.x = ssd->ptr_x; + ccmd->u.position.y = ssd->ptr_y; + } + ccmd->release_info.id = (uintptr_t)(&update->ext); + + cmd->type = QXL_CMD_CURSOR; + cmd->data = (uintptr_t)ccmd; + + return update; +} + /* * Called from spice server thread context (via interface_release_resource) * We do *not* hold the global qemu mutex here, so extra care is needed @@ -483,20 +526,50 @@ static int interface_req_cmd_notification(QXLInstance *sin) } static void interface_release_resource(QXLInstance *sin, - struct QXLReleaseInfoExt ext) + struct QXLReleaseInfoExt rext) { SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); - uintptr_t id; + SimpleSpiceUpdate *update; + SimpleSpiceCursor *cursor; + QXLCommandExt *ext; dprint(2, "%s/%d:\n", __func__, ssd->qxl.id); - id = ext.info->id; - qemu_spice_destroy_update(ssd, (void*)id); + ext = (void *)(rext.info->id); + switch (ext->cmd.type) { + case QXL_CMD_DRAW: + update = container_of(ext, SimpleSpiceUpdate, ext); + qemu_spice_destroy_update(ssd, update); + break; + case QXL_CMD_CURSOR: + cursor = container_of(ext, SimpleSpiceCursor, ext); + g_free(cursor); + break; + default: + g_assert_not_reached(); + } } static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt *ext) { - dprint(3, "%s:\n", __FUNCTION__); - return false; + SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); + int ret; + + dprint(3, "%s/%d:\n", __func__, ssd->qxl.id); + + qemu_mutex_lock(&ssd->lock); + if (ssd->ptr_define) { + *ext = ssd->ptr_define->ext; + ssd->ptr_define = NULL; + ret = true; + } else if (ssd->ptr_move) { + *ext = ssd->ptr_move->ext; + ssd->ptr_move = NULL; + ret = true; + } else { + ret = false; + } + qemu_mutex_unlock(&ssd->lock); + return ret; } static int interface_req_cursor_notification(QXLInstance *sin) @@ -617,11 +690,45 @@ static void display_refresh(DisplayChangeListener *dcl) qemu_spice_display_refresh(ssd); } +static void display_mouse_set(DisplayChangeListener *dcl, + int x, int y, int on) +{ + SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); + + qemu_mutex_lock(&ssd->lock); + ssd->ptr_x = x; + ssd->ptr_y = x; + if (ssd->ptr_move) { + g_free(ssd->ptr_move); + } + ssd->ptr_move = qemu_spice_create_cursor_update(ssd, NULL); + qemu_mutex_unlock(&ssd->lock); +} + +static void display_mouse_define(DisplayChangeListener *dcl, + QEMUCursor *c) +{ + SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); + + qemu_mutex_lock(&ssd->lock); + if (ssd->ptr_move) { + g_free(ssd->ptr_move); + ssd->ptr_move = NULL; + } + if (ssd->ptr_define) { + g_free(ssd->ptr_define); + } + ssd->ptr_define = qemu_spice_create_cursor_update(ssd, c); + qemu_mutex_unlock(&ssd->lock); +} + static const DisplayChangeListenerOps display_listener_ops = { - .dpy_name = "spice", - .dpy_gfx_update = display_update, - .dpy_gfx_switch = display_switch, - .dpy_refresh = display_refresh, + .dpy_name = "spice", + .dpy_gfx_update = display_update, + .dpy_gfx_switch = display_switch, + .dpy_refresh = display_refresh, + .dpy_mouse_set = display_mouse_set, + .dpy_cursor_define = display_mouse_define, }; static void qemu_spice_display_init_one(QemuConsole *con) -- 2.7.4