spice: add mouse cursor support
qxl-render: add sanity check -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJTmt8FAAoJEEy22O7T6HE4Ib0P/27T8x8pqrz1deIx+9Bsgrmb 94/qXM137T/WUjqpFL9WJgyqTENtNcW7HXbW/W3SI7yazTso4kCT85Qav5rwKqjt n7NNtwtoxBMz9jYfl6HuDgIUaPGHBxS/DtLzFyHICIYoF/LSj5dXKUvRvEYdvr/M 7qIYvJU71Ck540tYvZ+qUj6/cCHS4IDArBndpMuiWY8c/CQXwAsSKVOnBtdzm3V6 GPEPBT3+OaEFMqDBBlGMV6aDsCm7cpYCiqMGrYf6x64SZ4/JC2HhopS3VPTJR1Zg ugCb4x6GmkIHa/dE+45T1EZ6BFjgh2YuRnrIE7xold1i2FcajnBlDLMtcrh6rSOz f1PBL/KJW5RlhdRabFB8w6kuWAP9VPYDqT4ELGb5J373QN0ChtdYD5ZbvzukEMpq vRBaesuKFK1uyCkQ8xWZ938WTWZf21dliIeva+li+PE94a4SrdxAVsTEeGhfA5B4 tAE6Gg26EEgBEAf8FZdaJCf+17LxuVGm83bqCumhn2WT1SOmv+RZivbbxlsAmWDl 3IF2pHacGxbpGcUxDRdvIzoSsKwLeazbUvLXEoaKsEDGFqLeorXwhpmvelsE+xbN 011JEwTGdMWxYbxPWKTmAymS5PX5JT6BQudZ7XUlU/n8VQWMHZTpgSwHJfonXEaf 1wkY5iTie95D+n/Jd2yi =N8b6 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/spice/tags/pull-spice-20140613-1' into staging spice: add mouse cursor support qxl-render: add sanity check # gpg: Signature made Fri 13 Jun 2014 12:22:45 BST using RSA key ID D3E87138 # gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" # gpg: aka "Gerd Hoffmann <gerd@kraxel.org>" # gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>" * remotes/spice/tags/pull-spice-20140613-1: qxl-render: add sanity check spice: add mouse cursor support Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
592fb17691
@ -138,6 +138,12 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
|
|||||||
if (qemu_spice_rect_is_empty(qxl->dirty+i)) {
|
if (qemu_spice_rect_is_empty(qxl->dirty+i)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (qxl->dirty[i].left > qxl->dirty[i].right ||
|
||||||
|
qxl->dirty[i].top > qxl->dirty[i].bottom ||
|
||||||
|
qxl->dirty[i].right > qxl->guest_primary.surface.width ||
|
||||||
|
qxl->dirty[i].bottom > qxl->guest_primary.surface.height) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
qxl_blit(qxl, qxl->dirty+i);
|
qxl_blit(qxl, qxl->dirty+i);
|
||||||
dpy_gfx_update(vga->con,
|
dpy_gfx_update(vga->con,
|
||||||
qxl->dirty[i].left, qxl->dirty[i].top,
|
qxl->dirty[i].left, qxl->dirty[i].top,
|
||||||
|
@ -710,7 +710,11 @@ static void interface_release_resource(QXLInstance *sin,
|
|||||||
|
|
||||||
if (ext.group_id == MEMSLOT_GROUP_HOST) {
|
if (ext.group_id == MEMSLOT_GROUP_HOST) {
|
||||||
/* host group -> vga mode update request */
|
/* 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,6 +69,7 @@ QXLCookie *qxl_cookie_new(int type, uint64_t io);
|
|||||||
|
|
||||||
typedef struct SimpleSpiceDisplay SimpleSpiceDisplay;
|
typedef struct SimpleSpiceDisplay SimpleSpiceDisplay;
|
||||||
typedef struct SimpleSpiceUpdate SimpleSpiceUpdate;
|
typedef struct SimpleSpiceUpdate SimpleSpiceUpdate;
|
||||||
|
typedef struct SimpleSpiceCursor SimpleSpiceCursor;
|
||||||
|
|
||||||
struct SimpleSpiceDisplay {
|
struct SimpleSpiceDisplay {
|
||||||
DisplaySurface *ds;
|
DisplaySurface *ds;
|
||||||
@ -92,6 +93,13 @@ struct SimpleSpiceDisplay {
|
|||||||
*/
|
*/
|
||||||
QemuMutex lock;
|
QemuMutex lock;
|
||||||
QTAILQ_HEAD(, SimpleSpiceUpdate) updates;
|
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;
|
QEMUCursor *cursor;
|
||||||
int mouse_x, mouse_y;
|
int mouse_x, mouse_y;
|
||||||
};
|
};
|
||||||
@ -104,6 +112,12 @@ struct SimpleSpiceUpdate {
|
|||||||
QTAILQ_ENTRY(SimpleSpiceUpdate) next;
|
QTAILQ_ENTRY(SimpleSpiceUpdate) next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SimpleSpiceCursor {
|
||||||
|
QXLCursorCmd cmd;
|
||||||
|
QXLCommandExt ext;
|
||||||
|
QXLCursor cursor;
|
||||||
|
};
|
||||||
|
|
||||||
int qemu_spice_rect_is_empty(const QXLRect* r);
|
int qemu_spice_rect_is_empty(const QXLRect* r);
|
||||||
void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r);
|
void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r);
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ static void qemu_spice_create_one_update(SimpleSpiceDisplay *ssd,
|
|||||||
drawable->bbox = *rect;
|
drawable->bbox = *rect;
|
||||||
drawable->clip.type = SPICE_CLIP_TYPE_NONE;
|
drawable->clip.type = SPICE_CLIP_TYPE_NONE;
|
||||||
drawable->effect = QXL_EFFECT_OPAQUE;
|
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->type = QXL_DRAW_COPY;
|
||||||
drawable->surfaces_dest[0] = -1;
|
drawable->surfaces_dest[0] = -1;
|
||||||
drawable->surfaces_dest[1] = -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));
|
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)
|
* Called from spice server thread context (via interface_release_resource)
|
||||||
* We do *not* hold the global qemu mutex here, so extra care is needed
|
* 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,
|
static void interface_release_resource(QXLInstance *sin,
|
||||||
struct QXLReleaseInfoExt ext)
|
struct QXLReleaseInfoExt rext)
|
||||||
{
|
{
|
||||||
SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
|
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);
|
dprint(2, "%s/%d:\n", __func__, ssd->qxl.id);
|
||||||
id = ext.info->id;
|
ext = (void *)(rext.info->id);
|
||||||
qemu_spice_destroy_update(ssd, (void*)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)
|
static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt *ext)
|
||||||
{
|
{
|
||||||
dprint(3, "%s:\n", __FUNCTION__);
|
SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
|
||||||
return false;
|
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)
|
static int interface_req_cursor_notification(QXLInstance *sin)
|
||||||
@ -617,11 +690,45 @@ static void display_refresh(DisplayChangeListener *dcl)
|
|||||||
qemu_spice_display_refresh(ssd);
|
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 = {
|
static const DisplayChangeListenerOps display_listener_ops = {
|
||||||
.dpy_name = "spice",
|
.dpy_name = "spice",
|
||||||
.dpy_gfx_update = display_update,
|
.dpy_gfx_update = display_update,
|
||||||
.dpy_gfx_switch = display_switch,
|
.dpy_gfx_switch = display_switch,
|
||||||
.dpy_refresh = display_refresh,
|
.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)
|
static void qemu_spice_display_init_one(QemuConsole *con)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user