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) {
}
}
-/**
- * do_info_vnc(): Show VNC server information
- *
- * Return a QDict with server information. Connected clients are returned
- * as a QList of QDicts.
- *
- * The main QDict contains the following:
- *
- * - "enabled": true or false
- * - "host": server's IP address
- * - "family": address family ("ipv4" or "ipv6")
- * - "service": server's port number
- * - "auth": authentication method
- * - "clients": a QList of all connected clients
- *
- * Clients are described by a QDict, with the following information:
- *
- * - "host": client's IP address
- * - "family": address family ("ipv4" or "ipv6")
- * - "service": client's port number
- * - "x509_dname": TLS dname (optional)
- * - "sasl_username": SASL username (optional)
- *
- * Example:
- *
- * { "enabled": true, "host": "0.0.0.0", "service": "50402", "auth": "vnc",
- * "family": "ipv4",
- * "clients": [{ "host": "127.0.0.1", "service": "50401", "family": "ipv4" }]}
- */
void do_info_vnc(Monitor *mon, QObject **ret_data)
{
if (vnc_display == NULL || vnc_display->display == NULL) {
vnc_set_bit(s->dirty[y], (x + i) / 16);
}
-static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
- int32_t encoding)
+void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
+ int32_t encoding)
{
vnc_write_u16(vs, x);
vnc_write_u16(vs, y);
buffer->offset = 0;
}
+void buffer_free(Buffer *buffer)
+{
+ qemu_free(buffer->buffer);
+ buffer->offset = 0;
+ buffer->capacity = 0;
+ buffer->buffer = NULL;
+}
+
void buffer_append(Buffer *buffer, const void *data, size_t len)
{
memcpy(buffer->buffer + buffer->offset, data, len);
buffer->offset += len;
}
+static void vnc_desktop_resize(VncState *vs)
+{
+ DisplayState *ds = vs->ds;
+
+ if (vs->csock == -1 || !vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
+ return;
+ }
+ if (vs->client_width == ds_get_width(ds) &&
+ vs->client_height == ds_get_height(ds)) {
+ return;
+ }
+ vs->client_width = ds_get_width(ds);
+ vs->client_height = ds_get_height(ds);
+ vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
+ vnc_write_u8(vs, 0);
+ vnc_write_u16(vs, 1); /* number of rects */
+ vnc_framebuffer_update(vs, 0, 0, vs->client_width, vs->client_height,
+ VNC_ENCODING_DESKTOPRESIZE);
+ vnc_flush(vs);
+}
+
static void vnc_dpy_resize(DisplayState *ds)
{
- int size_changed;
VncDisplay *vd = ds->opaque;
VncState *vs;
vd->guest.ds = qemu_mallocz(sizeof(*vd->guest.ds));
if (ds_get_bytes_per_pixel(ds) != vd->guest.ds->pf.bytes_per_pixel)
console_color_init(ds);
- size_changed = ds_get_width(ds) != vd->guest.ds->width ||
- ds_get_height(ds) != vd->guest.ds->height;
*(vd->guest.ds) = *(ds->surface);
memset(vd->guest.dirty, 0xFF, sizeof(vd->guest.dirty));
QTAILQ_FOREACH(vs, &vd->clients, next) {
vnc_colordepth(vs);
- if (size_changed) {
- if (vs->csock != -1 && vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
- vnc_write_u8(vs, 0); /* msg id */
- vnc_write_u8(vs, 0);
- vnc_write_u16(vs, 1); /* number of rects */
- vnc_framebuffer_update(vs, 0, 0, ds_get_width(ds), ds_get_height(ds),
- VNC_ENCODING_DESKTOPRESIZE);
- vnc_flush(vs);
- }
+ vnc_desktop_resize(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);
}
/* slowest but generic code. */
-static void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
+void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
{
uint8_t r, g, b;
VncDisplay *vd = vs->vd;
}
}
-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;
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;
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;
}
}
-static void send_framebuffer_update_raw(VncState *vs, int x, int y, int w, int h)
+int vnc_raw_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
{
int i;
uint8_t *row;
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);
}
+ return 1;
}
-static void hextile_enc_cord(uint8_t *ptr, int x, int y, int w, int h)
-{
- ptr[0] = ((x & 0x0F) << 4) | (y & 0x0F);
- ptr[1] = (((w - 1) & 0x0F) << 4) | ((h - 1) & 0x0F);
-}
-
-#define BPP 8
-#include "vnchextile.h"
-#undef BPP
-
-#define BPP 16
-#include "vnchextile.h"
-#undef BPP
-
-#define BPP 32
-#include "vnchextile.h"
-#undef BPP
-
-#define GENERIC
-#define BPP 8
-#include "vnchextile.h"
-#undef BPP
-#undef GENERIC
-
-#define GENERIC
-#define BPP 16
-#include "vnchextile.h"
-#undef BPP
-#undef GENERIC
-
-#define GENERIC
-#define BPP 32
-#include "vnchextile.h"
-#undef BPP
-#undef GENERIC
-
-static void send_framebuffer_update_hextile(VncState *vs, int x, int y, int w, int h)
-{
- int i, j;
- int has_fg, has_bg;
- uint8_t *last_fg, *last_bg;
- VncDisplay *vd = vs->vd;
-
- last_fg = (uint8_t *) qemu_malloc(vd->server->pf.bytes_per_pixel);
- last_bg = (uint8_t *) qemu_malloc(vd->server->pf.bytes_per_pixel);
- has_fg = has_bg = 0;
- for (j = y; j < (y + h); j += 16) {
- for (i = x; i < (x + w); i += 16) {
- vs->send_hextile_tile(vs, i, j,
- MIN(16, x + w - i), MIN(16, y + h - j),
- last_bg, last_fg, &has_bg, &has_fg);
- }
- }
- free(last_fg);
- free(last_bg);
-
-}
-
-#define ZALLOC_ALIGNMENT 16
-
-static void *zalloc(void *x, unsigned items, unsigned size)
-{
- void *p;
-
- size *= items;
- size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1);
-
- p = qemu_mallocz(size);
-
- return (p);
-}
-
-static void zfree(void *x, void *addr)
-{
- qemu_free(addr);
-}
-
-static void vnc_zlib_init(VncState *vs)
-{
- int i;
- for (i=0; i<(sizeof(vs->zlib_stream) / sizeof(z_stream)); i++)
- vs->zlib_stream[i].opaque = NULL;
-}
-
-static void vnc_zlib_start(VncState *vs)
-{
- buffer_reset(&vs->zlib);
-
- // make the output buffer be the zlib buffer, so we can compress it later
- vs->zlib_tmp = vs->output;
- vs->output = vs->zlib;
-}
-
-static int vnc_zlib_stop(VncState *vs, int stream_id)
-{
- z_streamp zstream = &vs->zlib_stream[stream_id];
- int previous_out;
-
- // switch back to normal output/zlib buffers
- vs->zlib = vs->output;
- vs->output = vs->zlib_tmp;
-
- // compress the zlib buffer
-
- // initialize the stream
- // XXX need one stream per session
- if (zstream->opaque != vs) {
- int err;
-
- VNC_DEBUG("VNC: initializing zlib stream %d\n", stream_id);
- VNC_DEBUG("VNC: opaque = %p | vs = %p\n", zstream->opaque, vs);
- zstream->zalloc = zalloc;
- zstream->zfree = zfree;
-
- err = deflateInit2(zstream, vs->tight_compression, Z_DEFLATED, MAX_WBITS,
- MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
-
- if (err != Z_OK) {
- fprintf(stderr, "VNC: error initializing zlib\n");
- return -1;
- }
-
- zstream->opaque = vs;
- }
-
- // XXX what to do if tight_compression changed in between?
-
- // reserve memory in output buffer
- buffer_reserve(&vs->output, vs->zlib.offset + 64);
-
- // set pointers
- zstream->next_in = vs->zlib.buffer;
- zstream->avail_in = vs->zlib.offset;
- zstream->next_out = vs->output.buffer + vs->output.offset;
- zstream->avail_out = vs->output.capacity - vs->output.offset;
- zstream->data_type = Z_BINARY;
- previous_out = zstream->total_out;
-
- // start encoding
- if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) {
- fprintf(stderr, "VNC: error during zlib compression\n");
- return -1;
- }
-
- vs->output.offset = vs->output.capacity - zstream->avail_out;
- return zstream->total_out - previous_out;
-}
-
-static void send_framebuffer_update_zlib(VncState *vs, int x, int y, int w, int h)
+static int send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
{
- int old_offset, new_offset, bytes_written;
-
- vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_ZLIB);
-
- // remember where we put in the follow-up size
- old_offset = vs->output.offset;
- vnc_write_s32(vs, 0);
+ int n = 0;
- // compress the stream
- vnc_zlib_start(vs);
- send_framebuffer_update_raw(vs, x, y, w, h);
- bytes_written = vnc_zlib_stop(vs, 0);
-
- if (bytes_written == -1)
- return;
-
- // hack in the size
- new_offset = vs->output.offset;
- vs->output.offset = old_offset;
- vnc_write_u32(vs, bytes_written);
- vs->output.offset = new_offset;
-}
-
-static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
-{
switch(vs->vnc_encoding) {
case VNC_ENCODING_ZLIB:
- send_framebuffer_update_zlib(vs, x, y, w, h);
+ n = vnc_zlib_send_framebuffer_update(vs, x, y, w, h);
break;
case VNC_ENCODING_HEXTILE:
vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_HEXTILE);
- send_framebuffer_update_hextile(vs, x, y, w, h);
+ n = vnc_hextile_send_framebuffer_update(vs, x, y, w, h);
+ break;
+ case VNC_ENCODING_TIGHT:
+ n = vnc_tight_send_framebuffer_update(vs, x, y, w, h);
break;
default:
vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW);
- send_framebuffer_update_raw(vs, x, y, w, h);
+ n = vnc_raw_send_framebuffer_update(vs, x, y, w, h);
break;
}
+ return n;
}
static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
{
/* send bitblit op to the vnc client */
- vnc_write_u8(vs, 0); /* msg id */
+ vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
vnc_write_u8(vs, 0);
vnc_write_u16(vs, 1); /* number of rects */
vnc_framebuffer_update(vs, dst_x, dst_y, w, h, VNC_ENCODING_COPYRECT);
}
}
+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)
{
int y;
int n_rectangles;
int saved_offset;
+ int width, height;
+ int n;
if (vs->output.offset && !vs->audio_cap && !vs->force_update)
/* kernel send buffers are full -> drop frames to throttle */
* send them to the client.
*/
n_rectangles = 0;
- vnc_write_u8(vs, 0); /* msg id */
+ vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
vnc_write_u8(vs, 0);
saved_offset = vs->output.offset;
vnc_write_u16(vs, 0);
- for (y = 0; y < vd->server->height; y++) {
+ width = MIN(vd->server->width, vs->client_width);
+ height = MIN(vd->server->height, vs->client_height);
+
+ for (y = 0; y < height; y++) {
int x;
int last_x = -1;
- for (x = 0; x < vd->server->width / 16; x++) {
+ for (x = 0; x < width / 16; x++) {
if (vnc_get_bit(vs->dirty[y], x)) {
if (last_x == -1) {
last_x = x;
} else {
if (last_x != -1) {
int h = find_and_clear_dirty_height(vs, y, last_x, x);
- send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
- n_rectangles++;
+ n = send_framebuffer_update(vs, last_x * 16, y,
+ (x - last_x) * 16, h);
+ n_rectangles += n;
}
last_x = -1;
}
}
if (last_x != -1) {
int h = find_and_clear_dirty_height(vs, y, last_x, x);
- send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
- n_rectangles++;
+ n = send_framebuffer_update(vs, last_x * 16, y,
+ (x - last_x) * 16, h);
+ n_rectangles += n;
}
}
vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
switch (cmd) {
case AUD_CNOTIFY_DISABLE:
- vnc_write_u8(vs, 255);
- vnc_write_u8(vs, 1);
- vnc_write_u16(vs, 0);
+ vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
+ vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
+ vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_END);
vnc_flush(vs);
break;
case AUD_CNOTIFY_ENABLE:
- vnc_write_u8(vs, 255);
- vnc_write_u8(vs, 1);
- vnc_write_u16(vs, 1);
+ vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
+ vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
+ vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_BEGIN);
vnc_flush(vs);
break;
}
{
VncState *vs = opaque;
- vnc_write_u8(vs, 255);
- vnc_write_u8(vs, 1);
- vnc_write_u16(vs, 2);
+ vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
+ vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
+ vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_DATA);
vnc_write_u32(vs, size);
vnc_write(vs, buf, size);
vnc_flush(vs);
{
vnc_qmp_event(vs, QEVENT_VNC_DISCONNECTED);
- if (vs->input.buffer) {
- qemu_free(vs->input.buffer);
- vs->input.buffer = NULL;
- }
- if (vs->output.buffer) {
- qemu_free(vs->output.buffer);
- vs->output.buffer = NULL;
- }
+ buffer_free(&vs->input);
+ buffer_free(&vs->output);
qobject_decref(vs->info);
+ vnc_zlib_clear(vs);
+ vnc_tight_clear(vs);
+
#ifdef CONFIG_VNC_TLS
vnc_tls_client_cleanup(vs);
#endif /* CONFIG_VNC_TLS */
dcl->idle = 1;
}
+ qemu_remove_mouse_mode_change_notifier(&vs->mouse_mode_notifier);
vnc_remove_timer(vs->vd);
- qemu_remove_led_event_handler(vs->led);
+ if (vs->vd->lock_key_sync)
+ qemu_remove_led_event_handler(vs->led);
qemu_free(vs);
}
*/
void vnc_client_write(void *opaque)
{
- long ret;
VncState *vs = opaque;
#ifdef CONFIG_VNC_SASL
if (vs->sasl.conn &&
vs->sasl.runSSF &&
- !vs->sasl.waitWriteSSF)
- ret = vnc_client_write_sasl(vs);
- else
+ !vs->sasl.waitWriteSSF) {
+ vnc_client_write_sasl(vs);
+ } else
#endif /* CONFIG_VNC_SASL */
- ret = vnc_client_write_plain(vs);
+ vnc_client_write_plain(vs);
}
void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
{
}
-static void check_pointer_type_change(VncState *vs, int absolute)
+static void check_pointer_type_change(Notifier *notifier)
{
+ VncState *vs = container_of(notifier, VncState, mouse_mode_notifier);
+ int absolute = kbd_mouse_is_absolute();
+
if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) {
- vnc_write_u8(vs, 0);
+ vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
vnc_write_u8(vs, 0);
vnc_write_u16(vs, 1);
vnc_framebuffer_update(vs, absolute, 0,
vs->last_x = x;
vs->last_y = y;
}
-
- check_pointer_type_change(vs, kbd_mouse_is_absolute());
}
static void reset_keys(VncState *vs)
break;
}
- if (keycode_is_keypad(vs->vd->kbd_layout, keycode)) {
+ if (vs->vd->lock_key_sync &&
+ keycode_is_keypad(vs->vd->kbd_layout, keycode)) {
/* If the numlock state needs to change then simulate an additional
keypress before sending this one. This will happen if the user
toggles numlock away from the VNC window.
}
}
- if ((sym >= 'A' && sym <= 'Z') || (sym >= 'a' && sym <= 'z')) {
+ if (vs->vd->lock_key_sync &&
+ ((sym >= 'A' && sym <= 'Z') || (sym >= 'a' && sym <= 'z'))) {
/* If the capslock state needs to change then simulate an additional
keypress before sending this one. This will happen if the user
toggles capslock away from the VNC window.
int x_position, int y_position,
int w, int h)
{
- if (x_position > ds_get_width(vs->ds))
- x_position = ds_get_width(vs->ds);
if (y_position > ds_get_height(vs->ds))
y_position = ds_get_height(vs->ds);
- if (x_position + w >= ds_get_width(vs->ds))
- w = ds_get_width(vs->ds) - x_position;
if (y_position + h >= ds_get_height(vs->ds))
h = ds_get_height(vs->ds) - y_position;
static void send_ext_key_event_ack(VncState *vs)
{
- vnc_write_u8(vs, 0);
+ vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
vnc_write_u8(vs, 0);
vnc_write_u16(vs, 1);
vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
static void send_ext_audio_ack(VncState *vs)
{
- vnc_write_u8(vs, 0);
+ vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
vnc_write_u8(vs, 0);
vnc_write_u16(vs, 1);
vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
int i;
unsigned int enc = 0;
- vnc_zlib_init(vs);
vs->features = 0;
vs->vnc_encoding = 0;
vs->tight_compression = 9;
vs->tight_quality = 9;
vs->absolute = -1;
+ /*
+ * Start from the end because the encodings are sent in order of preference.
+ * This way the prefered encoding (first encoding defined in the array)
+ * will be set at the end of the loop.
+ */
for (i = n_encodings - 1; i >= 0; i--) {
enc = encodings[i];
switch (enc) {
vs->features |= VNC_FEATURE_HEXTILE_MASK;
vs->vnc_encoding = enc;
break;
+ case VNC_ENCODING_TIGHT:
+ vs->features |= VNC_FEATURE_TIGHT_MASK;
+ vs->vnc_encoding = enc;
+ break;
case VNC_ENCODING_ZLIB:
vs->features |= VNC_FEATURE_ZLIB_MASK;
vs->vnc_encoding = enc;
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;
break;
}
}
-
- check_pointer_type_change(vs, kbd_mouse_is_absolute());
+ vnc_desktop_resize(vs);
+ check_pointer_type_change(&vs->mouse_mode_notifier);
}
static void set_pixel_conversion(VncState *vs)
(vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG) &&
!memcmp(&(vs->clientds.pf), &(vs->ds->surface->pf), sizeof(PixelFormat))) {
vs->write_pixels = vnc_write_pixels_copy;
- switch (vs->ds->surface->pf.bits_per_pixel) {
- case 8:
- vs->send_hextile_tile = send_hextile_tile_8;
- break;
- case 16:
- vs->send_hextile_tile = send_hextile_tile_16;
- break;
- case 32:
- vs->send_hextile_tile = send_hextile_tile_32;
- break;
- }
+ vnc_hextile_set_pixel_conversion(vs, 0);
} else {
vs->write_pixels = vnc_write_pixels_generic;
- switch (vs->ds->surface->pf.bits_per_pixel) {
- case 8:
- vs->send_hextile_tile = send_hextile_tile_generic_8;
- break;
- case 16:
- vs->send_hextile_tile = send_hextile_tile_generic_16;
- break;
- case 32:
- vs->send_hextile_tile = send_hextile_tile_generic_32;
- break;
- }
+ vnc_hextile_set_pixel_conversion(vs, 1);
}
}
vnc_write_u8(vs, vs->ds->surface->pf.rshift); /* red-shift */
vnc_write_u8(vs, vs->ds->surface->pf.gshift); /* green-shift */
vnc_write_u8(vs, vs->ds->surface->pf.bshift); /* blue-shift */
- if (vs->ds->surface->pf.bits_per_pixel == 32)
- vs->send_hextile_tile = send_hextile_tile_32;
- else if (vs->ds->surface->pf.bits_per_pixel == 16)
- vs->send_hextile_tile = send_hextile_tile_16;
- else if (vs->ds->surface->pf.bits_per_pixel == 8)
- vs->send_hextile_tile = send_hextile_tile_8;
+
+ vnc_hextile_set_pixel_conversion(vs, 0);
+
vs->clientds = *(vs->ds->surface);
vs->clientds.flags &= ~QEMU_ALLOCATED_FLAG;
vs->write_pixels = vnc_write_pixels_copy;
{
if (vnc_has_feature(vs, VNC_FEATURE_WMVI)) {
/* Sending a WMVi message to notify the client*/
- vnc_write_u8(vs, 0); /* msg id */
+ vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
vnc_write_u8(vs, 0);
vnc_write_u16(vs, 1); /* number of rects */
vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds),
}
switch (data[0]) {
- case 0:
+ case VNC_MSG_CLIENT_SET_PIXEL_FORMAT:
if (len == 1)
return 20;
read_u16(data, 12), read_u8(data, 14),
read_u8(data, 15), read_u8(data, 16));
break;
- case 2:
+ case VNC_MSG_CLIENT_SET_ENCODINGS:
if (len == 1)
return 4;
set_encodings(vs, (int32_t *)(data + 4), limit);
break;
- case 3:
+ case VNC_MSG_CLIENT_FRAMEBUFFER_UPDATE_REQUEST:
if (len == 1)
return 10;
read_u8(data, 1), read_u16(data, 2), read_u16(data, 4),
read_u16(data, 6), read_u16(data, 8));
break;
- case 4:
+ case VNC_MSG_CLIENT_KEY_EVENT:
if (len == 1)
return 8;
key_event(vs, read_u8(data, 1), read_u32(data, 4));
break;
- case 5:
+ case VNC_MSG_CLIENT_POINTER_EVENT:
if (len == 1)
return 6;
pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
break;
- case 6:
+ case VNC_MSG_CLIENT_CUT_TEXT:
if (len == 1)
return 8;
client_cut_text(vs, read_u32(data, 4), data + 8);
break;
- case 255:
+ case VNC_MSG_CLIENT_QEMU:
if (len == 1)
return 2;
switch (read_u8(data, 1)) {
- case 0:
+ case VNC_MSG_CLIENT_QEMU_EXT_KEY_EVENT:
if (len == 2)
return 12;
ext_key_event(vs, read_u16(data, 2),
read_u32(data, 4), read_u32(data, 8));
break;
- case 1:
+ case VNC_MSG_CLIENT_QEMU_AUDIO:
if (len == 2)
return 4;
switch (read_u16 (data, 2)) {
- case 0:
+ case VNC_MSG_CLIENT_QEMU_AUDIO_ENABLE:
audio_add(vs);
break;
- case 1:
+ case VNC_MSG_CLIENT_QEMU_AUDIO_DISABLE:
audio_del(vs);
break;
- case 2:
+ case VNC_MSG_CLIENT_QEMU_AUDIO_SET_FORMAT:
if (len == 4)
return 10;
switch (read_u8(data, 4)) {
char buf[1024];
int size;
- vnc_write_u16(vs, ds_get_width(vs->ds));
- vnc_write_u16(vs, ds_get_height(vs->ds));
+ vs->client_width = ds_get_width(vs->ds);
+ vs->client_height = ds_get_height(vs->ds);
+ vnc_write_u16(vs, vs->client_width);
+ vnc_write_u16(vs, vs->client_height);
pixel_format_message(vs);
vnc_flush(vs);
vnc_read_when(vs, protocol_version, 12);
reset_keys(vs);
- vs->led = qemu_add_led_event_handler(kbd_leds, vs);
+ if (vs->vd->lock_key_sync)
+ vs->led = qemu_add_led_event_handler(kbd_leds, vs);
+
+ vs->mouse_mode_notifier.notify = check_pointer_type_change;
+ qemu_add_mouse_mode_change_notifier(&vs->mouse_mode_notifier);
vnc_init_timer(vd);
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;
}
int saslErr;
#endif
int acl = 0;
+ int lock_key_sync = 1;
if (!vnc_display)
return -1;
password = 1; /* Require password auth */
} else if (strncmp(options, "reverse", 7) == 0) {
reverse = 1;
+ } else if (strncmp(options, "no-lock-key-sync", 9) == 0) {
+ lock_key_sync = 0;
#ifdef CONFIG_VNC_SASL
} else if (strncmp(options, "sasl", 4) == 0) {
sasl = 1; /* Require SASL auth */
return -1;
}
#endif
+ vs->lock_key_sync = lock_key_sync;
if (reverse) {
/* connect to viewer */