Skip to content

Commit

Permalink
GUACAMOLE-288: Handle multiple monitors in RDP via resize display upd…
Browse files Browse the repository at this point in the history
…ates.
  • Loading branch information
corentin-soriano committed Oct 29, 2024
1 parent 26e3e80 commit 4d1fe5c
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 30 deletions.
73 changes: 45 additions & 28 deletions src/protocols/rdp/channels/disp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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)
Expand All @@ -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;

Expand All @@ -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);

}

}
Expand Down
10 changes: 9 additions & 1 deletion src/protocols/rdp/channels/disp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion src/protocols/rdp/rdp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions src/protocols/rdp/settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 4d1fe5c

Please sign in to comment.