From d467b679f2993cb07fcc8112bfee6f6e8a40d093 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 21 May 2010 11:54:34 +0200 Subject: [PATCH] vnc: rich cursor support. 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 Signed-off-by: Anthony Liguori --- vnc.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++------- vnc.h | 8 ++++++- vnchextile.h | 7 +++--- 3 files changed, 73 insertions(+), 12 deletions(-) diff --git a/vnc.c b/vnc.c index 1f7ad733c1..11ae3e5172 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 1aa71b0085..0d39897115 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 78ed8c4e91..b9f9f5ef89 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); } } -- 2.11.4.GIT