diff mbox

[3/3] vnc: rich cursor support.

Message ID 1274435674-9027-4-git-send-email-kraxel@redhat.com
State New
Headers show

Commit Message

Gerd Hoffmann May 21, 2010, 9:54 a.m. UTC
Uses VNC_ENCODING_RICH_CURSOR.  Adding XCURSOR support should be
possible without much trouble.  Shouldn't be needed though as
RICH_CURSOR is a superset of XCURSOR.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 vnc.c        |   70 +++++++++++++++++++++++++++++++++++++++++++++++++++------
 vnc.h        |    8 +++++-
 vnchextile.h |    7 +++--
 3 files changed, 73 insertions(+), 12 deletions(-)
diff mbox

Patch

diff --git a/vnc.c b/vnc.c
index 1f7ad73..11ae3e5 100644
--- a/vnc.c
+++ b/vnc.c
@@ -49,6 +49,8 @@ 
 static VncDisplay *vnc_display; /* needed for info vnc */
 static DisplayChangeListener *dcl;
 
+static int vnc_cursor_define(VncState *vs);
+
 static char *addr_to_string(const char *format,
                             struct sockaddr_storage *sa,
                             socklen_t salen) {
@@ -549,12 +551,16 @@  static void vnc_dpy_resize(DisplayState *ds)
                 vnc_flush(vs);
             }
         }
+        if (vs->vd->cursor) {
+            vnc_cursor_define(vs);
+        }
         memset(vs->dirty, 0xFF, sizeof(vs->dirty));
     }
 }
 
 /* fastest code */
-static void vnc_write_pixels_copy(VncState *vs, void *pixels, int size)
+static void vnc_write_pixels_copy(VncState *vs, struct PixelFormat *pf,
+                                  void *pixels, int size)
 {
     vnc_write(vs, pixels, size);
 }
@@ -604,12 +610,12 @@  void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
     }
 }
 
-static void vnc_write_pixels_generic(VncState *vs, void *pixels1, int size)
+static void vnc_write_pixels_generic(VncState *vs, struct PixelFormat *pf,
+                                     void *pixels1, int size)
 {
     uint8_t buf[4];
-    VncDisplay *vd = vs->vd;
 
-    if (vd->server->pf.bytes_per_pixel == 4) {
+    if (pf->bytes_per_pixel == 4) {
         uint32_t *pixels = pixels1;
         int n, i;
         n = size >> 2;
@@ -617,7 +623,7 @@  static void vnc_write_pixels_generic(VncState *vs, void *pixels1, int size)
             vnc_convert_pixel(vs, buf, pixels[i]);
             vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
         }
-    } else if (vd->server->pf.bytes_per_pixel == 2) {
+    } else if (pf->bytes_per_pixel == 2) {
         uint16_t *pixels = pixels1;
         int n, i;
         n = size >> 1;
@@ -625,7 +631,7 @@  static void vnc_write_pixels_generic(VncState *vs, void *pixels1, int size)
             vnc_convert_pixel(vs, buf, pixels[i]);
             vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
         }
-    } else if (vd->server->pf.bytes_per_pixel == 1) {
+    } else if (pf->bytes_per_pixel == 1) {
         uint8_t *pixels = pixels1;
         int n, i;
         n = size;
@@ -646,7 +652,7 @@  void vnc_raw_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
 
     row = vd->server->data + y * ds_get_linesize(vs->ds) + x * ds_get_bytes_per_pixel(vs->ds);
     for (i = 0; i < h; i++) {
-        vs->write_pixels(vs, row, w * ds_get_bytes_per_pixel(vs->ds));
+        vs->write_pixels(vs, &vd->server->pf, row, w * ds_get_bytes_per_pixel(vs->ds));
         row += ds_get_linesize(vs->ds);
     }
 }
@@ -752,6 +758,50 @@  static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int
     }
 }
 
+static void vnc_mouse_set(int x, int y, int visible)
+{
+    /* can we ask the client(s) to move the pointer ??? */
+}
+
+static int vnc_cursor_define(VncState *vs)
+{
+    QEMUCursor *c = vs->vd->cursor;
+    PixelFormat pf = qemu_default_pixelformat(32);
+    int isize;
+
+    if (vnc_has_feature(vs, VNC_FEATURE_RICH_CURSOR)) {
+        vnc_write_u8(vs,  VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
+        vnc_write_u8(vs,  0);  /*  padding     */
+        vnc_write_u16(vs, 1);  /*  # of rects  */
+        vnc_framebuffer_update(vs, c->hot_x, c->hot_y, c->width, c->height,
+                               VNC_ENCODING_RICH_CURSOR);
+        isize = c->width * c->height * vs->clientds.pf.bytes_per_pixel;
+        vnc_write_pixels_generic(vs, &pf, c->data, isize);
+        vnc_write(vs, vs->vd->cursor_mask, vs->vd->cursor_msize);
+        return 0;
+    }
+    return -1;
+}
+
+static void vnc_dpy_cursor_define(QEMUCursor *c)
+{
+    VncDisplay *vd = vnc_display;
+    VncState *vs;
+
+    cursor_put(vd->cursor);
+    qemu_free(vd->cursor_mask);
+
+    vd->cursor = c;
+    cursor_get(vd->cursor);
+    vd->cursor_msize = cursor_get_mono_bpl(c) * c->height;
+    vd->cursor_mask = qemu_mallocz(vd->cursor_msize);
+    cursor_get_mono_mask(c, 0, vd->cursor_mask);
+
+    QTAILQ_FOREACH(vs, &vd->clients, next) {
+        vnc_cursor_define(vs);
+    }
+}
+
 static int find_and_clear_dirty_height(struct VncState *vs,
                                        int y, int last_x, int x)
 {
@@ -1628,6 +1678,9 @@  static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
         case VNC_ENCODING_POINTER_TYPE_CHANGE:
             vs->features |= VNC_FEATURE_POINTER_TYPE_CHANGE_MASK;
             break;
+        case VNC_ENCODING_RICH_CURSOR:
+            vs->features |= VNC_FEATURE_RICH_CURSOR_MASK;
+            break;
         case VNC_ENCODING_EXT_KEY_EVENT:
             send_ext_key_event_ack(vs);
             break;
@@ -1648,7 +1701,6 @@  static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
             break;
         }
     }
