Refactoring resizing into state machine.

- Fixes MSTSC resizing (with RFX as well).
- Queue system so that resizes are processed when XRDP and the X server
are ready, not immediately.
- Deletes and recreates the encoder (RFX fix)
- Introduces a dynamic_monitor_description struct that is used for the
queue system.
- Fix some lines previously introduced by the original resizing code to
be 80 chars long, as is the standard for XRDP.
This commit is contained in:
Christopher Pitstick 2022-03-15 00:45:26 -04:00
parent 7711978713
commit 6f461aa54c
5 changed files with 470 additions and 199 deletions

View File

@ -147,8 +147,12 @@ xrdp_wm_get_wait_objs(struct xrdp_wm *self, tbus *robjs, int *rc,
tbus *wobjs, int *wc, int *timeout); tbus *wobjs, int *wc, int *timeout);
int int
xrdp_wm_check_wait_objs(struct xrdp_wm *self); xrdp_wm_check_wait_objs(struct xrdp_wm *self);
const char *
xrdp_wm_login_state_to_str(enum wm_login_state login_state);
int int
xrdp_wm_set_login_state(struct xrdp_wm *self, enum wm_login_state login_state); xrdp_wm_set_login_state(struct xrdp_wm *self, enum wm_login_state login_state);
int
xrdp_wm_can_resize(struct xrdp_wm *self);
void void
xrdp_wm_mod_connect_done(struct xrdp_wm *self, int status); xrdp_wm_mod_connect_done(struct xrdp_wm *self, int status);
@ -397,18 +401,12 @@ xrdp_bitmap_compress(char *in_data, int width, int height,
/* xrdp_mm.c */ /* xrdp_mm.c */
struct dynamic_monitor_layout struct display_control_monitor_layout_data
{ {
int flags; struct display_size_description description;
int left; enum display_resize_state state;
int top; int last_state_update_timestamp;
int width; int start_time;
int height;
int physical_width;
int physical_height;
int orientation;
int desktop_scale_factor;
int device_scale_factor;
}; };
int int

View File

@ -43,6 +43,7 @@
#include "xrdp_encoder.h" #include "xrdp_encoder.h"
#include "xrdp_sockets.h" #include "xrdp_sockets.h"
#include <limits.h>
/* Forward declarations */ /* Forward declarations */
@ -65,6 +66,8 @@ struct xrdp_mm *
xrdp_mm_create(struct xrdp_wm *owner) xrdp_mm_create(struct xrdp_wm *owner)
{ {
struct xrdp_mm *self; struct xrdp_mm *self;
char buf[1024];
int pid;
self = (struct xrdp_mm *)g_malloc(sizeof(struct xrdp_mm), 1); self = (struct xrdp_mm *)g_malloc(sizeof(struct xrdp_mm), 1);
self->wm = owner; self->wm = owner;
@ -72,6 +75,14 @@ xrdp_mm_create(struct xrdp_wm *owner)
self->login_names->auto_free = 1; self->login_names->auto_free = 1;
self->login_values = list_create(); self->login_values = list_create();
self->login_values->auto_free = 1; self->login_values->auto_free = 1;
self->resize_queue = list_create();
self->resize_queue->auto_free = 1;
pid = g_getpid();
/* setup wait objects for signalling */
g_snprintf(buf, sizeof(buf), "xrdp_%8.8x_resize_ready", pid);
self->resize_ready = g_create_wait_obj(buf);
self->resize_data = NULL;
LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_mm_create: bpp %d mcs_connection_type %d " LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_mm_create: bpp %d mcs_connection_type %d "
"jpeg_codec_id %d v3_codec_id %d rfx_codec_id %d " "jpeg_codec_id %d v3_codec_id %d rfx_codec_id %d "
@ -165,6 +176,9 @@ xrdp_mm_delete(struct xrdp_mm *self)
self->sesman_trans = 0; self->sesman_trans = 0;
list_delete(self->login_names); list_delete(self->login_names);
list_delete(self->login_values); list_delete(self->login_values);
list_delete(self->resize_queue);
g_free(self->resize_data);
g_delete_wait_obj(self->resize_ready);
g_free(self); g_free(self);
} }
@ -969,7 +983,8 @@ dynamic_monitor_open_response(intptr_t id, int chan_id, int creation_status)
struct stream *s; struct stream *s;
int bytes; int bytes;
LOG_DEVEL(LOG_LEVEL_TRACE, "dynamic_monitor_open_response: chan_id %d creation_status 0x%8.8x", chan_id, creation_status); LOG_DEVEL(LOG_LEVEL_TRACE, "dynamic_monitor_open_response: chan_id %d "
"creation_status 0x%8.8x", chan_id, creation_status);
if (creation_status != 0) if (creation_status != 0)
{ {
LOG(LOG_LEVEL_ERROR, "dynamic_monitor_open_response: error"); LOG(LOG_LEVEL_ERROR, "dynamic_monitor_open_response: error");
@ -1031,152 +1046,24 @@ sync_dynamic_monitor_data(struct xrdp_wm *wm,
MAXIMUM_MONITOR_SIZE); MAXIMUM_MONITOR_SIZE);
} }
/******************************************************************************/ int
static int advance_resize_state_machine(struct xrdp_mm *mm,
process_dynamic_monitor_description(struct xrdp_wm *wm, enum display_resize_state new_state)
struct display_size_description *description)
{ {
int error = 0; struct display_control_monitor_layout_data *description = mm->resize_data;
struct xrdp_mm *mm = wm->mm; LOG_DEVEL(LOG_LEVEL_INFO,
struct xrdp_mod *module = mm->mod; "advance_resize_state_machine:"
" Processing resize to: %d x %d."
LOG_DEVEL(LOG_LEVEL_TRACE, "process_dynamic_monitor_description:"); " Advancing state from %s to %s."
" Previous state took %d MS.",
if (wm->client_info->suppress_output == 1) description->description.session_width,
{ description->description.session_height,
LOG(LOG_LEVEL_ERROR, XRDP_DISPLAY_RESIZE_STATE_TO_STR(description->state),
"process_dynamic_monitor_description:" XRDP_DISPLAY_RESIZE_STATE_TO_STR(new_state),
" Not allowing resize. Suppress output is active."); g_time3() - description->last_state_update_timestamp);
return 0; description->state = new_state;
} description->last_state_update_timestamp = g_time3();
if (description == NULL) g_set_wait_obj(mm->resize_ready);
{
LOG_DEVEL(LOG_LEVEL_ERROR,
"process_dynamic_monitor_description:"
" description is null.");
return 0;
}
if (description->session_width <= 0 || description->session_height <= 0)
{
LOG(LOG_LEVEL_ERROR,
"process_dynamic_monitor_description: Not allowing resize due to"
" invalid dimensions (w: %d x h: %d)",
description->session_width, description->session_height);
return 0;
}
if (description->session_width
== wm->client_info->display_sizes.session_width
&& description->session_height
== wm->client_info->display_sizes.session_height)
{
LOG(LOG_LEVEL_WARNING, "process_dynamic_monitor_description:"
" Not resizing. Already this size. (w: %d x h: %d)",
description->session_width,
description->session_height);
sync_dynamic_monitor_data(wm, description);
return 0;
}
// TODO: Unify this logic with server_reset
error = libxrdp_reset(wm->session,
description->session_width,
description->session_height,
wm->screen->bpp);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_ERROR,
"process_dynamic_monitor_description:"
" libxrdp_reset failed %d", error);
return error;
}
/* reset cache */
error = xrdp_cache_reset(wm->cache, wm->client_info);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_ERROR,
"process_dynamic_monitor_description: xrdp_cache_reset"
" failed %d", error);
return error;
}
/* load some stuff */
error = xrdp_wm_load_static_colors_plus(wm, 0);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_ERROR, "process_dynamic_monitor_description:"
" xrdp_wm_load_static_colors_plus failed %d", error);
return error;
}
error = xrdp_wm_load_static_pointers(wm);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_ERROR, "process_dynamic_monitor_description:"
" xrdp_wm_load_static_pointers failed %d", error);
return error;
}
/* resize the main window */
error = xrdp_bitmap_resize(wm->screen,
description->session_width,
description->session_height);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_ERROR, "process_dynamic_monitor_description:"
" xrdp_bitmap_resize failed %d", error);
return error;
}
/* redraw */
error = xrdp_bitmap_invalidate(wm->screen, 0);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_ERROR,
"process_dynamic_monitor_description:"
" xrdp_bitmap_invalidate failed %d", error);
return error;
}
if (module != 0)
{
error = module->mod_server_version_message(module);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_ERROR, "process_dynamic_monitor_description:"
" mod_server_version_message failed %d", error);
return error;
}
error = module->mod_server_monitor_resize(
module,
description->session_width,
description->session_height);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_ERROR, "process_dynamic_monitor_description:"
"mod_server_monitor_resize failed %d", error);
return error;
}
error = module->mod_server_monitor_full_invalidate(
module,
description->session_width,
description->session_height);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_ERROR, "process_dynamic_monitor_description:"
"mod_server_monitor_full_invalidate failed %d", error);
return error;
}
}
// Need to recreate the encoder for connections that use it.
if (mm->encoder != NULL)
{
xrdp_encoder_delete(mm->encoder);
mm->encoder = NULL;
}
if (mm->encoder == NULL)
{
mm->encoder = xrdp_encoder_create(mm);
}
sync_dynamic_monitor_data(wm, description);
return 0; return 0;
} }
@ -1192,10 +1079,19 @@ dynamic_monitor_data(intptr_t id, int chan_id, char *data, int bytes)
struct xrdp_process *pro; struct xrdp_process *pro;
struct xrdp_wm *wm; struct xrdp_wm *wm;
int monitor_layout_size; int monitor_layout_size;
struct display_size_description *display_size_data;
LOG_DEVEL(LOG_LEVEL_TRACE, "dynamic_monitor_data:"); LOG_DEVEL(LOG_LEVEL_TRACE, "dynamic_monitor_data:");
pro = (struct xrdp_process *) id; pro = (struct xrdp_process *) id;
wm = pro->wm; wm = pro->wm;
if (wm->client_info->suppress_output == 1)
{
LOG(LOG_LEVEL_INFO, "dynamic_monitor_data: Not allowing resize."
" Suppress output is active.");
return error;
}
g_memset(&ls, 0, sizeof(ls)); g_memset(&ls, 0, sizeof(ls));
ls.data = data; ls.data = data;
ls.p = ls.data; ls.p = ls.data;
@ -1204,16 +1100,33 @@ dynamic_monitor_data(intptr_t id, int chan_id, char *data, int bytes)
s = &ls; s = &ls;
in_uint32_le(s, msg_type); in_uint32_le(s, msg_type);
in_uint32_le(s, msg_length); in_uint32_le(s, msg_length);
LOG(LOG_LEVEL_DEBUG, "dynamic_monitor_data: msg_type %d msg_length %d", LOG_DEVEL(LOG_LEVEL_DEBUG,
msg_type, msg_length); "dynamic_monitor_data: msg_type %d msg_length %d",
msg_type, msg_length);
if (msg_type != DISPLAYCONTROL_PDU_TYPE_MONITOR_LAYOUT) if (msg_type != DISPLAYCONTROL_PDU_TYPE_MONITOR_LAYOUT
&& msg_length >= 0)
{ {
// Unsupported message types
switch (msg_type)
{
case DISPLAYCONTROL_PDU_TYPE_CAPS:
LOG(LOG_LEVEL_ERROR, "dynamic_monitor_data: Received"
" DISPLAYCONTROL_PDU_TYPE_CAPS. Per MS-RDPEDISP 2.2.2.1,"
" this is a server-to-client message, client should never"
" send this. Ignoring message");
break;
default:
LOG(LOG_LEVEL_ERROR, "dynamic_monitor_data: Received neither"
" nor DISPLAYCONTROL_PDU_TYPE_CAPS. Ignoring message.");
break;
}
return 0; return 0;
} }
in_uint32_le(s, monitor_layout_size); in_uint32_le(s, monitor_layout_size);
if (monitor_layout_size != 40) if (monitor_layout_size != 40)
{ {
/* 2.2.2.2 DISPLAYCONTROL_MONITOR_LAYOUT_PDU */
LOG(LOG_LEVEL_ERROR, "dynamic_monitor_data: monitor_layout_size" LOG(LOG_LEVEL_ERROR, "dynamic_monitor_data: monitor_layout_size"
" is %d. Per spec ([MS-RDPEDISP] 2.2.2.2" " is %d. Per spec ([MS-RDPEDISP] 2.2.2.2"
" DISPLAYCONTROL_MONITOR_LAYOUT_PDU) it must be 40.", " DISPLAYCONTROL_MONITOR_LAYOUT_PDU) it must be 40.",
@ -1221,19 +1134,300 @@ dynamic_monitor_data(intptr_t id, int chan_id, char *data, int bytes)
return 1; return 1;
} }
struct display_size_description *description = display_size_data = (struct display_size_description *)
(struct display_size_description *) g_malloc(sizeof(struct display_size_description), 1);
g_malloc(sizeof(struct display_size_description), 1); if (!display_size_data)
error = libxrdp_process_monitor_stream(s, description, 1);
if (error == 0)
{ {
error = process_dynamic_monitor_description(wm, description); return 1;
} }
g_free(description); error = libxrdp_process_monitor_stream(s, display_size_data, 1);
if (error)
{
LOG(LOG_LEVEL_ERROR, "dynamic_monitor_data:"
" libxrdp_process_monitor_stream"
" failed with error %d.", error);
g_free(display_size_data);
return error;
}
list_add_item(wm->mm->resize_queue, (tintptr)display_size_data);
g_set_wait_obj(wm->mm->resize_ready);
LOG(LOG_LEVEL_DEBUG, "dynamic_monitor_data:"
" received width %d, received height %d.", display_size_data->session_width, display_size_data->session_height);
return 0;
}
/******************************************************************************/
static int
advance_error(int error,
struct xrdp_mm *mm)
{
advance_resize_state_machine(mm, WMRZ_ERROR);
return error; return error;
} }
/******************************************************************************/
static int
process_display_control_monitor_layout_data(struct xrdp_wm *wm)
{
int error = 0;
struct xrdp_mm *mm;
struct xrdp_mod *module;
LOG_DEVEL(LOG_LEVEL_TRACE, "process_display_control_monitor_layout_data:");
if (wm == NULL)
{
return 1;
}
mm = wm->mm;
if (mm == NULL)
{
return 1;
}
module = mm->mod;
if (module == NULL)
{
return 1;
}
if (!xrdp_wm_can_resize(wm))
{
return 0;
}
struct display_control_monitor_layout_data *description
= mm->resize_data;
const unsigned int desc_width = description->description.session_width;
const unsigned int desc_height = description->description.session_height;
switch (description->state)
{
case WMRZ_ENCODER_DELETE:
// Disable the encoder until the resize is complete.
if (mm->encoder != NULL)
{
xrdp_encoder_delete(mm->encoder);
mm->encoder = NULL;
}
advance_resize_state_machine(mm, WMRZ_SERVER_MONITOR_RESIZE);
break;
case WMRZ_SERVER_MONITOR_RESIZE:
error = module->mod_server_monitor_resize(
module, desc_width, desc_height);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_INFO,
"process_display_control_monitor_layout_data:"
" mod_server_monitor_resize failed %d", error);
return advance_error(error, mm);
}
advance_resize_state_machine(mm, WMRZ_SERVER_VERSION_MESSAGE);
break;
case WMRZ_SERVER_VERSION_MESSAGE:
error = module->mod_server_version_message(module);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_INFO,
"process_display_control_monitor_layout_data:"
" mod_server_version_message failed %d", error);
return advance_error(error, mm);
}
advance_resize_state_machine(mm, WMRZ_XRDP_CORE_RESIZE);
break;
case WMRZ_XRDP_CORE_RESIZE:
// TODO: Unify this logic with server_reset
error = libxrdp_reset(
wm->session, desc_width, desc_height, wm->screen->bpp);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_INFO,
"process_display_control_monitor_layout_data:"
" libxrdp_reset failed %d", error);
return advance_error(error, mm);
}
/* reset cache */
error = xrdp_cache_reset(wm->cache, wm->client_info);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_INFO,
"process_display_control_monitor_layout_data:"
" xrdp_cache_reset failed %d", error);
return advance_error(error, mm);
}
/* load some stuff */
error = xrdp_wm_load_static_colors_plus(wm, 0);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_INFO,
"process_display_control_monitor_layout_data:"
" xrdp_wm_load_static_colors_plus failed %d", error);
return advance_error(error, mm);
}
error = xrdp_wm_load_static_pointers(wm);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_INFO,
"process_display_control_monitor_layout_data:"
" xrdp_wm_load_static_pointers failed %d", error);
return advance_error(error, mm);
}
/* resize the main window */
error = xrdp_bitmap_resize(
wm->screen, desc_width, desc_height);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_INFO,
"process_display_control_monitor_layout_data:"
" xrdp_bitmap_resize failed %d", error);
return advance_error(error, mm);
}
sync_dynamic_monitor_data(wm, &(description->description));
advance_resize_state_machine(mm, WMRZ_ENCODER_CREATE);
break;
case WMRZ_ENCODER_CREATE:
if (mm->encoder == NULL)
{
mm->encoder = xrdp_encoder_create(mm);
}
advance_resize_state_machine(mm, WMRZ_SERVER_INVALIDATE);
break;
case WMRZ_SERVER_INVALIDATE:
/* redraw */
error = xrdp_bitmap_invalidate(wm->screen, 0);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_INFO,
"process_display_control_monitor_layout_data:"
" xrdp_bitmap_invalidate failed %d", error);
return advance_error(error, mm);
}
if (module != 0)
{
// Ack all frames to speed up resize.
module->mod_frame_ack(module, 0, INT_MAX);
}
advance_resize_state_machine(mm, WMRZ_COMPLETE);
break;
default:
break;
}
return 0;
}
/******************************************************************************/
static int
dynamic_monitor_process_queue(struct xrdp_mm *self)
{
LOG_DEVEL(LOG_LEVEL_TRACE, "dynamic_monitor_process_queue:");
if (self == 0)
{
return 0;
}
struct xrdp_wm *wm = self->wm;
if (!xrdp_wm_can_resize(wm))
{
return 0;
}
if (self->resize_data == NULL)
{
if (self->resize_queue->count <= 0)
{
LOG_DEVEL(LOG_LEVEL_DEBUG, "Resize queue is empty.");
return 0;
}
LOG_DEVEL(LOG_LEVEL_DEBUG, "dynamic_monitor_process_queue: Queue is"
" not empty. Filling out description.");
const struct display_size_description *queue_head =
(struct display_size_description *)
list_get_item(self->resize_queue, 0);
const int invalid_dimensions = queue_head->session_width <= 0
|| queue_head->session_height <= 0;
if (invalid_dimensions)
{
LOG(LOG_LEVEL_DEBUG,
"dynamic_monitor_process_queue: Not allowing"
" resize due to invalid dimensions (w: %d x h: %d)",
queue_head->session_width,
queue_head->session_height);
}
const struct display_size_description *current_size
= &wm->client_info->display_sizes;
const int already_this_size = queue_head->session_width
== current_size->session_width
&& queue_head->session_height
== current_size->session_height;
if (already_this_size)
{
LOG(LOG_LEVEL_DEBUG,
"dynamic_monitor_process_queue: Not resizing."
" Already this size. (w: %d x h: %d)",
queue_head->session_width,
queue_head->session_height);
}
if (!invalid_dimensions && !already_this_size)
{
const int LAYOUT_DATA_SIZE =
sizeof(struct display_control_monitor_layout_data);
self->resize_data = (struct display_control_monitor_layout_data *)
g_malloc(LAYOUT_DATA_SIZE, 1);
g_memcpy(&(self->resize_data->description), queue_head,
sizeof(struct display_size_description));
const int time = g_time3();
self->resize_data->start_time = time;
self->resize_data->last_state_update_timestamp = time;
advance_resize_state_machine(self, WMRZ_ENCODER_DELETE);
}
else
{
g_set_wait_obj(self->resize_ready);
}
list_remove_item(self->resize_queue, 0);
return 0;
}
else
{
LOG_DEVEL(LOG_LEVEL_DEBUG, "dynamic_monitor_process_queue:"
" Resize data is not null.");
}
if (self->resize_data->state == WMRZ_COMPLETE)
{
LOG(LOG_LEVEL_INFO, "dynamic_monitor_process_queue: Clearing"
" completed resize (w: %d x h: %d). It took %d milliseconds.",
self->resize_data->description.session_width,
self->resize_data->description.session_height,
g_time3() - self->resize_data->start_time);
g_set_wait_obj(self->resize_ready);
}
else if (self->resize_data->state == WMRZ_ERROR)
{
LOG(LOG_LEVEL_INFO, "dynamic_monitor_process_queue: Clearing"
" failed request to resize to: (w: %d x h: %d)",
self->resize_data->description.session_width,
self->resize_data->description.session_height);
g_set_wait_obj(self->resize_ready);
}
else
{
// No errors, process it!
return process_display_control_monitor_layout_data(self->wm);
}
g_free(self->resize_data);
self->resize_data = NULL;
return 0;
}
/******************************************************************************/ /******************************************************************************/
int int
dynamic_monitor_initialize(struct xrdp_mm *self) dynamic_monitor_initialize(struct xrdp_mm *self)
@ -1266,6 +1460,7 @@ dynamic_monitor_initialize(struct xrdp_mm *self)
int int
xrdp_mm_drdynvc_up(struct xrdp_mm *self) xrdp_mm_drdynvc_up(struct xrdp_mm *self)
{ {
struct display_control_monitor_layout_data *ignore_marker;
const char *enable_dynamic_resize; const char *enable_dynamic_resize;
int error = 0; int error = 0;
@ -1279,11 +1474,12 @@ xrdp_mm_drdynvc_up(struct xrdp_mm *self)
!g_text2bool(enable_dynamic_resize)) !g_text2bool(enable_dynamic_resize))
{ {
LOG(LOG_LEVEL_INFO, "User has disabled dynamic resizing."); LOG(LOG_LEVEL_INFO, "User has disabled dynamic resizing.");
return error;
} }
else ignore_marker = (struct display_control_monitor_layout_data *)
{ g_malloc(sizeof(struct display_control_monitor_layout_data), 1);
error = dynamic_monitor_initialize(self); list_add_item(self->resize_queue, (tintptr)ignore_marker);
} error = dynamic_monitor_initialize(self);
return error; return error;
} }
@ -1317,7 +1513,8 @@ xrdp_mm_drdynvc_open_response(intptr_t id, int chan_id, int creation_status)
struct xrdp_process *pro; struct xrdp_process *pro;
int chansrv_chan_id; int chansrv_chan_id;
LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_mm_drdynvc_open_response: chan_id %d creation_status %d", LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_mm_drdynvc_open_response: "
" chan_id %d creation_status %d",
chan_id, creation_status); chan_id, creation_status);
pro = (struct xrdp_process *) id; pro = (struct xrdp_process *) id;
wm = pro->wm; wm = pro->wm;
@ -2684,6 +2881,11 @@ xrdp_mm_get_wait_objs(struct xrdp_mm *self,
read_objs[(*rcount)++] = self->encoder->xrdp_encoder_event_processed; read_objs[(*rcount)++] = self->encoder->xrdp_encoder_event_processed;
} }
if (self->resize_queue != 0)
{
read_objs[(*rcount)++] = self->resize_ready;
}
return rv; return rv;
} }
@ -2908,6 +3110,12 @@ xrdp_mm_check_wait_objs(struct xrdp_mm *self)
} }
} }
if (g_is_wait_obj_set(self->resize_ready))
{
g_reset_wait_obj(self->resize_ready);
dynamic_monitor_process_queue(self);
}
if (self->encoder != NULL) if (self->encoder != NULL)
{ {
if (g_is_wait_obj_set(self->encoder->xrdp_encoder_event_processed)) if (g_is_wait_obj_set(self->encoder->xrdp_encoder_event_processed))
@ -3557,7 +3765,8 @@ server_reset(struct xrdp_mod *mod, int width, int height, int bpp)
if (wm->client_info->display_sizes.session_width == (uint32_t)width && if (wm->client_info->display_sizes.session_width == (uint32_t)width &&
wm->client_info->display_sizes.session_height == (uint32_t)height && wm->client_info->display_sizes.session_height == (uint32_t)height &&
wm->client_info->bpp == bpp && wm->client_info->bpp == bpp &&
(wm->client_info->display_sizes.monitorCount == 0 || wm->client_info->multimon == 0)) (wm->client_info->display_sizes.monitorCount == 0 ||
wm->client_info->multimon == 0))
{ {
return 0; return 0;
} }

View File

@ -311,6 +311,30 @@ enum mm_connect_state
MMCS_DONE MMCS_DONE
}; };
enum display_resize_state
{
WMRZ_ENCODER_DELETE = 0,
WMRZ_SERVER_MONITOR_RESIZE,
WMRZ_SERVER_VERSION_MESSAGE,
WMRZ_XRDP_CORE_RESIZE,
WMRZ_ENCODER_CREATE,
WMRZ_SERVER_INVALIDATE,
WMRZ_COMPLETE,
WMRZ_ERROR
};
#define XRDP_DISPLAY_RESIZE_STATE_TO_STR(status) \
((status) == WMRZ_ENCODER_DELETE ? "WMRZ_ENCODER_DELETE" : \
(status) == WMRZ_SERVER_MONITOR_RESIZE ? "WMRZ_SERVER_MONITOR_RESIZE" : \
(status) == WMRZ_SERVER_VERSION_MESSAGE ? "WMRZ_SERVER_VERSION_MESSAGE" : \
(status) == WMRZ_XRDP_CORE_RESIZE ? "WMRZ_XRDP_CORE_RESIZE" : \
(status) == WMRZ_ENCODER_CREATE ? "WMRZ_ENCODER_CREATE" : \
(status) == WMRZ_SERVER_INVALIDATE ? "WMRZ_SERVER_INVALIDATE" : \
(status) == WMRZ_COMPLETE ? "WMRZ_COMPLETE" : \
(status) == WMRZ_ERROR ? "WMRZ_ERROR" : \
"unknown" \
)
struct xrdp_mm struct xrdp_mm
{ {
struct xrdp_wm *wm; /* owner */ struct xrdp_wm *wm; /* owner */
@ -344,6 +368,11 @@ struct xrdp_mm
int cs2xr_cid_map[256]; int cs2xr_cid_map[256];
int xr2cr_cid_map[256]; int xr2cr_cid_map[256];
int dynamic_monitor_chanid; int dynamic_monitor_chanid;
/* Resize on-the-fly control */
struct display_control_monitor_layout_data *resize_data;
struct list *resize_queue;
tbus resize_ready;
}; };
struct xrdp_key_info struct xrdp_key_info

