From 6f461aa54c9ab3092b25ffd079060cd45b7c7285 Mon Sep 17 00:00:00 2001 From: Christopher Pitstick Date: Tue, 15 Mar 2022 00:45:26 -0400 Subject: [PATCH] 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. --- xrdp/xrdp.h | 20 +- xrdp/xrdp_mm.c | 535 ++++++++++++++++++++++++++++++++-------------- xrdp/xrdp_types.h | 29 +++ xrdp/xrdp_wm.c | 23 +- xup/xup.c | 62 ++++-- 5 files changed, 470 insertions(+), 199 deletions(-) diff --git a/xrdp/xrdp.h b/xrdp/xrdp.h index 88ec8814..d1ae20fb 100644 --- a/xrdp/xrdp.h +++ b/xrdp/xrdp.h @@ -147,8 +147,12 @@ xrdp_wm_get_wait_objs(struct xrdp_wm *self, tbus *robjs, int *rc, tbus *wobjs, int *wc, int *timeout); int xrdp_wm_check_wait_objs(struct xrdp_wm *self); +const char * +xrdp_wm_login_state_to_str(enum wm_login_state login_state); int 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 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 */ -struct dynamic_monitor_layout +struct display_control_monitor_layout_data { - int flags; - int left; - int top; - int width; - int height; - int physical_width; - int physical_height; - int orientation; - int desktop_scale_factor; - int device_scale_factor; + struct display_size_description description; + enum display_resize_state state; + int last_state_update_timestamp; + int start_time; }; int diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index 3d65675a..89aa108c 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -43,6 +43,7 @@ #include "xrdp_encoder.h" #include "xrdp_sockets.h" +#include /* Forward declarations */ @@ -65,6 +66,8 @@ struct xrdp_mm * xrdp_mm_create(struct xrdp_wm *owner) { struct xrdp_mm *self; + char buf[1024]; + int pid; self = (struct xrdp_mm *)g_malloc(sizeof(struct xrdp_mm), 1); self->wm = owner; @@ -72,6 +75,14 @@ xrdp_mm_create(struct xrdp_wm *owner) self->login_names->auto_free = 1; self->login_values = list_create(); 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 " "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; list_delete(self->login_names); 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); } @@ -969,7 +983,8 @@ dynamic_monitor_open_response(intptr_t id, int chan_id, int creation_status) struct stream *s; 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) { LOG(LOG_LEVEL_ERROR, "dynamic_monitor_open_response: error"); @@ -1031,152 +1046,24 @@ sync_dynamic_monitor_data(struct xrdp_wm *wm, MAXIMUM_MONITOR_SIZE); } -/******************************************************************************/ -static int -process_dynamic_monitor_description(struct xrdp_wm *wm, - struct display_size_description *description) +int +advance_resize_state_machine(struct xrdp_mm *mm, + enum display_resize_state new_state) { - int error = 0; - struct xrdp_mm *mm = wm->mm; - struct xrdp_mod *module = mm->mod; - - LOG_DEVEL(LOG_LEVEL_TRACE, "process_dynamic_monitor_description:"); - - if (wm->client_info->suppress_output == 1) - { - LOG(LOG_LEVEL_ERROR, - "process_dynamic_monitor_description:" - " Not allowing resize. Suppress output is active."); - return 0; - } - if (description == NULL) - { - 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); + struct display_control_monitor_layout_data *description = mm->resize_data; + LOG_DEVEL(LOG_LEVEL_INFO, + "advance_resize_state_machine:" + " Processing resize to: %d x %d." + " Advancing state from %s to %s." + " Previous state took %d MS.", + description->description.session_width, + description->description.session_height, + XRDP_DISPLAY_RESIZE_STATE_TO_STR(description->state), + XRDP_DISPLAY_RESIZE_STATE_TO_STR(new_state), + g_time3() - description->last_state_update_timestamp); + description->state = new_state; + description->last_state_update_timestamp = g_time3(); + g_set_wait_obj(mm->resize_ready); 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_wm *wm; int monitor_layout_size; + struct display_size_description *display_size_data; LOG_DEVEL(LOG_LEVEL_TRACE, "dynamic_monitor_data:"); pro = (struct xrdp_process *) id; 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)); ls.data = data; ls.p = ls.data; @@ -1204,16 +1100,33 @@ dynamic_monitor_data(intptr_t id, int chan_id, char *data, int bytes) s = &ls; in_uint32_le(s, msg_type); in_uint32_le(s, msg_length); - LOG(LOG_LEVEL_DEBUG, "dynamic_monitor_data: msg_type %d msg_length %d", - msg_type, msg_length); + LOG_DEVEL(LOG_LEVEL_DEBUG, + "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; } in_uint32_le(s, monitor_layout_size); if (monitor_layout_size != 40) { + /* 2.2.2.2 DISPLAYCONTROL_MONITOR_LAYOUT_PDU */ LOG(LOG_LEVEL_ERROR, "dynamic_monitor_data: monitor_layout_size" " is %d. Per spec ([MS-RDPEDISP] 2.2.2.2" " 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; } - struct display_size_description *description = - (struct display_size_description *) - g_malloc(sizeof(struct display_size_description), 1); - - error = libxrdp_process_monitor_stream(s, description, 1); - if (error == 0) + display_size_data = (struct display_size_description *) + g_malloc(sizeof(struct display_size_description), 1); + if (!display_size_data) { - 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; } +/******************************************************************************/ +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 dynamic_monitor_initialize(struct xrdp_mm *self) @@ -1266,6 +1460,7 @@ dynamic_monitor_initialize(struct xrdp_mm *self) int xrdp_mm_drdynvc_up(struct xrdp_mm *self) { + struct display_control_monitor_layout_data *ignore_marker; const char *enable_dynamic_resize; int error = 0; @@ -1279,11 +1474,12 @@ xrdp_mm_drdynvc_up(struct xrdp_mm *self) !g_text2bool(enable_dynamic_resize)) { LOG(LOG_LEVEL_INFO, "User has disabled dynamic resizing."); + return error; } - else - { - error = dynamic_monitor_initialize(self); - } + ignore_marker = (struct display_control_monitor_layout_data *) + g_malloc(sizeof(struct display_control_monitor_layout_data), 1); + list_add_item(self->resize_queue, (tintptr)ignore_marker); + error = dynamic_monitor_initialize(self); return error; } @@ -1317,7 +1513,8 @@ xrdp_mm_drdynvc_open_response(intptr_t id, int chan_id, int creation_status) struct xrdp_process *pro; 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); pro = (struct xrdp_process *) id; 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; } + if (self->resize_queue != 0) + { + read_objs[(*rcount)++] = self->resize_ready; + } + 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 (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 && wm->client_info->display_sizes.session_height == (uint32_t)height && 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; } diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h index d800370c..41d109a0 100644 --- a/xrdp/xrdp_types.h +++ b/xrdp/xrdp_types.h @@ -311,6 +311,30 @@ enum mm_connect_state 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_wm *wm; /* owner */ @@ -344,6 +368,11 @@ struct xrdp_mm int cs2xr_cid_map[256]; int xr2cr_cid_map[256]; 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 diff --git a/xrdp/xrdp_wm.c b/xrdp/xrdp_wm.c index 6d5f1b89..ff37deb7 100644 --- a/xrdp/xrdp_wm.c +++ b/xrdp/xrdp_wm.c @@ -2230,9 +2230,8 @@ xrdp_wm_check_wait_objs(struct xrdp_wm *self) } /*****************************************************************************/ - -static const char * -wm_login_state_to_str(enum wm_login_state login_state) +const char * +xrdp_wm_login_state_to_str(enum wm_login_state login_state) { const char *result = "unknown"; /* 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) { LOG(LOG_LEVEL_DEBUG, "Login state change request %s -> %s", - wm_login_state_to_str(self->login_state), - wm_login_state_to_str(login_state)); + xrdp_wm_login_state_to_str(self->login_state), + xrdp_wm_login_state_to_str(login_state)); self->login_state = login_state; g_set_wait_obj(self->login_state_event); 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; +} diff --git a/xup/xup.c b/xup/xup.c index cae29100..fcb65d75 100644 --- a/xup/xup.c +++ b/xup/xup.c @@ -28,10 +28,12 @@ #include "string_calls.h" 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 -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 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); /* 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, - "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; } @@ -220,12 +227,14 @@ lib_mod_connect(struct mod *mod) if (error == 0) { /* 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) { - 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); @@ -1261,7 +1270,8 @@ send_server_version_message(struct mod *mod, struct stream *s) /******************************************************************************/ /* return error */ 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 */ 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, height); /* - TODO: The bpp here is only necessary for initial creation. We should modify XUP to require this - only on server initialization, but not on resize. Microsoft's RDP protocol does not support changing + TODO: The bpp here is only necessary for initial creation. We should + 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. */ 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); out_uint32_le(s, len); 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 " - "width=%d, height=%d, bpp=%d, return value=%d", + LOG_DEVEL(LOG_LEVEL_DEBUG, "send_server_monitor_resize:" + " sent resize message with following properties to" + " xorgxrdp backend width=%d, height=%d, bpp=%d, return value=%d", width, height, bpp, rv); return rv; } 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 */ 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); out_uint32_le(s, len); 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 " - "width=%d, height=%d, return value=%d", + LOG_DEVEL(LOG_LEVEL_DEBUG, "send_server_monitor_full_invalidate:" + " sent invalidate message with following" + " properties to xorgxrdp backend" + " width=%d, height=%d, return value=%d", width, height, 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); break; 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; break; } @@ -1523,7 +1539,8 @@ lib_mod_process_message(struct mod *mod, struct stream *s) } 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++) { phold = s->p; @@ -1533,7 +1550,9 @@ lib_mod_process_message(struct mod *mod, struct stream *s) switch (type) { 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); break; } @@ -1661,7 +1680,8 @@ lib_mod_check_wait_objs(struct mod *mod) int 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); return 0; } @@ -1672,7 +1692,8 @@ int lib_mod_suppress_output(struct mod *amod, int suppress, 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); send_suppress_output(amod, suppress, left, top, right, bottom); return 0; @@ -1699,7 +1720,8 @@ mod_init(void) mod->mod_frame_ack = lib_mod_frame_ack; mod->mod_suppress_output = lib_mod_suppress_output; 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; return (tintptr) mod; }