Implement client side cursor rendering

pull/63/head
Andri Yngvason 2022-02-06 15:43:45 +00:00
parent 258dccd768
commit 48baf74560
4 changed files with 88 additions and 3 deletions

View File

@ -89,6 +89,7 @@ struct nvnc_client {
struct cut_text cut_text; struct cut_text cut_text;
bool is_qemu_key_ext_notified; bool is_qemu_key_ext_notified;
struct encoder* encoder; struct encoder* encoder;
uint32_t cursor_seq;
}; };
LIST_HEAD(nvnc_client_list, nvnc_client); LIST_HEAD(nvnc_client_list, nvnc_client);
@ -107,6 +108,11 @@ struct nvnc {
nvnc_client_fn new_client_fn; nvnc_client_fn new_client_fn;
nvnc_cut_text_fn cut_text_fn; nvnc_cut_text_fn cut_text_fn;
struct nvnc_display* display; struct nvnc_display* display;
struct {
struct nvnc_fb* buffer;
uint32_t x_hotspot, y_hotspot;
} cursor;
uint32_t cursor_seq;
#ifdef ENABLE_TLS #ifdef ENABLE_TLS
gnutls_certificate_credentials_t tls_creds; gnutls_certificate_credentials_t tls_creds;

View File

@ -141,3 +141,6 @@ void nvnc_display_feed_buffer(struct nvnc_display*, struct nvnc_fb*,
struct pixman_region16* damage); struct pixman_region16* damage);
void nvnc_send_cut_text(struct nvnc*, const char* text, uint32_t len); void nvnc_send_cut_text(struct nvnc*, const char* text, uint32_t len);
void nvnc_set_cursor(struct nvnc*, struct nvnc_fb*, uint16_t x_hotspot,
uint16_t y_hotspot, struct pixman_region16* damage);

View File

@ -83,6 +83,7 @@ sources = [
'src/damage-refinery.c', 'src/damage-refinery.c',
'src/murmurhash.c', 'src/murmurhash.c',
'src/encoder.c', 'src/encoder.c',
'src/cursor.c',
] ]
dependencies = [ dependencies = [

View File

@ -29,6 +29,7 @@
#include "encoder.h" #include "encoder.h"
#include "tight.h" #include "tight.h"
#include "enc-util.h" #include "enc-util.h"
#include "cursor.h"
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
@ -518,6 +519,39 @@ static void on_encoder_push_done(struct encoder* encoder, struct rcbuf* payload)
process_fb_update_requests(client); process_fb_update_requests(client);
} }
static void send_cursor_update(struct nvnc_client* client)
{
struct nvnc* server = client->server;
if (!server->cursor.buffer) {
// TODO: Empty buffer means that no cursor should be visible
return;
}
struct vec payload;
vec_init(&payload, 4096);
struct rfb_server_fb_update_msg head = {
.type = RFB_SERVER_TO_CLIENT_FRAMEBUFFER_UPDATE,
.n_rects = htons(1),
};
vec_append(&payload, &head, sizeof(head));
int rc = cursor_encode(&payload, &client->pixfmt, server->cursor.buffer,
server->cursor.x_hotspot, server->cursor.y_hotspot);
if (rc < 0) {
log_error("Failed to send cursor to client\n");
vec_destroy(&payload);
return;
}
client->cursor_seq = server->cursor_seq;
stream_send(client->net_stream, rcbuf_new(payload.data, payload.len),
NULL, NULL);
}
static void process_fb_update_requests(struct nvnc_client* client) static void process_fb_update_requests(struct nvnc_client* client)
{ {
struct nvnc* server = client->server; struct nvnc* server = client->server;
@ -528,9 +562,6 @@ static void process_fb_update_requests(struct nvnc_client* client)
if (client->net_stream->state == STREAM_STATE_CLOSED) if (client->net_stream->state == STREAM_STATE_CLOSED)
return; return;
if (!pixman_region_not_empty(&client->damage))
return;
if (client->is_updating || client->n_pending_requests == 0) if (client->is_updating || client->n_pending_requests == 0)
return; return;
@ -559,6 +590,17 @@ static void process_fb_update_requests(struct nvnc_client* client)
return; return;
} }
if (server->cursor_seq != client->cursor_seq
&& client_has_encoding(client, RFB_ENCODING_CURSOR)) {
send_cursor_update(client);
if (--client->n_pending_requests <= 0)
return;
}
if (!pixman_region_not_empty(&client->damage))
return;
DTRACE_PROBE1(neatvnc, update_fb_start, client); DTRACE_PROBE1(neatvnc, update_fb_start, client);
enum rfb_encodings encoding = choose_frame_encoding(client, fb); enum rfb_encodings encoding = choose_frame_encoding(client, fb);
@ -1533,3 +1575,36 @@ cert_alloc_failure:
#endif #endif
return -1; return -1;
} }
EXPORT
void nvnc_set_cursor(struct nvnc* self, struct nvnc_fb* fb, uint16_t x_hotspot,
uint16_t y_hotspot, struct pixman_region16* damage)
{
if (self->cursor.buffer) {
nvnc_fb_release(self->cursor.buffer);
nvnc_fb_unref(self->cursor.buffer);
}
self->cursor.buffer = fb;
if (!fb) {
self->cursor.x_hotspot = 0;
self->cursor.y_hotspot = 0;
return;
}
nvnc_fb_ref(fb);
nvnc_fb_hold(fb);
self->cursor.x_hotspot = x_hotspot;
self->cursor.y_hotspot = y_hotspot;
if (!damage || pixman_region_not_empty(damage)) {
// TODO: Hash cursors to check if they actually changed
self->cursor_seq++;
struct nvnc_client* client;
LIST_FOREACH(client, &self->clients, link)
process_fb_update_requests(client);
}
}