From 4d1fe5c09d0234c570f4bfb1b63fdf87773d2fa3 Mon Sep 17 00:00:00 2001 From: Corentin SORIANO Date: Sun, 20 Oct 2024 11:39:50 +0200 Subject: [PATCH] GUACAMOLE-288: Handle multiple monitors in RDP via resize display updates. --- src/protocols/rdp/channels/disp.c | 73 +++++++++++++++++++------------ src/protocols/rdp/channels/disp.h | 10 ++++- src/protocols/rdp/rdp.c | 1 - src/protocols/rdp/settings.c | 2 + 4 files changed, 56 insertions(+), 30 deletions(-) diff --git a/src/protocols/rdp/channels/disp.c b/src/protocols/rdp/channels/disp.c index d72921d53..bad459b94 100644 --- a/src/protocols/rdp/channels/disp.c +++ b/src/protocols/rdp/channels/disp.c @@ -44,9 +44,10 @@ guac_rdp_disp* guac_rdp_disp_alloc(guac_client* client) { /* No requests have been made */ disp->last_request = guac_timestamp_current(); - disp->requested_width = 0; - disp->requested_height = 0; - disp->reconnect_needed = 0; + disp->requested_width = 0; + disp->requested_height = 0; + disp->reconnect_needed = 0; + disp->requested_monitors = 1; return disp; @@ -88,7 +89,7 @@ static void guac_rdp_disp_channel_connected(rdpContext* context, /* Init module with current display size */ guac_rdp_disp_set_size(guac_disp, rdp_client->settings, context->instance, guac_rdp_get_width(context->instance), - guac_rdp_get_height(context->instance)); + guac_rdp_get_height(context->instance), 1); /* Store reference to the display update plugin once it's connected */ DispClientContext* disp = (DispClientContext*) args->pInterface; @@ -180,6 +181,7 @@ void guac_rdp_disp_set_size(guac_rdp_disp* disp, guac_rdp_settings* settings, /* Store deferred size */ disp->requested_width = width; disp->requested_height = height; + disp->requested_monitors = monitors; /* Send display update notification if possible */ guac_rdp_disp_update_size(disp, settings, rdp_inst); @@ -191,6 +193,7 @@ void guac_rdp_disp_update_size(guac_rdp_disp* disp, int width = disp->requested_width; int height = disp->requested_height; + int monitors_count = disp->requested_monitors; /* Do not update size if no requests have been received */ if (width == 0 || height == 0) @@ -204,7 +207,7 @@ void guac_rdp_disp_update_size(guac_rdp_disp* disp, /* Do NOT send requests unless the size will change */ if (rdp_inst != NULL - && width == guac_rdp_get_width(rdp_inst) + && width * monitors_count == guac_rdp_get_width(rdp_inst) && height == guac_rdp_get_height(rdp_inst)) return; @@ -221,32 +224,46 @@ void guac_rdp_disp_update_size(guac_rdp_disp* disp, } - else if (settings->resize_method == GUAC_RESIZE_DISPLAY_UPDATE) { - DISPLAY_CONTROL_MONITOR_LAYOUT monitors[1] = {{ - .Flags = 0x1, /* DISPLAYCONTROL_MONITOR_PRIMARY */ - .Left = 0, - .Top = 0, - .Width = width, - .Height = height, - .PhysicalWidth = 0, - .PhysicalHeight = 0, - .Orientation = 0, - .DesktopScaleFactor = 0, - .DeviceScaleFactor = 0 - }}; - - /* Send display update notification if display channel is connected */ - if (disp->disp != NULL) { - - guac_client* client = disp->client; - guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; - - pthread_mutex_lock(&(rdp_client->message_lock)); - disp->disp->SendMonitorLayout(disp->disp, 1, monitors); - pthread_mutex_unlock(&(rdp_client->message_lock)); + /* Send display update notification if display channel is connected */ + else if (settings->resize_method == GUAC_RESIZE_DISPLAY_UPDATE + && disp->disp != NULL) { + + /* Init monitors layout */ + DISPLAY_CONTROL_MONITOR_LAYOUT* monitors; + monitors = guac_mem_alloc(monitors_count * sizeof(DISPLAY_CONTROL_MONITOR_LAYOUT)); + + for (int i = 0; i < monitors_count; i++) { + + /* First monitor is the primary */ + int primary_monitor = (i == 0 ? 1 : 0); + + /* Shift each monitor to the right */ + int monitor_left = i * width; + /* Get current monitor */ + DISPLAY_CONTROL_MONITOR_LAYOUT* monitor = &monitors[i]; + + /* Set current monitor properties */ + monitor->Flags = primary_monitor; + monitor->Left = monitor_left; + monitor->Top = 0; + monitor->Width = width; + monitor->Height = height; + monitor->Orientation = 0; + monitor->PhysicalWidth = 0; + monitor->PhysicalHeight = 0; } + /* Send display update notification */ + guac_client* client = disp->client; + guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; + + pthread_mutex_lock(&(rdp_client->message_lock)); + disp->disp->SendMonitorLayout(disp->disp, monitors_count, monitors); + pthread_mutex_unlock(&(rdp_client->message_lock)); + + guac_mem_free(monitors); + } } diff --git a/src/protocols/rdp/channels/disp.h b/src/protocols/rdp/channels/disp.h index 54fe4ccfa..4aa997170 100644 --- a/src/protocols/rdp/channels/disp.h +++ b/src/protocols/rdp/channels/disp.h @@ -74,6 +74,11 @@ typedef struct guac_rdp_disp { */ int requested_height; + /** + * The number of monitors requested. + */ + int requested_monitors; + /** * Whether the size has changed and the RDP connection must be closed and * reestablished. @@ -154,9 +159,12 @@ void guac_rdp_disp_load_plugin(rdpContext* context); * The desired display height, in pixels. Due to the restrictions of the * RDP display update channel, this will be constrained to the range of 200 * through 8192 inclusive. + * + * @param monitors + * The count of monitors. */ void guac_rdp_disp_set_size(guac_rdp_disp* disp, guac_rdp_settings* settings, - freerdp* rdp_inst, int width, int height); + freerdp* rdp_inst, int width, int height, int monitors); /** * Sends an actual display update request to the RDP server based on previous diff --git a/src/protocols/rdp/rdp.c b/src/protocols/rdp/rdp.c index a6e7720d3..80c45d1f5 100644 --- a/src/protocols/rdp/rdp.c +++ b/src/protocols/rdp/rdp.c @@ -607,7 +607,6 @@ static int guac_rdp_handle_connection(guac_client* client) { guac_rdp_disp_update_size(rdp_client->disp, settings, rdp_inst); /* Wait for data and construct a reasonable frame */ - int wait_result = rdp_guac_client_wait_for_messages(client, GUAC_RDP_MESSAGE_CHECK_INTERVAL); if (wait_result < 0) break; diff --git a/src/protocols/rdp/settings.c b/src/protocols/rdp/settings.c index f47b1cff8..eb7c45d5f 100644 --- a/src/protocols/rdp/settings.c +++ b/src/protocols/rdp/settings.c @@ -1729,6 +1729,7 @@ void guac_rdp_push_settings(guac_client* client, freerdp_settings_set_uint32(rdp_settings, FreeRDP_OsMajorType, OSMAJORTYPE_UNSPECIFIED); freerdp_settings_set_uint32(rdp_settings, FreeRDP_OsMinorType, OSMINORTYPE_UNSPECIFIED); freerdp_settings_set_bool(rdp_settings, FreeRDP_DesktopResize, TRUE); + freerdp_settings_set_bool(rdp_settings, FreeRDP_UseMultimon, TRUE); /* Claim support only for specific updates, independent of FreeRDP defaults */ BYTE* order_support = freerdp_settings_get_pointer_writable(rdp_settings, FreeRDP_OrderSupport); @@ -1975,6 +1976,7 @@ void guac_rdp_push_settings(guac_client* client, rdp_settings->OsMajorType = OSMAJORTYPE_UNSPECIFIED; rdp_settings->OsMinorType = OSMINORTYPE_UNSPECIFIED; rdp_settings->DesktopResize = TRUE; + rdp_settings->UseMultimon = TRUE; /* Claim support only for specific updates, independent of FreeRDP defaults */ ZeroMemory(rdp_settings->OrderSupport, GUAC_RDP_ORDER_SUPPORT_LENGTH);