View File

@ -2230,9 +2230,8 @@ xrdp_wm_check_wait_objs(struct xrdp_wm *self)
} }
/*****************************************************************************/ /*****************************************************************************/
const char *
static const char * xrdp_wm_login_state_to_str(enum wm_login_state login_state)
wm_login_state_to_str(enum wm_login_state login_state)
{ {
const char *result = "unknown"; const char *result = "unknown";
/* Use a switch for this, as some compilers will warn about missing states /* Use a switch for this, as some compilers will warn about missing states
@ -2266,10 +2265,24 @@ int
xrdp_wm_set_login_state(struct xrdp_wm *self, enum wm_login_state login_state) xrdp_wm_set_login_state(struct xrdp_wm *self, enum wm_login_state login_state)
{ {
LOG(LOG_LEVEL_DEBUG, "Login state change request %s -> %s", LOG(LOG_LEVEL_DEBUG, "Login state change request %s -> %s",
wm_login_state_to_str(self->login_state), xrdp_wm_login_state_to_str(self->login_state),
wm_login_state_to_str(login_state)); xrdp_wm_login_state_to_str(login_state));
self->login_state = login_state; self->login_state = login_state;
g_set_wait_obj(self->login_state_event); g_set_wait_obj(self->login_state_event);
return 0; return 0;
} }
int
xrdp_wm_can_resize(struct xrdp_wm *self)
{
if (self->login_state != WMLS_CLEANUP
&& self->login_state != WMLS_INACTIVE)
{
LOG(LOG_LEVEL_INFO, "Not allowing resize. Login in progress.");
LOG_DEVEL(LOG_LEVEL_INFO,
"State is %s", xrdp_wm_login_state_to_str(self->login_state));
return 0;
}
return 1;
}

View File

@ -28,10 +28,12 @@
#include "string_calls.h" #include "string_calls.h"
static int static int
send_server_monitor_resize(struct mod *mod, struct stream *s, int width, int height, int bpp); send_server_monitor_resize(
struct mod *mod, struct stream *s, int width, int height, int bpp);
static int static int
send_server_monitor_full_invalidate(struct mod *mod, struct stream *s, int width, int height); send_server_monitor_full_invalidate(
struct mod *mod, struct stream *s, int width, int height);
static int static int
send_server_version_message(struct mod *v, struct stream *s); send_server_version_message(struct mod *v, struct stream *s);
@ -154,10 +156,15 @@ lib_mod_connect(struct mod *mod)
mod->server_msg(mod, "started connecting", 0); mod->server_msg(mod, "started connecting", 0);
/* only support 8, 15, 16, 24, and 32 bpp connections from rdp client */ /* only support 8, 15, 16, 24, and 32 bpp connections from rdp client */
if (mod->bpp != 8 && mod->bpp != 15 && mod->bpp != 16 && mod->bpp != 24 && mod->bpp != 32) if (mod->bpp != 8
&& mod->bpp != 15
&& mod->bpp != 16
&& mod->bpp != 24
&& mod->bpp != 32)
{ {
mod->server_msg(mod, mod->server_msg(mod,
"error - only supporting 8, 15, 16, 24, and 32 bpp rdp connections", 0); "error - only supporting 8, 15, 16, 24, and 32"
" bpp rdp connections", 0);
return 1; return 1;
} }
@ -220,12 +227,14 @@ lib_mod_connect(struct mod *mod)
if (error == 0) if (error == 0)
{ {
/* send screen size message */ /* send screen size message */
error = send_server_monitor_resize(mod, s, mod->width, mod->height, mod->bpp); error = send_server_monitor_resize(
mod, s, mod->width, mod->height, mod->bpp);
} }
if (error == 0) if (error == 0)
{ {
error = send_server_monitor_full_invalidate(mod, s, mod->width, mod->height); error = send_server_monitor_full_invalidate(
mod, s, mod->width, mod->height);
} }
free_stream(s); free_stream(s);
@ -1261,7 +1270,8 @@ send_server_version_message(struct mod *mod, struct stream *s)
/******************************************************************************/ /******************************************************************************/
/* return error */ /* return error */
static int static int
send_server_monitor_resize(struct mod *mod, struct stream *s, int width, int height, int bpp) send_server_monitor_resize(
struct mod *mod, struct stream *s, int width, int height, int bpp)
{ {
/* send screen size message */ /* send screen size message */
init_stream(s, 8192); init_stream(s, 8192);
@ -1271,8 +1281,9 @@ send_server_monitor_resize(struct mod *mod, struct stream *s, int width, int hei
out_uint32_le(s, width); out_uint32_le(s, width);
out_uint32_le(s, height); out_uint32_le(s, height);
/* /*
TODO: The bpp here is only necessary for initial creation. We should modify XUP to require this TODO: The bpp here is only necessary for initial creation. We should
only on server initialization, but not on resize. Microsoft's RDP protocol does not support changing modify XUP to require this only on server initialization, but not on
resize. Microsoft's RDP protocol does not support changing
the bpp on resize. the bpp on resize.
*/ */
out_uint32_le(s, bpp); out_uint32_le(s, bpp);
@ -1282,14 +1293,16 @@ send_server_monitor_resize(struct mod *mod, struct stream *s, int width, int hei
s_pop_layer(s, iso_hdr); s_pop_layer(s, iso_hdr);
out_uint32_le(s, len); out_uint32_le(s, len);
int rv = lib_send_copy(mod, s); int rv = lib_send_copy(mod, s);
LOG_DEVEL(LOG_LEVEL_DEBUG, "send_server_monitor_resize: sent resize message with following properties to xorgxrdp backend " LOG_DEVEL(LOG_LEVEL_DEBUG, "send_server_monitor_resize:"
"width=%d, height=%d, bpp=%d, return value=%d", " sent resize message with following properties to"
" xorgxrdp backend width=%d, height=%d, bpp=%d, return value=%d",
width, height, bpp, rv); width, height, bpp, rv);
return rv; return rv;
} }
static int static int
send_server_monitor_full_invalidate(struct mod *mod, struct stream *s, int width, int height) send_server_monitor_full_invalidate(
struct mod *mod, struct stream *s, int width, int height)
{ {
/* send invalidate message */ /* send invalidate message */
init_stream(s, 8192); init_stream(s, 8192);
@ -1309,8 +1322,10 @@ send_server_monitor_full_invalidate(struct mod *mod, struct stream *s, int width
s_pop_layer(s, iso_hdr); s_pop_layer(s, iso_hdr);
out_uint32_le(s, len); out_uint32_le(s, len);
int rv = lib_send_copy(mod, s); int rv = lib_send_copy(mod, s);
LOG_DEVEL(LOG_LEVEL_DEBUG, "send_server_monitor_full_invalidate: sent invalidate message with following properties to xorgxrdp backend " LOG_DEVEL(LOG_LEVEL_DEBUG, "send_server_monitor_full_invalidate:"
"width=%d, height=%d, return value=%d", " sent invalidate message with following"
" properties to xorgxrdp backend"
" width=%d, height=%d, return value=%d",
width, height, rv); width, height, rv);
return rv; return rv;
} }
@ -1456,7 +1471,8 @@ lib_mod_process_orders(struct mod *mod, int type, struct stream *s)
rv = process_server_paint_rect_shmem_ex(mod, s); rv = process_server_paint_rect_shmem_ex(mod, s);
break; break;
default: default:
LOG_DEVEL(LOG_LEVEL_WARNING, "lib_mod_process_orders: unknown order type %d", type); LOG_DEVEL(LOG_LEVEL_WARNING,
"lib_mod_process_orders: unknown order type %d", type);
rv = 0; rv = 0;
break; break;
} }
@ -1523,7 +1539,8 @@ lib_mod_process_message(struct mod *mod, struct stream *s)
} }
else if (type == 2) /* caps */ else if (type == 2) /* caps */
{ {
LOG_DEVEL(LOG_LEVEL_TRACE, "lib_mod_process_message: type 2 len %d", len); LOG_DEVEL(LOG_LEVEL_TRACE,
"lib_mod_process_message: type 2 len %d", len);
for (index = 0; index < num_orders; index++) for (index = 0; index < num_orders; index++)
{ {
phold = s->p; phold = s->p;
@ -1533,7 +1550,9 @@ lib_mod_process_message(struct mod *mod, struct stream *s)
switch (type) switch (type)
{ {
default: default:
LOG_DEVEL(LOG_LEVEL_TRACE, "lib_mod_process_message: unknown cap type %d len %d", LOG_DEVEL(LOG_LEVEL_TRACE,
"lib_mod_process_message: unknown"
" cap type %d len %d",
type, len); type, len);
break; break;
} }
@ -1661,7 +1680,8 @@ lib_mod_check_wait_objs(struct mod *mod)
int int
lib_mod_frame_ack(struct mod *amod, int flags, int frame_id) lib_mod_frame_ack(struct mod *amod, int flags, int frame_id)
{ {
LOG_DEVEL(LOG_LEVEL_TRACE, "lib_mod_frame_ack: flags 0x%8.8x frame_id %d", flags, frame_id); LOG_DEVEL(LOG_LEVEL_TRACE,
"lib_mod_frame_ack: flags 0x%8.8x frame_id %d", flags, frame_id);
send_paint_rect_ex_ack(amod, flags, frame_id); send_paint_rect_ex_ack(amod, flags, frame_id);
return 0; return 0;
} }
@ -1672,7 +1692,8 @@ int
lib_mod_suppress_output(struct mod *amod, int suppress, lib_mod_suppress_output(struct mod *amod, int suppress,
int left, int top, int right, int bottom) int left, int top, int right, int bottom)
{ {
LOG_DEVEL(LOG_LEVEL_TRACE, "lib_mod_suppress_output: suppress 0x%8.8x left %d top %d " LOG_DEVEL(LOG_LEVEL_TRACE,
"lib_mod_suppress_output: suppress 0x%8.8x left %d top %d "
"right %d bottom %d", suppress, left, top, right, bottom); "right %d bottom %d", suppress, left, top, right, bottom);
send_suppress_output(amod, suppress, left, top, right, bottom); send_suppress_output(amod, suppress, left, top, right, bottom);
return 0; return 0;
@ -1699,7 +1720,8 @@ mod_init(void)
mod->mod_frame_ack = lib_mod_frame_ack; mod->mod_frame_ack = lib_mod_frame_ack;
mod->mod_suppress_output = lib_mod_suppress_output; mod->mod_suppress_output = lib_mod_suppress_output;
mod->mod_server_monitor_resize = lib_send_server_monitor_resize; mod->mod_server_monitor_resize = lib_send_server_monitor_resize;
mod->mod_server_monitor_full_invalidate = lib_send_server_monitor_full_invalidate; mod->mod_server_monitor_full_invalidate
= lib_send_server_monitor_full_invalidate;
mod->mod_server_version_message = lib_send_server_version_message; mod->mod_server_version_message = lib_send_server_version_message;
return (tintptr) mod; return (tintptr) mod;
} }