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 <kraxel@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
parent
fbe6d7a48d
commit
d467b679f2
70
vnc.c
70
vnc.c
@ -49,6 +49,8 @@
|
|||||||
static VncDisplay *vnc_display; /* needed for info vnc */
|
static VncDisplay *vnc_display; /* needed for info vnc */
|
||||||
static DisplayChangeListener *dcl;
|
static DisplayChangeListener *dcl;
|
||||||
|
|
||||||
|
static int vnc_cursor_define(VncState *vs);
|
||||||
|
|
||||||
static char *addr_to_string(const char *format,
|
static char *addr_to_string(const char *format,
|
||||||
struct sockaddr_storage *sa,
|
struct sockaddr_storage *sa,
|
||||||
socklen_t salen) {
|
socklen_t salen) {
|
||||||
@ -549,12 +551,16 @@ static void vnc_dpy_resize(DisplayState *ds)
|
|||||||
vnc_flush(vs);
|
vnc_flush(vs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (vs->vd->cursor) {
|
||||||
|
vnc_cursor_define(vs);
|
||||||
|
}
|
||||||
memset(vs->dirty, 0xFF, sizeof(vs->dirty));
|
memset(vs->dirty, 0xFF, sizeof(vs->dirty));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fastest code */
|
/* 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);
|
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];
|
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;
|
uint32_t *pixels = pixels1;
|
||||||
int n, i;
|
int n, i;
|
||||||
n = size >> 2;
|
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_convert_pixel(vs, buf, pixels[i]);
|
||||||
vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
|
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;
|
uint16_t *pixels = pixels1;
|
||||||
int n, i;
|
int n, i;
|
||||||
n = size >> 1;
|
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_convert_pixel(vs, buf, pixels[i]);
|
||||||
vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
|
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;
|
uint8_t *pixels = pixels1;
|
||||||
int n, i;
|
int n, i;
|
||||||
n = size;
|
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);
|
row = vd->server->data + y * ds_get_linesize(vs->ds) + x * ds_get_bytes_per_pixel(vs->ds);
|
||||||
for (i = 0; i < h; i++) {
|
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);
|
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,
|
static int find_and_clear_dirty_height(struct VncState *vs,
|
||||||
int y, int last_x, int x)
|
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:
|
case VNC_ENCODING_POINTER_TYPE_CHANGE:
|
||||||
vs->features |= VNC_FEATURE_POINTER_TYPE_CHANGE_MASK;
|
vs->features |= VNC_FEATURE_POINTER_TYPE_CHANGE_MASK;
|
||||||
break;
|
break;
|
||||||
|
case VNC_ENCODING_RICH_CURSOR:
|
||||||
|
vs->features |= VNC_FEATURE_RICH_CURSOR_MASK;
|
||||||
|
break;
|
||||||
case VNC_ENCODING_EXT_KEY_EVENT:
|
case VNC_ENCODING_EXT_KEY_EVENT:
|
||||||
send_ext_key_event_ack(vs);
|
send_ext_key_event_ack(vs);
|
||||||
break;
|
break;
|
||||||
@ -1648,7 +1701,6 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
check_pointer_type_change(&vs->mouse_mode_notifier);
|
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_resize = vnc_dpy_resize;
|
||||||
dcl->dpy_setdata = vnc_dpy_setdata;
|
dcl->dpy_setdata = vnc_dpy_setdata;
|
||||||
register_displaychangelistener(ds, dcl);
|
register_displaychangelistener(ds, dcl);
|
||||||
|
ds->mouse_set = vnc_mouse_set;
|
||||||
|
ds->cursor_define = vnc_dpy_cursor_define;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
8
vnc.h
8
vnc.h
@ -61,7 +61,7 @@ typedef struct VncState VncState;
|
|||||||
|
|
||||||
typedef int VncReadEvent(VncState *vs, uint8_t *data, size_t len);
|
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,
|
typedef void VncSendHextileTile(VncState *vs,
|
||||||
int x, int y, int w, int h,
|
int x, int y, int w, int h,
|
||||||
@ -101,6 +101,10 @@ struct VncDisplay
|
|||||||
kbd_layout_t *kbd_layout;
|
kbd_layout_t *kbd_layout;
|
||||||
int lock_key_sync;
|
int lock_key_sync;
|
||||||
|
|
||||||
|
QEMUCursor *cursor;
|
||||||
|
int cursor_msize;
|
||||||
|
uint8_t *cursor_mask;
|
||||||
|
|
||||||
struct VncSurface guest; /* guest visible surface (aka ds->surface) */
|
struct VncSurface guest; /* guest visible surface (aka ds->surface) */
|
||||||
DisplaySurface *server; /* vnc server surface */
|
DisplaySurface *server; /* vnc server surface */
|
||||||
|
|
||||||
@ -273,6 +277,7 @@ enum {
|
|||||||
#define VNC_FEATURE_TIGHT 4
|
#define VNC_FEATURE_TIGHT 4
|
||||||
#define VNC_FEATURE_ZLIB 5
|
#define VNC_FEATURE_ZLIB 5
|
||||||
#define VNC_FEATURE_COPYRECT 6
|
#define VNC_FEATURE_COPYRECT 6
|
||||||
|
#define VNC_FEATURE_RICH_CURSOR 7
|
||||||
|
|
||||||
#define VNC_FEATURE_RESIZE_MASK (1 << VNC_FEATURE_RESIZE)
|
#define VNC_FEATURE_RESIZE_MASK (1 << VNC_FEATURE_RESIZE)
|
||||||
#define VNC_FEATURE_HEXTILE_MASK (1 << VNC_FEATURE_HEXTILE)
|
#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_TIGHT_MASK (1 << VNC_FEATURE_TIGHT)
|
||||||
#define VNC_FEATURE_ZLIB_MASK (1 << VNC_FEATURE_ZLIB)
|
#define VNC_FEATURE_ZLIB_MASK (1 << VNC_FEATURE_ZLIB)
|
||||||
#define VNC_FEATURE_COPYRECT_MASK (1 << VNC_FEATURE_COPYRECT)
|
#define VNC_FEATURE_COPYRECT_MASK (1 << VNC_FEATURE_COPYRECT)
|
||||||
|
#define VNC_FEATURE_RICH_CURSOR_MASK (1 << VNC_FEATURE_RICH_CURSOR)
|
||||||
|
|
||||||
|
|
||||||
/* Client -> Server message IDs */
|
/* Client -> Server message IDs */
|
||||||
|
@ -189,16 +189,17 @@ static void CONCAT(send_hextile_tile_, NAME)(VncState *vs,
|
|||||||
vnc_write_u8(vs, flags);
|
vnc_write_u8(vs, flags);
|
||||||
if (n_colors < 4) {
|
if (n_colors < 4) {
|
||||||
if (flags & 0x02)
|
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)
|
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) {
|
if (n_subtiles) {
|
||||||
vnc_write_u8(vs, n_subtiles);
|
vnc_write_u8(vs, n_subtiles);
|
||||||
vnc_write(vs, data, n_data);
|
vnc_write(vs, data, n_data);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (j = 0; j < h; j++) {
|
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);
|
row += ds_get_linesize(vs->ds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user