-
     check_pointer_type_change(&vs->mouse_mode_notifier);
 }
 
@@ -2294,6 +2346,8 @@  void vnc_display_init(DisplayState *ds)
     dcl->dpy_resize = vnc_dpy_resize;
     dcl->dpy_setdata = vnc_dpy_setdata;
     register_displaychangelistener(ds, dcl);
+    ds->mouse_set = vnc_mouse_set;
+    ds->cursor_define = vnc_dpy_cursor_define;
 }
 
 
diff --git a/vnc.h b/vnc.h
index 1aa71b0..0d39897 100644
--- a/vnc.h
+++ b/vnc.h
@@ -61,7 +61,7 @@  typedef struct VncState VncState;
 
 typedef int VncReadEvent(VncState *vs, uint8_t *data, size_t len);
 
-typedef void VncWritePixels(VncState *vs, void *data, int size);
+typedef void VncWritePixels(VncState *vs, struct PixelFormat *pf, void *data, int size);
 
 typedef void VncSendHextileTile(VncState *vs,
                                 int x, int y, int w, int h,
@@ -101,6 +101,10 @@  struct VncDisplay
     kbd_layout_t *kbd_layout;
     int lock_key_sync;
 
+    QEMUCursor *cursor;
+    int cursor_msize;
+    uint8_t *cursor_mask;
+
     struct VncSurface guest;   /* guest visible surface (aka ds->surface) */
     DisplaySurface *server;  /* vnc server surface */
 
@@ -273,6 +277,7 @@  enum {
 #define VNC_FEATURE_TIGHT                    4
 #define VNC_FEATURE_ZLIB                     5
 #define VNC_FEATURE_COPYRECT                 6
+#define VNC_FEATURE_RICH_CURSOR              7
 
 #define VNC_FEATURE_RESIZE_MASK              (1 << VNC_FEATURE_RESIZE)
 #define VNC_FEATURE_HEXTILE_MASK             (1 << VNC_FEATURE_HEXTILE)
@@ -281,6 +286,7 @@  enum {
 #define VNC_FEATURE_TIGHT_MASK               (1 << VNC_FEATURE_TIGHT)
 #define VNC_FEATURE_ZLIB_MASK                (1 << VNC_FEATURE_ZLIB)
 #define VNC_FEATURE_COPYRECT_MASK            (1 << VNC_FEATURE_COPYRECT)
+#define VNC_FEATURE_RICH_CURSOR_MASK         (1 << VNC_FEATURE_RICH_CURSOR)
 
 
 /* Client -> Server message IDs */
diff --git a/vnchextile.h b/vnchextile.h
index 78ed8c4..b9f9f5e 100644
--- a/vnchextile.h
+++ b/vnchextile.h
@@ -189,16 +189,17 @@  static void CONCAT(send_hextile_tile_, NAME)(VncState *vs,
     vnc_write_u8(vs, flags);
     if (n_colors < 4) {
 	if (flags & 0x02)
-	    vs->write_pixels(vs, last_bg, sizeof(pixel_t));
+	    vs->write_pixels(vs, &vd->server->pf, last_bg, sizeof(pixel_t));
 	if (flags & 0x04)
-	    vs->write_pixels(vs, last_fg, sizeof(pixel_t));
+	    vs->write_pixels(vs, &vd->server->pf, last_fg, sizeof(pixel_t));
 	if (n_subtiles) {
 	    vnc_write_u8(vs, n_subtiles);
 	    vnc_write(vs, data, n_data);
 	}
     } else {
 	for (j = 0; j < h; j++) {
-	    vs->write_pixels(vs, row, w * ds_get_bytes_per_pixel(vs->ds));
+	    vs->write_pixels(vs, &vd->server->pf, row,
+                             w * ds_get_bytes_per_pixel(vs->ds));
 	    row += ds_get_linesize(vs->ds);
 	}
     }