Add ExtendedDesktopSize support to VNC module
This commit is contained in:
parent
79c8ed8579
commit
3293370faf
493
vnc/vnc.c
493
vnc/vnc.c
@ -16,6 +16,14 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
*
|
||||||
* libvnc
|
* libvnc
|
||||||
|
*
|
||||||
|
* The message definitions used in this source file can be found mostly
|
||||||
|
* in RFC6143 - "The Remote Framebuffer Protocol".
|
||||||
|
*
|
||||||
|
* The ExtendedDesktopSize encoding is reserved in RFC6143, but not
|
||||||
|
* documented there. It is documented by the RFB protocol community
|
||||||
|
* wiki currently held at https://github.com/rfbproto/rfbroto. This is
|
||||||
|
* referred to below as the "RFB community wiki"
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined(HAVE_CONFIG_H)
|
#if defined(HAVE_CONFIG_H)
|
||||||
@ -26,6 +34,7 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "trans.h"
|
#include "trans.h"
|
||||||
#include "ssl_calls.h"
|
#include "ssl_calls.h"
|
||||||
|
#include "xrdp_client_info.h"
|
||||||
|
|
||||||
#define LLOG_LEVEL 1
|
#define LLOG_LEVEL 1
|
||||||
#define LLOGLN(_level, _args) \
|
#define LLOGLN(_level, _args) \
|
||||||
@ -41,6 +50,13 @@
|
|||||||
|
|
||||||
#define AS_LOG_MESSAGE log_message
|
#define AS_LOG_MESSAGE log_message
|
||||||
|
|
||||||
|
/* Encodings and pseudo-encodings from RFC6143 */
|
||||||
|
#define ENC_RAW 0
|
||||||
|
#define ENC_COPY_RECT 1
|
||||||
|
#define ENC_CURSOR (unsigned int)-239
|
||||||
|
#define ENC_DESKTOP_SIZE (unsigned int)-223
|
||||||
|
#define ENC_EXTENDED_DESKTOP_SIZE (unsigned int)-308
|
||||||
|
|
||||||
static int
|
static int
|
||||||
lib_mod_process_message(struct vnc *v, struct stream *s);
|
lib_mod_process_message(struct vnc *v, struct stream *s);
|
||||||
|
|
||||||
@ -256,6 +272,356 @@ lib_process_channel_data(struct vnc *v, int chanid, int flags, int size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
static void
|
||||||
|
log_debug_screen_layout(const char *source,
|
||||||
|
const struct vnc_screen_layout *layout)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
char text[256];
|
||||||
|
size_t pos;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
pos = 0;
|
||||||
|
res = g_snprintf(text, sizeof(text) - pos,
|
||||||
|
"Layout from %s (#screens=%d) :",
|
||||||
|
source, layout->count);
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (res > 0 && res < sizeof(text) - pos && i < layout->count)
|
||||||
|
{
|
||||||
|
pos += res;
|
||||||
|
res = g_snprintf(&text[pos], sizeof(text) - pos,
|
||||||
|
" %d:(%dx%d+%d+%d)",
|
||||||
|
layout->s[i].id,
|
||||||
|
layout->s[i].width, layout->s[i].height,
|
||||||
|
layout->s[i].x, layout->s[i].y);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
log_message(LOG_LEVEL_DEBUG, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Compares two vnc_screen structures, returning a value which can
|
||||||
|
* also be used for sorting on id
|
||||||
|
*/
|
||||||
|
static int cmp_vnc_screen(const struct vnc_screen *a,
|
||||||
|
const struct vnc_screen *b)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
if (a->id != b->id)
|
||||||
|
{
|
||||||
|
result = a->id - b->id;
|
||||||
|
}
|
||||||
|
else if (a->x != b->x)
|
||||||
|
{
|
||||||
|
result = a->x - b->x;
|
||||||
|
}
|
||||||
|
else if (a->y != b->y)
|
||||||
|
{
|
||||||
|
result = a->y - b->y;
|
||||||
|
}
|
||||||
|
else if (a->width != b->width)
|
||||||
|
{
|
||||||
|
result = a->width - b->width;
|
||||||
|
}
|
||||||
|
else if (a->height != b->height)
|
||||||
|
{
|
||||||
|
result = a->height - b->height;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Compares two vnc_screen_layout structures
|
||||||
|
*
|
||||||
|
* Result can only be used for equality testing
|
||||||
|
*/
|
||||||
|
static int cmp_vnc_screen_layout(const struct vnc_screen_layout *a,
|
||||||
|
const struct vnc_screen_layout *b)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
int result = b->count - a->count;
|
||||||
|
|
||||||
|
for (i = 0 ; result == 0 && i < a->count ; ++i)
|
||||||
|
{
|
||||||
|
result = cmp_vnc_screen(&a->s[i], &b->s[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Reads an extended desktop size rectangle from the VNC server
|
||||||
|
*
|
||||||
|
* Returned structure is in increasing ID order, rather than order on-the-wire
|
||||||
|
*
|
||||||
|
* On a successful return, layout->s has been allocated, and must be
|
||||||
|
* freed after use.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
read_extended_desktop_size_rect(struct vnc *v,
|
||||||
|
struct vnc_screen_layout *layout)
|
||||||
|
{
|
||||||
|
struct stream *s;
|
||||||
|
int error;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
layout->count = 0;
|
||||||
|
|
||||||
|
make_stream(s);
|
||||||
|
init_stream(s, 8192);
|
||||||
|
|
||||||
|
/* Read in the current screen config */
|
||||||
|
error = trans_force_read_s(v->trans, s, 4);
|
||||||
|
if (error == 0)
|
||||||
|
{
|
||||||
|
/* Get the number of screens */
|
||||||
|
in_uint8(s, layout->count);
|
||||||
|
in_uint8s(s, 3);
|
||||||
|
|
||||||
|
error = trans_force_read_s(v->trans, s, 16 * layout->count);
|
||||||
|
if (error == 0)
|
||||||
|
{
|
||||||
|
layout->s = g_new(struct vnc_screen, layout->count);
|
||||||
|
if (layout->s == NULL)
|
||||||
|
{
|
||||||
|
log_message(LOG_LEVEL_ERROR,
|
||||||
|
"VNC : Can't alloc for %d screens", layout->count);
|
||||||
|
layout->count = 0;
|
||||||
|
error = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i = 0 ; i < layout->count ; ++i)
|
||||||
|
{
|
||||||
|
in_uint32_be(s, layout->s[i].id);
|
||||||
|
in_uint16_be(s, layout->s[i].x);
|
||||||
|
in_uint16_be(s, layout->s[i].y);
|
||||||
|
in_uint16_be(s, layout->s[i].width);
|
||||||
|
in_uint16_be(s, layout->s[i].height);
|
||||||
|
in_uint32_be(s, layout->s[i].flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sort monitors in increasing ID order */
|
||||||
|
qsort(layout->s, layout->count, sizeof(layout->s[0]),
|
||||||
|
(int (*)(const void *, const void *))cmp_vnc_screen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free_stream(s);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Check to see if a SetDesktopSize message should be sent, based on the
|
||||||
|
* current Xvnc geometry and screen layout
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
set_desktop_size_is_needed(struct vnc *v, int vnc_width, int vnc_height,
|
||||||
|
const struct vnc_screen_layout *vnc_layout)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
if (v->mod_width != vnc_width || v->mod_height != vnc_height)
|
||||||
|
{
|
||||||
|
log_message(LOG_LEVEL_DEBUG, "VNC SetDesktopSize needed "
|
||||||
|
"for size change from (%d,%d) to (%d,%d)",
|
||||||
|
vnc_width, vnc_height, v->mod_width, v->mod_height);
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
else if (cmp_vnc_screen_layout(vnc_layout, &v->screen_layout) != 0)
|
||||||
|
{
|
||||||
|
log_message(LOG_LEVEL_DEBUG, "VNC SetDesktopSize needed "
|
||||||
|
"for changed screen layouts");
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log_message(LOG_LEVEL_DEBUG, "VNC SetDesktopSize not needed");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Send a SetDesktopSize message based on the initial RDP parameters
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
send_set_desktop_size_msg(struct vnc *v)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
struct stream *s;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
make_stream(s);
|
||||||
|
init_stream(s, 8192);
|
||||||
|
out_uint8(s, 251);
|
||||||
|
out_uint8(s, 0);
|
||||||
|
out_uint16_be(s, v->mod_width);
|
||||||
|
out_uint16_be(s, v->mod_height);
|
||||||
|
|
||||||
|
out_uint8(s, v->screen_layout.count);
|
||||||
|
out_uint8(s, 0);
|
||||||
|
for (i = 0 ; i < v->screen_layout.count ; ++i)
|
||||||
|
{
|
||||||
|
out_uint32_be(s, v->screen_layout.s[i].id);
|
||||||
|
out_uint16_be(s, v->screen_layout.s[i].x);
|
||||||
|
out_uint16_be(s, v->screen_layout.s[i].y);
|
||||||
|
out_uint16_be(s, v->screen_layout.s[i].width);
|
||||||
|
out_uint16_be(s, v->screen_layout.s[i].height);
|
||||||
|
out_uint32_be(s, v->screen_layout.s[i].flags);
|
||||||
|
}
|
||||||
|
s_mark_end(s);
|
||||||
|
log_message(LOG_LEVEL_DEBUG, "VNC Sending SetDesktopSize");
|
||||||
|
error = lib_send_copy(v, s);
|
||||||
|
free_stream(s);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Check to resize the attached client
|
||||||
|
*
|
||||||
|
* The resizing of multi-screen layouts isn't supported. If
|
||||||
|
* we end up in this situation we currently throw an error, resulting in
|
||||||
|
* a disconnect.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
check_to_resize_client(struct vnc *v, int width, int height,
|
||||||
|
const struct vnc_screen_layout *layout)
|
||||||
|
{
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
if (width != v->mod_width || height != v->mod_height ||
|
||||||
|
cmp_vnc_screen_layout(&v->screen_layout, layout) != 0)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* we don't have the capability to cope with a rearrangement
|
||||||
|
* of a multi-screen layout.
|
||||||
|
*/
|
||||||
|
if (layout->count != 1 || v->screen_layout.count != 1)
|
||||||
|
{
|
||||||
|
char text[256];
|
||||||
|
g_sprintf(text, "VNC Resize to %d screen(s) from %d screen(s) "
|
||||||
|
"not implemented",
|
||||||
|
v->screen_layout.count, layout->count);
|
||||||
|
v->server_msg(v, text, 0);
|
||||||
|
|
||||||
|
/* Dump some useful info, in case we get here when we don't
|
||||||
|
* need to */
|
||||||
|
log_debug_screen_layout("OldLayout", layout);
|
||||||
|
log_debug_screen_layout("NewLayout", layout);
|
||||||
|
error = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
v->mod_width = width;
|
||||||
|
v->mod_height = height;
|
||||||
|
v->screen_layout.s[0] = layout->s[0];
|
||||||
|
error = v->server_reset(v, width, height, v->mod_bpp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Process an ExtendedDesktopSize message
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
process_extended_desktop_size(struct vnc *v, int x, int y, int cx, int cy,
|
||||||
|
const struct vnc_screen_layout *layout)
|
||||||
|
{
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
switch (x)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
/* Spec says to treat unknown values as a zero */
|
||||||
|
if (x != 0)
|
||||||
|
{
|
||||||
|
log_message(LOG_LEVEL_ERROR,
|
||||||
|
"VNC got ExtendedDesktopSize rectangle type %d", x);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v->first_framebuffer_update)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* This is a response to our first framebuffer update
|
||||||
|
* request. At this point, we want to impose our will
|
||||||
|
* on the client. After that, the server may request
|
||||||
|
* size changes of its own.
|
||||||
|
*/
|
||||||
|
log_message(LOG_LEVEL_DEBUG,
|
||||||
|
"VNC got first ExtendedDesktopSize rectangle "
|
||||||
|
"x=%d, y=%d, cx=%d, cy=%d", x, y, cx, cy);
|
||||||
|
log_debug_screen_layout("Xvnc", layout);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we've only got one screen, and the other side has
|
||||||
|
* only got one screen, we will preserve their screen
|
||||||
|
* ID and any flags. This may prevent us sending
|
||||||
|
* an unwanted SetDesktopSize message if the screen
|
||||||
|
* dimensions are a match. We can't do this with more than
|
||||||
|
* one screen, as we have no way to map different IDs
|
||||||
|
*/
|
||||||
|
if (layout->count == 1 && v->screen_layout.count == 1)
|
||||||
|
{
|
||||||
|
log_message(LOG_LEVEL_DEBUG, "VNC "
|
||||||
|
"setting screen id to %d from server",
|
||||||
|
layout->s[0].id);
|
||||||
|
|
||||||
|
v->screen_layout.s[0].id = layout->s[0].id;
|
||||||
|
v->screen_layout.s[0].flags = layout->s[0].flags;
|
||||||
|
}
|
||||||
|
if (set_desktop_size_is_needed(v, cx, cy, layout))
|
||||||
|
{
|
||||||
|
error = send_set_desktop_size_msg(v);
|
||||||
|
v->set_desktop_size_in_progress = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (v->set_desktop_size_in_progress)
|
||||||
|
{
|
||||||
|
/* Ignore this, until the X server has responded */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Could be a response to another framebuffer update request,
|
||||||
|
* or a server-side change (i.e. with xrandr)
|
||||||
|
*/
|
||||||
|
error = check_to_resize_client(v, cx, cy, layout);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: /* Response to a SetDesktopSize message from us */
|
||||||
|
v->set_desktop_size_in_progress = 0;
|
||||||
|
if (y == 0)
|
||||||
|
{
|
||||||
|
log_message(LOG_LEVEL_DEBUG,
|
||||||
|
"VNC SetDesktopSize was successful");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log_message(LOG_LEVEL_ERROR,
|
||||||
|
"VNC SetDesktopSize failed and returned %d", y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
/*
|
||||||
|
* Another client has resized or re-arranged the screen
|
||||||
|
*/
|
||||||
|
error = check_to_resize_client(v, cx, cy, layout);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
int
|
int
|
||||||
lib_mod_event(struct vnc *v, int msg, long param1, long param2,
|
lib_mod_event(struct vnc *v, int msg, long param1, long param2,
|
||||||
long param3, long param4)
|
long param3, long param4)
|
||||||
@ -385,7 +751,7 @@ lib_mod_event(struct vnc *v, int msg, long param1, long param2,
|
|||||||
/* FramebufferUpdateRequest */
|
/* FramebufferUpdateRequest */
|
||||||
init_stream(s, 8192);
|
init_stream(s, 8192);
|
||||||
out_uint8(s, 3);
|
out_uint8(s, 3);
|
||||||
out_uint8(s, 0);
|
out_uint8(s, 0); /* incremental == 0 : Full contents */
|
||||||
x = (param1 >> 16) & 0xffff;
|
x = (param1 >> 16) & 0xffff;
|
||||||
out_uint16_be(s, x);
|
out_uint16_be(s, x);
|
||||||
y = param1 & 0xffff;
|
y = param1 & 0xffff;
|
||||||
@ -615,6 +981,8 @@ lib_framebuffer_update(struct vnc *v)
|
|||||||
int need_size;
|
int need_size;
|
||||||
struct stream *s;
|
struct stream *s;
|
||||||
struct stream *pixel_s;
|
struct stream *pixel_s;
|
||||||
|
int extended_desktop_size_msg_received = 0;
|
||||||
|
struct vnc_screen_layout layout = { 0 };
|
||||||
|
|
||||||
num_recs = 0;
|
num_recs = 0;
|
||||||
Bpp = (v->mod_bpp + 7) / 8;
|
Bpp = (v->mod_bpp + 7) / 8;
|
||||||
@ -655,7 +1023,7 @@ lib_framebuffer_update(struct vnc *v)
|
|||||||
in_uint16_be(s, cy);
|
in_uint16_be(s, cy);
|
||||||
in_uint32_be(s, encoding);
|
in_uint32_be(s, encoding);
|
||||||
|
|
||||||
if (encoding == 0) /* raw */
|
if (encoding == ENC_RAW)
|
||||||
{
|
{
|
||||||
need_size = cx * cy * Bpp;
|
need_size = cx * cy * Bpp;
|
||||||
init_stream(pixel_s, need_size);
|
init_stream(pixel_s, need_size);
|
||||||
@ -666,7 +1034,7 @@ lib_framebuffer_update(struct vnc *v)
|
|||||||
error = v->server_paint_rect(v, x, y, cx, cy, pixel_s->data, cx, cy, 0, 0);
|
error = v->server_paint_rect(v, x, y, cx, cy, pixel_s->data, cx, cy, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (encoding == 1) /* copy rect */
|
else if (encoding == ENC_COPY_RECT)
|
||||||
{
|
{
|
||||||
init_stream(s, 8192);
|
init_stream(s, 8192);
|
||||||
error = trans_force_read_s(v->trans, s, 4);
|
error = trans_force_read_s(v->trans, s, 4);
|
||||||
@ -678,7 +1046,7 @@ lib_framebuffer_update(struct vnc *v)
|
|||||||
error = v->server_screen_blt(v, x, y, cx, cy, srcx, srcy);
|
error = v->server_screen_blt(v, x, y, cx, cy, srcx, srcy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (encoding == 0xffffff11) /* cursor */
|
else if (encoding == ENC_CURSOR)
|
||||||
{
|
{
|
||||||
g_memset(cursor_data, 0, 32 * (32 * 3));
|
g_memset(cursor_data, 0, 32 * (32 * 3));
|
||||||
g_memset(cursor_mask, 0, 32 * (32 / 8));
|
g_memset(cursor_mask, 0, 32 * (32 / 8));
|
||||||
@ -723,12 +1091,24 @@ lib_framebuffer_update(struct vnc *v)
|
|||||||
error = v->server_set_cursor(v, x, y, cursor_data, cursor_mask);
|
error = v->server_set_cursor(v, x, y, cursor_data, cursor_mask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (encoding == 0xffffff21) /* desktop size */
|
else if (encoding == ENC_DESKTOP_SIZE)
|
||||||
{
|
{
|
||||||
|
/* Only received for non-resizeable desktops */
|
||||||
v->mod_width = cx;
|
v->mod_width = cx;
|
||||||
v->mod_height = cy;
|
v->mod_height = cy;
|
||||||
error = v->server_reset(v, cx, cy, v->mod_bpp);
|
error = v->server_reset(v, cx, cy, v->mod_bpp);
|
||||||
}
|
}
|
||||||
|
else if (encoding == ENC_EXTENDED_DESKTOP_SIZE)
|
||||||
|
{
|
||||||
|
extended_desktop_size_msg_received = 1;
|
||||||
|
error = read_extended_desktop_size_rect(v, &layout);
|
||||||
|
if (error == 0)
|
||||||
|
{
|
||||||
|
error = process_extended_desktop_size(v, x, y, cx, cy,
|
||||||
|
&layout);
|
||||||
|
g_free(layout.s);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_sprintf(text, "VNC error in lib_framebuffer_update encoding = %8.8x",
|
g_sprintf(text, "VNC error in lib_framebuffer_update encoding = %8.8x",
|
||||||
@ -743,6 +1123,20 @@ lib_framebuffer_update(struct vnc *v)
|
|||||||
error = v->server_end_update(v);
|
error = v->server_end_update(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (v->first_framebuffer_update)
|
||||||
|
{
|
||||||
|
v->first_framebuffer_update = 0;
|
||||||
|
if (v->resizeable_mode && !extended_desktop_size_msg_received)
|
||||||
|
{
|
||||||
|
log_message(LOG_LEVEL_ERROR, "Resizeable mode requested, "
|
||||||
|
"but X server does not support it");
|
||||||
|
if (error == 0)
|
||||||
|
{
|
||||||
|
error = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
{
|
{
|
||||||
if (v->suppress_output == 0)
|
if (v->suppress_output == 0)
|
||||||
@ -750,7 +1144,7 @@ lib_framebuffer_update(struct vnc *v)
|
|||||||
/* FramebufferUpdateRequest */
|
/* FramebufferUpdateRequest */
|
||||||
init_stream(s, 8192);
|
init_stream(s, 8192);
|
||||||
out_uint8(s, 3);
|
out_uint8(s, 3);
|
||||||
out_uint8(s, 1);
|
out_uint8(s, 1); /* incremental == 1 : Changes only */
|
||||||
out_uint16_be(s, 0);
|
out_uint16_be(s, 0);
|
||||||
out_uint16_be(s, 0);
|
out_uint16_be(s, 0);
|
||||||
out_uint16_be(s, v->mod_width);
|
out_uint16_be(s, v->mod_width);
|
||||||
@ -1188,8 +1582,14 @@ lib_mod_connect(struct vnc *v)
|
|||||||
|
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
{
|
{
|
||||||
in_uint16_be(s, v->mod_width);
|
/* In resizeable mode, we're not interested at this stage how
|
||||||
in_uint16_be(s, v->mod_height);
|
* big the X server is, as we're going to go for the size set
|
||||||
|
* by the "client_info" param */
|
||||||
|
if (!v->resizeable_mode)
|
||||||
|
{
|
||||||
|
in_uint16_be(s, v->mod_width);
|
||||||
|
in_uint16_be(s, v->mod_height);
|
||||||
|
}
|
||||||
init_stream(pixel_format, 8192);
|
init_stream(pixel_format, 8192);
|
||||||
v->server_msg(v, "VNC receiving pixel format", 0);
|
v->server_msg(v, "VNC receiving pixel format", 0);
|
||||||
error = trans_force_read_s(v->trans, pixel_format, 16);
|
error = trans_force_read_s(v->trans, pixel_format, 16);
|
||||||
@ -1329,11 +1729,20 @@ lib_mod_connect(struct vnc *v)
|
|||||||
init_stream(s, 8192);
|
init_stream(s, 8192);
|
||||||
out_uint8(s, 2);
|
out_uint8(s, 2);
|
||||||
out_uint8(s, 0);
|
out_uint8(s, 0);
|
||||||
out_uint16_be(s, 4);
|
out_uint16_be(s, 4); /* Number of encodings following */
|
||||||
out_uint32_be(s, 0); /* raw */
|
out_uint32_be(s, ENC_RAW);
|
||||||
out_uint32_be(s, 1); /* copy rect */
|
out_uint32_be(s, ENC_COPY_RECT);
|
||||||
out_uint32_be(s, 0xffffff11); /* cursor */
|
out_uint32_be(s, ENC_CURSOR);
|
||||||
out_uint32_be(s, 0xffffff21); /* desktop size */
|
if (v->resizeable_mode)
|
||||||
|
{
|
||||||
|
v->server_msg(v, "VNC with ExtendedDesktopSize pseudo-encoding", 0);
|
||||||
|
out_uint32_be(s, ENC_EXTENDED_DESKTOP_SIZE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
v->server_msg(v, "VNC with DesktopSize pseudo-encoding", 0);
|
||||||
|
out_uint32_be(s, ENC_DESKTOP_SIZE);
|
||||||
|
}
|
||||||
v->server_msg(v, "VNC sending encodings", 0);
|
v->server_msg(v, "VNC sending encodings", 0);
|
||||||
s_mark_end(s);
|
s_mark_end(s);
|
||||||
error = trans_force_write_s(v->trans, s);
|
error = trans_force_write_s(v->trans, s);
|
||||||
@ -1344,6 +1753,7 @@ lib_mod_connect(struct vnc *v)
|
|||||||
error = v->server_reset(v, v->mod_width, v->mod_height, v->mod_bpp);
|
error = v->server_reset(v, v->mod_width, v->mod_height, v->mod_bpp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v->first_framebuffer_update = 1;
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
{
|
{
|
||||||
if (v->suppress_output == 0)
|
if (v->suppress_output == 0)
|
||||||
@ -1351,7 +1761,7 @@ lib_mod_connect(struct vnc *v)
|
|||||||
/* FramebufferUpdateRequest */
|
/* FramebufferUpdateRequest */
|
||||||
init_stream(s, 8192);
|
init_stream(s, 8192);
|
||||||
out_uint8(s, 3);
|
out_uint8(s, 3);
|
||||||
out_uint8(s, 0);
|
out_uint8(s, 0); /* incremental == 0 : Full contents */
|
||||||
out_uint16_be(s, 0);
|
out_uint16_be(s, 0);
|
||||||
out_uint16_be(s, 0);
|
out_uint16_be(s, 0);
|
||||||
out_uint16_be(s, v->mod_width);
|
out_uint16_be(s, v->mod_width);
|
||||||
@ -1430,6 +1840,8 @@ lib_mod_end(struct vnc *v)
|
|||||||
int
|
int
|
||||||
lib_mod_set_param(struct vnc *v, const char *name, const char *value)
|
lib_mod_set_param(struct vnc *v, const char *name, const char *value)
|
||||||
{
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
if (g_strcasecmp(name, "username") == 0)
|
if (g_strcasecmp(name, "username") == 0)
|
||||||
{
|
{
|
||||||
g_strncpy(v->username, value, 255);
|
g_strncpy(v->username, value, 255);
|
||||||
@ -1459,6 +1871,56 @@ lib_mod_set_param(struct vnc *v, const char *name, const char *value)
|
|||||||
v->got_guid = 1;
|
v->got_guid = 1;
|
||||||
g_memcpy(v->guid, value, 16);
|
g_memcpy(v->guid, value, 16);
|
||||||
}
|
}
|
||||||
|
else if (g_strcasecmp(name, "code") == 0)
|
||||||
|
{
|
||||||
|
v->resizeable_mode = (g_atoi(value) == 1);
|
||||||
|
}
|
||||||
|
else if (g_strcasecmp(name, "client_info") == 0)
|
||||||
|
{
|
||||||
|
const struct xrdp_client_info *client_info =
|
||||||
|
(const struct xrdp_client_info *) value;
|
||||||
|
|
||||||
|
g_free(v->screen_layout.s);
|
||||||
|
|
||||||
|
/* The RDP client (width,height) is requested for the X server
|
||||||
|
* later on if we're in resizeable mode. If we're not, these
|
||||||
|
* settings will be overwritten later by the ServerInit
|
||||||
|
* message from the X server */
|
||||||
|
v->mod_width = client_info->width;
|
||||||
|
v->mod_height = client_info->height;
|
||||||
|
|
||||||
|
/* Save info needed for resizeable support */
|
||||||
|
if (!client_info->multimon || client_info->monitorCount < 1)
|
||||||
|
{
|
||||||
|
v->screen_layout.count = 1;
|
||||||
|
v->screen_layout.s = g_new(struct vnc_screen, 1);
|
||||||
|
v->screen_layout.s[0].id = 0;
|
||||||
|
v->screen_layout.s[0].x = 0;
|
||||||
|
v->screen_layout.s[0].y = 0;
|
||||||
|
v->screen_layout.s[0].width = client_info->width;
|
||||||
|
v->screen_layout.s[0].height = client_info->height;
|
||||||
|
v->screen_layout.s[0].flags = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
v->screen_layout.count = client_info->monitorCount;
|
||||||
|
v->screen_layout.s = g_new(struct vnc_screen,
|
||||||
|
v->screen_layout.count);
|
||||||
|
for (i = 0 ; i < client_info->monitorCount ; ++i)
|
||||||
|
{
|
||||||
|
v->screen_layout.s[i].id = i;
|
||||||
|
v->screen_layout.s[i].x = client_info->minfo[i].left;
|
||||||
|
v->screen_layout.s[i].y = client_info->minfo[i].top;
|
||||||
|
v->screen_layout.s[i].width = client_info->minfo[i].right -
|
||||||
|
client_info->minfo[i].left + 1;
|
||||||
|
v->screen_layout.s[i].height = client_info->minfo[i].bottom -
|
||||||
|
client_info->minfo[i].top + 1;
|
||||||
|
v->screen_layout.s[i].flags = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log_debug_screen_layout("client_info", &v->screen_layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1526,7 +1988,7 @@ lib_mod_suppress_output(struct vnc *v, int suppress,
|
|||||||
make_stream(s);
|
make_stream(s);
|
||||||
init_stream(s, 8192);
|
init_stream(s, 8192);
|
||||||
out_uint8(s, 3);
|
out_uint8(s, 3);
|
||||||
out_uint8(s, 0);
|
out_uint8(s, 0); /* incremental == 0 : Full contents */
|
||||||
out_uint16_be(s, 0);
|
out_uint16_be(s, 0);
|
||||||
out_uint16_be(s, 0);
|
out_uint16_be(s, 0);
|
||||||
out_uint16_be(s, v->mod_width);
|
out_uint16_be(s, v->mod_width);
|
||||||
@ -1575,5 +2037,6 @@ mod_exit(tintptr handle)
|
|||||||
}
|
}
|
||||||
trans_delete(v->trans);
|
trans_delete(v->trans);
|
||||||
g_free(v);
|
g_free(v);
|
||||||
|
g_free(v->screen_layout.s);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
23
vnc/vnc.h
23
vnc/vnc.h
@ -26,6 +26,24 @@
|
|||||||
|
|
||||||
#define CURRENT_MOD_VER 4
|
#define CURRENT_MOD_VER 4
|
||||||
|
|
||||||
|
/* Screen used for ExtendedDesktopSize / Set DesktopSize */
|
||||||
|
struct vnc_screen
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct vnc_screen_layout
|
||||||
|
{
|
||||||
|
unsigned int count;
|
||||||
|
/* For comparison, screens are sorted in increasing order of ID */
|
||||||
|
struct vnc_screen *s;
|
||||||
|
};
|
||||||
|
|
||||||
struct vnc
|
struct vnc
|
||||||
{
|
{
|
||||||
int size; /* size of this struct */
|
int size; /* size of this struct */
|
||||||
@ -120,4 +138,9 @@ struct vnc
|
|||||||
int got_guid;
|
int got_guid;
|
||||||
tui8 guid[16];
|
tui8 guid[16];
|
||||||
int suppress_output;
|
int suppress_output;
|
||||||
|
/* Resizeable support */
|
||||||
|
int resizeable_mode; /* true for resizeable mode, false for traditional */
|
||||||
|
struct vnc_screen_layout screen_layout;
|
||||||
|
int first_framebuffer_update; /* Identifies the first framebuffer_update */
|
||||||
|
int set_desktop_size_in_progress; /* Waiting for SetDesktopSize response */
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user