The extended desktop resize encoding adds support for (a) clients
sending resize requests to the server, and (b) multihead support.
This patch implements (a). All resize requests are rejected by qemu.
Qemu can't resize the framebuffer on its own, this is in the hands of
the guest, so all qemu can do is forward the request to the guest.
Should the guest actually resize the framebuffer we can notify the vnc
client later with a separate message.
This requires support in the display device. Works with virtio-gpu.
https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst#extendeddesktopsize-pseudo-encoding
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
ui/vnc.h | 2 ++
ui/vnc.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 65 insertions(+), 1 deletion(-)
diff --git a/ui/vnc.h b/ui/vnc.h
index c8d3ad9ec496..77a310947bd6 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -442,6 +442,7 @@ enum {
enum VncFeatures {
VNC_FEATURE_RESIZE,
+ VNC_FEATURE_RESIZE_EXT,
VNC_FEATURE_HEXTILE,
VNC_FEATURE_POINTER_TYPE_CHANGE,
VNC_FEATURE_WMVI,
@@ -456,6 +457,7 @@ enum VncFeatures {
};
#define VNC_FEATURE_RESIZE_MASK (1 << VNC_FEATURE_RESIZE)
+#define VNC_FEATURE_RESIZE_EXT_MASK (1 << VNC_FEATURE_RESIZE_EXT)
#define VNC_FEATURE_HEXTILE_MASK (1 << VNC_FEATURE_HEXTILE)
#define VNC_FEATURE_POINTER_TYPE_CHANGE_MASK (1 << VNC_FEATURE_POINTER_TYPE_CHANGE)
#define VNC_FEATURE_WMVI_MASK (1 << VNC_FEATURE_WMVI)
diff --git a/ui/vnc.c b/ui/vnc.c
index bdaf384f71a4..a15132faa96f 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -663,10 +663,35 @@ void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
vnc_write_s32(vs, encoding);
}
+static void vnc_desktop_resize_ext(VncState *vs, bool reject)
+{
+ vnc_lock_output(vs);
+ 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,
+ reject ? 1 : 0,
+ reject ? 3 : 0,
+ vs->client_width, vs->client_height,
+ VNC_ENCODING_DESKTOP_RESIZE_EXT);
+ vnc_write_u8(vs, 1); /* number of screens */
+ vnc_write_u8(vs, 0); /* padding */
+ vnc_write_u8(vs, 0); /* padding */
+ vnc_write_u8(vs, 0); /* padding */
+ vnc_write_u32(vs, 0); /* screen id */
+ vnc_write_u16(vs, 0); /* screen x-pos */
+ vnc_write_u16(vs, 0); /* screen y-pos */
+ vnc_write_u16(vs, vs->client_width);
+ vnc_write_u16(vs, vs->client_height);
+ vnc_write_u32(vs, 0); /* screen flags */
+ vnc_unlock_output(vs);
+ vnc_flush(vs);
+}
static void vnc_desktop_resize(VncState *vs, bool force)
{
- if (vs->ioc == NULL || !vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
+ if (vs->ioc == NULL || (!vnc_has_feature(vs, VNC_FEATURE_RESIZE) &&
+ !vnc_has_feature(vs, VNC_FEATURE_RESIZE_EXT))) {
return;
}
if (vs->client_width == pixman_image_get_width(vs->vd->server) &&
@@ -681,6 +706,12 @@ static void vnc_desktop_resize(VncState *vs, bool force)
pixman_image_get_height(vs->vd->server) >= 0);
vs->client_width = pixman_image_get_width(vs->vd->server);
vs->client_height = pixman_image_get_height(vs->vd->server);
+
+ if (vnc_has_feature(vs, VNC_FEATURE_RESIZE_EXT)) {
+ vnc_desktop_resize_ext(vs, false);
+ return;
+ }
+
vnc_lock_output(vs);
vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
vnc_write_u8(vs, 0);
@@ -2110,6 +2141,9 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
case VNC_ENCODING_DESKTOPRESIZE:
vs->features |= VNC_FEATURE_RESIZE_MASK;
break;
+ case VNC_ENCODING_DESKTOP_RESIZE_EXT:
+ vs->features |= VNC_FEATURE_RESIZE_EXT_MASK;
+ break;
case VNC_ENCODING_POINTER_TYPE_CHANGE:
vs->features |= VNC_FEATURE_POINTER_TYPE_CHANGE_MASK;
break;
@@ -2431,6 +2465,34 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
break;
}
break;
+ case VNC_MSG_CLIENT_SET_DESKTOP_SIZE:
+ {
+ size_t size;
+ uint8_t screens;
+ uint16_t width;
+ uint16_t height;
+ QemuUIInfo info;
+
+ if (len < 8) {
+ return 8;
+ }
+
+ screens = read_u8(data, 6);
+ size = 8 + screens * 16;
+ if (len < size) {
+ return size;
+ }
+
+ width = read_u16(data, 2);
+ height = read_u16(data, 4);
+ vnc_desktop_resize_ext(vs, true);
+
+ memset(&info, 0, sizeof(info));
+ info.width = width;
+ info.height = height;
+ dpy_set_ui_info(vs->vd->dcl.con, &info);
+ break;
+ }
default:
VNC_DEBUG("Msg: %d\n", data[0]);
vnc_client_error(vs);
--
2.27.0
On Thu, Dec 03, 2020 at 12:08:04PM +0100, Gerd Hoffmann wrote:
> The extended desktop resize encoding adds support for (a) clients
> sending resize requests to the server, and (b) multihead support.
>
> This patch implements (a). All resize requests are rejected by qemu.
> Qemu can't resize the framebuffer on its own, this is in the hands of
> the guest, so all qemu can do is forward the request to the guest.
> Should the guest actually resize the framebuffer we can notify the vnc
> client later with a separate message.
>
> This requires support in the display device. Works with virtio-gpu.
>
> https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst#extendeddesktopsize-pseudo-encoding
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
> ui/vnc.h | 2 ++
> ui/vnc.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> 2 files changed, 65 insertions(+), 1 deletion(-)
>
> diff --git a/ui/vnc.h b/ui/vnc.h
> index c8d3ad9ec496..77a310947bd6 100644
> --- a/ui/vnc.h
> +++ b/ui/vnc.h
> @@ -442,6 +442,7 @@ enum {
>
> enum VncFeatures {
> VNC_FEATURE_RESIZE,
> + VNC_FEATURE_RESIZE_EXT,
> VNC_FEATURE_HEXTILE,
> VNC_FEATURE_POINTER_TYPE_CHANGE,
> VNC_FEATURE_WMVI,
> @@ -456,6 +457,7 @@ enum VncFeatures {
> };
>
> #define VNC_FEATURE_RESIZE_MASK (1 << VNC_FEATURE_RESIZE)
> +#define VNC_FEATURE_RESIZE_EXT_MASK (1 << VNC_FEATURE_RESIZE_EXT)
> #define VNC_FEATURE_HEXTILE_MASK (1 << VNC_FEATURE_HEXTILE)
> #define VNC_FEATURE_POINTER_TYPE_CHANGE_MASK (1 << VNC_FEATURE_POINTER_TYPE_CHANGE)
> #define VNC_FEATURE_WMVI_MASK (1 << VNC_FEATURE_WMVI)
> diff --git a/ui/vnc.c b/ui/vnc.c
> index bdaf384f71a4..a15132faa96f 100644
> --- a/ui/vnc.c
> +++ b/ui/vnc.c
> @@ -663,10 +663,35 @@ void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
> vnc_write_s32(vs, encoding);
> }
>
> +static void vnc_desktop_resize_ext(VncState *vs, bool reject)
> +{
> + vnc_lock_output(vs);
> + 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,
> + reject ? 1 : 0,
> + reject ? 3 : 0,
> + vs->client_width, vs->client_height,
> + VNC_ENCODING_DESKTOP_RESIZE_EXT);
> + vnc_write_u8(vs, 1); /* number of screens */
> + vnc_write_u8(vs, 0); /* padding */
> + vnc_write_u8(vs, 0); /* padding */
> + vnc_write_u8(vs, 0); /* padding */
> + vnc_write_u32(vs, 0); /* screen id */
> + vnc_write_u16(vs, 0); /* screen x-pos */
> + vnc_write_u16(vs, 0); /* screen y-pos */
> + vnc_write_u16(vs, vs->client_width);
> + vnc_write_u16(vs, vs->client_height);
> + vnc_write_u32(vs, 0); /* screen flags */
> + vnc_unlock_output(vs);
> + vnc_flush(vs);
> +}
>
> static void vnc_desktop_resize(VncState *vs, bool force)
> {
> - if (vs->ioc == NULL || !vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
> + if (vs->ioc == NULL || (!vnc_has_feature(vs, VNC_FEATURE_RESIZE) &&
> + !vnc_has_feature(vs, VNC_FEATURE_RESIZE_EXT))) {
> return;
> }
> if (vs->client_width == pixman_image_get_width(vs->vd->server) &&
> @@ -681,6 +706,12 @@ static void vnc_desktop_resize(VncState *vs, bool force)
> pixman_image_get_height(vs->vd->server) >= 0);
> vs->client_width = pixman_image_get_width(vs->vd->server);
> vs->client_height = pixman_image_get_height(vs->vd->server);
> +
> + if (vnc_has_feature(vs, VNC_FEATURE_RESIZE_EXT)) {
> + vnc_desktop_resize_ext(vs, false);
> + return;
> + }
> +
> vnc_lock_output(vs);
> vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
> vnc_write_u8(vs, 0);
> @@ -2110,6 +2141,9 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
> case VNC_ENCODING_DESKTOPRESIZE:
> vs->features |= VNC_FEATURE_RESIZE_MASK;
> break;
> + case VNC_ENCODING_DESKTOP_RESIZE_EXT:
> + vs->features |= VNC_FEATURE_RESIZE_EXT_MASK;
IIUC, we shouldn't set this flag unless all current displays adapters
associated with the VNC server support the "ui_info" callbacks,
otherwise the client will think it can send resize requests
but they'll never be honoured.
> + break;
> case VNC_ENCODING_POINTER_TYPE_CHANGE:
> vs->features |= VNC_FEATURE_POINTER_TYPE_CHANGE_MASK;
> break;
> @@ -2431,6 +2465,34 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
> break;
> }
> break;
> + case VNC_MSG_CLIENT_SET_DESKTOP_SIZE:
> + {
> + size_t size;
> + uint8_t screens;
> + uint16_t width;
> + uint16_t height;
> + QemuUIInfo info;
> +
> + if (len < 8) {
> + return 8;
> + }
> +
> + screens = read_u8(data, 6);
> + size = 8 + screens * 16;
> + if (len < size) {
> + return size;
> + }
> +
> + width = read_u16(data, 2);
> + height = read_u16(data, 4);
> + vnc_desktop_resize_ext(vs, true);
> +
> + memset(&info, 0, sizeof(info));
> + info.width = width;
> + info.height = height;
> + dpy_set_ui_info(vs->vd->dcl.con, &info);
> + break;
> + }
> default:
> VNC_DEBUG("Msg: %d\n", data[0]);
> vnc_client_error(vs);
> --
> 2.27.0
>
>
Regards,
Daniel
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
Hi, > > + case VNC_ENCODING_DESKTOP_RESIZE_EXT: > > + vs->features |= VNC_FEATURE_RESIZE_EXT_MASK; > > IIUC, we shouldn't set this flag unless all current displays adapters > associated with the VNC server support the "ui_info" callbacks, > otherwise the client will think it can send resize requests > but they'll never be honoured. Well, that can happen anyway as honoring the request is in the hands of the guest and not something qemu can guarantee. So vnc clients must be able to deal with that no matter what. The spec even explicitly states that rejecting all resize requests from the client is perfectly valid behavior for a server. For tigervnc it seems to make no difference whenever the server supports extended desktop resize or not. I doubt making this conditional buys us anything ... take care, Gerd
On Fri, Dec 04, 2020 at 07:37:50AM +0100, Gerd Hoffmann wrote: > Hi, > > > > + case VNC_ENCODING_DESKTOP_RESIZE_EXT: > > > + vs->features |= VNC_FEATURE_RESIZE_EXT_MASK; > > > > IIUC, we shouldn't set this flag unless all current displays adapters > > associated with the VNC server support the "ui_info" callbacks, > > otherwise the client will think it can send resize requests > > but they'll never be honoured. > > Well, that can happen anyway as honoring the request is in the hands of > the guest and not something qemu can guarantee. So vnc clients must be > able to deal with that no matter what. The spec even explicitly states > that rejecting all resize requests from the client is perfectly valid > behavior for a server. Yes, I see we are rejecting requests unconditionally now. I still think it is valuable to clients to see a difference between something that is rejected because there is zero chance it will be honoured, vs something that we are likely honour albeit asynchronously. So I suggested we have a new error reason to indicate it is being processed async. If we don't have ui_info, then we should reject with reason 1 - Resize is administratively prohibited, but if we can probably honour it, then reject with a new reason 4 to indicate async handling. > For tigervnc it seems to make no difference whenever the server supports > extended desktop resize or not. > > I doubt making this conditional buys us anything ... If we know there is zero chance of this working, then clients can take different behaviour. For example, we can make the window non-resizable, or activate scaling of the graphics, instead of waiting for a resize. So this distinction will be useful to improve the user experiance of virt-viewer/remote-viewer IMHO. Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
Hi
On Thu, Dec 3, 2020 at 3:13 PM Gerd Hoffmann <kraxel@redhat.com> wrote:
> The extended desktop resize encoding adds support for (a) clients
> sending resize requests to the server, and (b) multihead support.
>
> This patch implements (a). All resize requests are rejected by qemu.
> Qemu can't resize the framebuffer on its own, this is in the hands of
> the guest, so all qemu can do is forward the request to the guest.
> Should the guest actually resize the framebuffer we can notify the vnc
> client later with a separate message.
>
> This requires support in the display device. Works with virtio-gpu.
>
>
> https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst#extendeddesktopsize-pseudo-encoding
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
> ui/vnc.h | 2 ++
> ui/vnc.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> 2 files changed, 65 insertions(+), 1 deletion(-)
>
> diff --git a/ui/vnc.h b/ui/vnc.h
> index c8d3ad9ec496..77a310947bd6 100644
> --- a/ui/vnc.h
> +++ b/ui/vnc.h
> @@ -442,6 +442,7 @@ enum {
>
> enum VncFeatures {
> VNC_FEATURE_RESIZE,
> + VNC_FEATURE_RESIZE_EXT,
> VNC_FEATURE_HEXTILE,
> VNC_FEATURE_POINTER_TYPE_CHANGE,
> VNC_FEATURE_WMVI,
> @@ -456,6 +457,7 @@ enum VncFeatures {
> };
>
> #define VNC_FEATURE_RESIZE_MASK (1 << VNC_FEATURE_RESIZE)
> +#define VNC_FEATURE_RESIZE_EXT_MASK (1 << VNC_FEATURE_RESIZE_EXT)
> #define VNC_FEATURE_HEXTILE_MASK (1 << VNC_FEATURE_HEXTILE)
> #define VNC_FEATURE_POINTER_TYPE_CHANGE_MASK (1 <<
> VNC_FEATURE_POINTER_TYPE_CHANGE)
> #define VNC_FEATURE_WMVI_MASK (1 << VNC_FEATURE_WMVI)
> diff --git a/ui/vnc.c b/ui/vnc.c
> index bdaf384f71a4..a15132faa96f 100644
> --- a/ui/vnc.c
> +++ b/ui/vnc.c
> @@ -663,10 +663,35 @@ void vnc_framebuffer_update(VncState *vs, int x, int
> y, int w, int h,
> vnc_write_s32(vs, encoding);
> }
>
> +static void vnc_desktop_resize_ext(VncState *vs, bool reject)
> +{
> + vnc_lock_output(vs);
> + 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,
> + reject ? 1 : 0,
1 "The client receiving this message requested a change of the screen
layout. The change may or may not have happened depending on server policy
or available resources. The status code in the *y-position* field must be
used to determine which."
ok
0 "The screen layout was changed via non-RFB means on the server."
ok
+ reject ? 3 : 0,
>
3 "Invalid screen layout"
ok
+ vs->client_width, vs->client_height,
> + VNC_ENCODING_DESKTOP_RESIZE_EXT);
> + vnc_write_u8(vs, 1); /* number of screens */
> + vnc_write_u8(vs, 0); /* padding */
> + vnc_write_u8(vs, 0); /* padding */
> + vnc_write_u8(vs, 0); /* padding */
> + vnc_write_u32(vs, 0); /* screen id */
> + vnc_write_u16(vs, 0); /* screen x-pos */
> + vnc_write_u16(vs, 0); /* screen y-pos */
> + vnc_write_u16(vs, vs->client_width);
> + vnc_write_u16(vs, vs->client_height);
> + vnc_write_u32(vs, 0); /* screen flags */
> + vnc_unlock_output(vs);
> + vnc_flush(vs);
> +}
>
> static void vnc_desktop_resize(VncState *vs, bool force)
> {
> - if (vs->ioc == NULL || !vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
> + if (vs->ioc == NULL || (!vnc_has_feature(vs, VNC_FEATURE_RESIZE) &&
> + !vnc_has_feature(vs,
> VNC_FEATURE_RESIZE_EXT))) {
> return;
> }
> if (vs->client_width == pixman_image_get_width(vs->vd->server) &&
> @@ -681,6 +706,12 @@ static void vnc_desktop_resize(VncState *vs, bool
> force)
> pixman_image_get_height(vs->vd->server) >= 0);
> vs->client_width = pixman_image_get_width(vs->vd->server);
> vs->client_height = pixman_image_get_height(vs->vd->server);
> +
> + if (vnc_has_feature(vs, VNC_FEATURE_RESIZE_EXT)) {
> + vnc_desktop_resize_ext(vs, false);
> + return;
> + }
> +
> vnc_lock_output(vs);
> vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
> vnc_write_u8(vs, 0);
> @@ -2110,6 +2141,9 @@ static void set_encodings(VncState *vs, int32_t
> *encodings, size_t n_encodings)
> case VNC_ENCODING_DESKTOPRESIZE:
> vs->features |= VNC_FEATURE_RESIZE_MASK;
> break;
> + case VNC_ENCODING_DESKTOP_RESIZE_EXT:
> + vs->features |= VNC_FEATURE_RESIZE_EXT_MASK;
> + break;
> case VNC_ENCODING_POINTER_TYPE_CHANGE:
> vs->features |= VNC_FEATURE_POINTER_TYPE_CHANGE_MASK;
> break;
> @@ -2431,6 +2465,34 @@ static int protocol_client_msg(VncState *vs,
> uint8_t *data, size_t len)
> break;
> }
> break;
> + case VNC_MSG_CLIENT_SET_DESKTOP_SIZE:
> + {
> + size_t size;
> + uint8_t screens;
> + uint16_t width;
> + uint16_t height;
> + QemuUIInfo info;
> +
> + if (len < 8) {
> + return 8;
> + }
> +
> + screens = read_u8(data, 6);
> + size = 8 + screens * 16;
> + if (len < size) {
> + return size;
> + }
>
Maybe leave a TODO note for handling multiple screens etc?
lgtm
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
+
> + width = read_u16(data, 2);
> + height = read_u16(data, 4);
> + vnc_desktop_resize_ext(vs, true);
> +
> + memset(&info, 0, sizeof(info));
> + info.width = width;
> + info.height = height;
> + dpy_set_ui_info(vs->vd->dcl.con, &info);
> + break;
> + }
> default:
> VNC_DEBUG("Msg: %d\n", data[0]);
> vnc_client_error(vs);
> --
> 2.27.0
>
>
>
--
Marc-André Lureau
On Thu, Dec 03, 2020 at 12:08:04PM +0100, Gerd Hoffmann wrote:
> The extended desktop resize encoding adds support for (a) clients
> sending resize requests to the server, and (b) multihead support.
>
> This patch implements (a). All resize requests are rejected by qemu.
> Qemu can't resize the framebuffer on its own, this is in the hands of
> the guest, so all qemu can do is forward the request to the guest.
> Should the guest actually resize the framebuffer we can notify the vnc
> client later with a separate message.
>
> This requires support in the display device. Works with virtio-gpu.
>
> https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst#extendeddesktopsize-pseudo-encoding
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
> ui/vnc.h | 2 ++
> ui/vnc.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> 2 files changed, 65 insertions(+), 1 deletion(-)
>
> diff --git a/ui/vnc.h b/ui/vnc.h
> index c8d3ad9ec496..77a310947bd6 100644
> --- a/ui/vnc.h
> +++ b/ui/vnc.h
> @@ -442,6 +442,7 @@ enum {
>
> enum VncFeatures {
> VNC_FEATURE_RESIZE,
> + VNC_FEATURE_RESIZE_EXT,
> VNC_FEATURE_HEXTILE,
> VNC_FEATURE_POINTER_TYPE_CHANGE,
> VNC_FEATURE_WMVI,
> @@ -456,6 +457,7 @@ enum VncFeatures {
> };
>
> #define VNC_FEATURE_RESIZE_MASK (1 << VNC_FEATURE_RESIZE)
> +#define VNC_FEATURE_RESIZE_EXT_MASK (1 << VNC_FEATURE_RESIZE_EXT)
> #define VNC_FEATURE_HEXTILE_MASK (1 << VNC_FEATURE_HEXTILE)
> #define VNC_FEATURE_POINTER_TYPE_CHANGE_MASK (1 << VNC_FEATURE_POINTER_TYPE_CHANGE)
> #define VNC_FEATURE_WMVI_MASK (1 << VNC_FEATURE_WMVI)
> diff --git a/ui/vnc.c b/ui/vnc.c
> index bdaf384f71a4..a15132faa96f 100644
> --- a/ui/vnc.c
> +++ b/ui/vnc.c
> @@ -663,10 +663,35 @@ void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
> vnc_write_s32(vs, encoding);
> }
>
> +static void vnc_desktop_resize_ext(VncState *vs, bool reject)
> +{
> + vnc_lock_output(vs);
> + 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,
> + reject ? 1 : 0,
> + reject ? 3 : 0,
So there are a number of reject reasons defined
Code Description
0 No error
1 Resize is administratively prohibited
2 Out of resources
3 Invalid screen layout
none of them is an ideal fit, because we are actually attempting
to honour the request, but it is asynchronous so we can't
confirm this to the client yet.
I feel like we could propose a new reason 4 to the spec, since
it explicitly allows for adding new reasons
"Request under consideration"
to make it clear this is not actually an invalid layout.
This can be useful for clients to decide how they want to
handle the failure.
> + vs->client_width, vs->client_height,
> + VNC_ENCODING_DESKTOP_RESIZE_EXT);
> + vnc_write_u8(vs, 1); /* number of screens */
> + vnc_write_u8(vs, 0); /* padding */
> + vnc_write_u8(vs, 0); /* padding */
> + vnc_write_u8(vs, 0); /* padding */
> + vnc_write_u32(vs, 0); /* screen id */
> + vnc_write_u16(vs, 0); /* screen x-pos */
> + vnc_write_u16(vs, 0); /* screen y-pos */
> + vnc_write_u16(vs, vs->client_width);
> + vnc_write_u16(vs, vs->client_height);
> + vnc_write_u32(vs, 0); /* screen flags */
> + vnc_unlock_output(vs);
> + vnc_flush(vs);
> +}
>
> static void vnc_desktop_resize(VncState *vs, bool force)
> {
> - if (vs->ioc == NULL || !vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
> + if (vs->ioc == NULL || (!vnc_has_feature(vs, VNC_FEATURE_RESIZE) &&
> + !vnc_has_feature(vs, VNC_FEATURE_RESIZE_EXT))) {
> return;
> }
> if (vs->client_width == pixman_image_get_width(vs->vd->server) &&
> @@ -681,6 +706,12 @@ static void vnc_desktop_resize(VncState *vs, bool force)
> pixman_image_get_height(vs->vd->server) >= 0);
> vs->client_width = pixman_image_get_width(vs->vd->server);
> vs->client_height = pixman_image_get_height(vs->vd->server);
> +
> + if (vnc_has_feature(vs, VNC_FEATURE_RESIZE_EXT)) {
> + vnc_desktop_resize_ext(vs, false);
> + return;
> + }
> +
> vnc_lock_output(vs);
> vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
> vnc_write_u8(vs, 0);
> @@ -2110,6 +2141,9 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
> case VNC_ENCODING_DESKTOPRESIZE:
> vs->features |= VNC_FEATURE_RESIZE_MASK;
> break;
> + case VNC_ENCODING_DESKTOP_RESIZE_EXT:
> + vs->features |= VNC_FEATURE_RESIZE_EXT_MASK;
> + break;
> case VNC_ENCODING_POINTER_TYPE_CHANGE:
> vs->features |= VNC_FEATURE_POINTER_TYPE_CHANGE_MASK;
> break;
> @@ -2431,6 +2465,34 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
> break;
> }
> break;
> + case VNC_MSG_CLIENT_SET_DESKTOP_SIZE:
> + {
> + size_t size;
> + uint8_t screens;
> + uint16_t width;
> + uint16_t height;
> + QemuUIInfo info;
> +
> + if (len < 8) {
> + return 8;
> + }
> +
> + screens = read_u8(data, 6);
> + size = 8 + screens * 16;
> + if (len < size) {
> + return size;
> + }
> +
> + width = read_u16(data, 2);
> + height = read_u16(data, 4);
> + vnc_desktop_resize_ext(vs, true);
I think it is worth a comment to say why we are rejecting the request...
> +
> + memset(&info, 0, sizeof(info));
> + info.width = width;
> + info.height = height;
> + dpy_set_ui_info(vs->vd->dcl.con, &info);
...while still (attempting to) honour it.
> + break;
> + }
> default:
> VNC_DEBUG("Msg: %d\n", data[0]);
> vnc_client_error(vs);
Regards,
Daniel
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
© 2016 - 2025 Red Hat, Inc.