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 <kraxel@redhat.com>
This commit is contained in:
		
							parent
							
								
									2a2c4830c0
								
							
						
					
					
						commit
						5643fc012c
					
				@ -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