From d467b679f2993cb07fcc8112bfee6f6e8a40d093 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 21 May 2010 11:54:34 +0200 Subject: 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 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 8 deletions(-) (limited to 'vnc.c') 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; } -- cgit v1.2.3