qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH] spice: add mouse cursor support


From: Gerd Hoffmann
Subject: [Qemu-devel] [PATCH] spice: add mouse cursor support
Date: Tue, 10 Jun 2014 14:25:10 +0200

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 <address@hidden>
---
 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)
-- 
1.8.3.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]