aboutsummaryrefslogtreecommitdiff
path: root/ui/vnc-jobs.c
diff options
context:
space:
mode:
authorDaniel P. Berrangé <berrange@redhat.com>2021-03-11 18:29:55 +0000
committerGerd Hoffmann <kraxel@redhat.com>2021-03-15 17:37:50 +0100
commit55b400497cf9c79acbb5c01abc58737bc52c081c (patch)
tree756c926530dfacb3898f51ada0712bbd6ab1bd93 /ui/vnc-jobs.c
parentadc8fce871afd30b4bf13cf5440a96a3ffb486db (diff)
ui: avoid sending framebuffer updates outside client desktop bounds
We plan framebuffer update rects based on the VNC server surface. If the client doesn't support desktop resize, then the client bounds may differ from the server surface bounds. VNC clients may become upset if we then send an update message outside the bounds of the client desktop. This takes the approach of clamping the rectangles from the worker thread immediately before sending them. This may sometimes results in sending a framebuffer update message with zero rectangles. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20210311182957.486939-3-berrange@redhat.com> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Diffstat (limited to 'ui/vnc-jobs.c')
-rw-r--r--ui/vnc-jobs.c44
1 files changed, 40 insertions, 4 deletions
diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c
index dbbfbefe56..4562bf8928 100644
--- a/ui/vnc-jobs.c
+++ b/ui/vnc-jobs.c
@@ -32,6 +32,7 @@
#include "qemu/sockets.h"
#include "qemu/main-loop.h"
#include "block/aio.h"
+#include "trace.h"
/*
* Locking:
@@ -94,6 +95,8 @@ int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h)
{
VncRectEntry *entry = g_new0(VncRectEntry, 1);
+ trace_vnc_job_add_rect(job->vs, job, x, y, w, h);
+
entry->rect.x = x;
entry->rect.y = y;
entry->rect.w = w;
@@ -190,6 +193,8 @@ static void vnc_async_encoding_start(VncState *orig, VncState *local)
local->zlib = orig->zlib;
local->hextile = orig->hextile;
local->zrle = orig->zrle;
+ local->client_width = orig->client_width;
+ local->client_height = orig->client_height;
}
static void vnc_async_encoding_end(VncState *orig, VncState *local)
@@ -202,6 +207,34 @@ static void vnc_async_encoding_end(VncState *orig, VncState *local)
orig->lossy_rect = local->lossy_rect;
}
+static bool vnc_worker_clamp_rect(VncState *vs, VncJob *job, VncRect *rect)
+{
+ trace_vnc_job_clamp_rect(vs, job, rect->x, rect->y, rect->w, rect->h);
+
+ if (rect->x >= vs->client_width) {
+ goto discard;
+ }
+ rect->w = MIN(vs->client_width - rect->x, rect->w);
+ if (rect->w == 0) {
+ goto discard;
+ }
+
+ if (rect->y >= vs->client_height) {
+ goto discard;
+ }
+ rect->h = MIN(vs->client_height - rect->y, rect->h);
+ if (rect->h == 0) {
+ goto discard;
+ }
+
+ trace_vnc_job_clamped_rect(vs, job, rect->x, rect->y, rect->w, rect->h);
+ return true;
+
+ discard:
+ trace_vnc_job_discard_rect(vs, job, rect->x, rect->y, rect->w, rect->h);
+ return false;
+}
+
static int vnc_worker_thread_loop(VncJobQueue *queue)
{
VncJob *job;
@@ -260,14 +293,17 @@ static int vnc_worker_thread_loop(VncJobQueue *queue)
goto disconnected;
}
- n = vnc_send_framebuffer_update(&vs, entry->rect.x, entry->rect.y,
- entry->rect.w, entry->rect.h);
+ if (vnc_worker_clamp_rect(&vs, job, &entry->rect)) {
+ n = vnc_send_framebuffer_update(&vs, entry->rect.x, entry->rect.y,
+ entry->rect.w, entry->rect.h);
- if (n >= 0) {
- n_rectangles += n;
+ if (n >= 0) {
+ n_rectangles += n;
+ }
}
g_free(entry);
}
+ trace_vnc_job_nrects(&vs, job, n_rectangles);
vnc_unlock_display(job->vs->vd);
/* Put n_rectangles at the beginning of the message */