From 121a2348663a8299bb26fcf2d4e9720f5ac868c6 Mon Sep 17 00:00:00 2001 From: davewheel Date: Wed, 20 Jan 2016 16:54:15 +0100 Subject: [PATCH] Add better handling of monitors This patch makes FreeRDP announce the support for monitor layout PDU. It also adds support for servers to announce the monitors layout. --- include/freerdp/update.h | 4 +++- libfreerdp/core/activation.c | 25 +++++++++++++++++++++++++ libfreerdp/core/gcc.c | 6 ++++++ libfreerdp/core/rdp.c | 29 ++++++++++++++++------------- libfreerdp/core/rdp.h | 2 ++ libfreerdp/core/settings.c | 1 + 6 files changed, 53 insertions(+), 14 deletions(-) diff --git a/include/freerdp/update.h b/include/freerdp/update.h index 527d291..16829b1 100644 --- a/include/freerdp/update.h +++ b/include/freerdp/update.h @@ -148,6 +148,7 @@ typedef BOOL (*pSetKeyboardIndicators)(rdpContext* context, UINT16 led_flags); typedef BOOL (*pRefreshRect)(rdpContext* context, BYTE count, RECTANGLE_16* areas); typedef BOOL (*pSuppressOutput)(rdpContext* context, BYTE allow, RECTANGLE_16* area); +typedef BOOL (*pRemoteMonitors)(rdpContext* context, UINT32 count, const MONITOR_DEF *monitors); typedef BOOL (*pSurfaceCommand)(rdpContext* context, wStream* s); typedef BOOL (*pSurfaceBits)(rdpContext* context, SURFACE_BITS_COMMAND* surfaceBitsCommand); @@ -180,7 +181,8 @@ struct rdp_update pRefreshRect RefreshRect; /* 48 */ pSuppressOutput SuppressOutput; /* 49 */ - UINT32 paddingD[64 - 50]; /* 50 */ + pRemoteMonitors RemoteMonitors; /* 50 */ + UINT32 paddingD[64 - 51]; /* 51 */ pSurfaceCommand SurfaceCommand; /* 64 */ pSurfaceBits SurfaceBits; /* 65 */ diff --git a/libfreerdp/core/activation.c b/libfreerdp/core/activation.c index 97ea426..2db0566 100644 --- a/libfreerdp/core/activation.c +++ b/libfreerdp/core/activation.c @@ -364,9 +364,34 @@ BOOL rdp_server_accept_client_control_pdu(rdpRdp* rdp, wStream* s) BOOL rdp_server_accept_client_font_list_pdu(rdpRdp* rdp, wStream* s) { + rdpSettings *settings = rdp->settings; + if (!rdp_recv_client_font_list_pdu(s)) return FALSE; + if (settings->SupportMonitorLayoutPdu && settings->MonitorCount) + { + /* client supports the monitorLayout PDU, let's send him the monitors if any */ + wStream *st; + BOOL r; + + st = rdp_data_pdu_init(rdp); + if (!st) + return FALSE; + + if (!rdp_write_monitor_layout_pdu(st, settings->MonitorCount, settings->MonitorDefArray)) + { + Stream_Free(st, TRUE); + return FALSE; + } + + r = rdp_send_data_pdu(rdp, st, DATA_PDU_TYPE_MONITOR_LAYOUT, 0); + Stream_Free(st, TRUE); + + if (!r) + return FALSE; + } + if (!rdp_send_server_font_map_pdu(rdp)) return FALSE; diff --git a/libfreerdp/core/gcc.c b/libfreerdp/core/gcc.c index af0b9c3..f4b0bee 100644 --- a/libfreerdp/core/gcc.c +++ b/libfreerdp/core/gcc.c @@ -761,6 +761,9 @@ BOOL gcc_read_client_core_data(wStream* s, rdpMcs* mcs, UINT16 blockLength) if (settings->SupportDynamicTimeZone) settings->SupportDynamicTimeZone = (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE) ? TRUE : FALSE; + if (settings->SupportMonitorLayoutPdu) + settings->SupportMonitorLayoutPdu = (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU) ? TRUE : FALSE; + if (!(earlyCapabilityFlags & RNS_UD_CS_VALID_CONNECTION_TYPE)) connectionType = 0; @@ -866,6 +869,9 @@ void gcc_write_client_core_data(wStream* s, rdpMcs* mcs) if (settings->SupportDynamicTimeZone) earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE; + if (settings->SupportMonitorLayoutPdu) + earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU; + Stream_Write_UINT16(s, highColorDepth); /* highColorDepth */ Stream_Write_UINT16(s, supportedColorDepths); /* supportedColorDepths */ diff --git a/libfreerdp/core/rdp.c b/libfreerdp/core/rdp.c index f49ae99..655a032 100644 --- a/libfreerdp/core/rdp.c +++ b/libfreerdp/core/rdp.c @@ -706,13 +706,14 @@ BOOL rdp_recv_monitor_layout_pdu(rdpRdp* rdp, wStream* s) UINT32 monitorCount; MONITOR_DEF* monitor; MONITOR_DEF* monitorDefArray; + BOOL ret = TRUE; if (Stream_GetRemainingLength(s) < 4) return FALSE; Stream_Read_UINT32(s, monitorCount); /* monitorCount (4 bytes) */ - if (Stream_GetRemainingLength(s) < (monitorCount * 20)) + if ((Stream_GetRemainingLength(s) / 20) < monitorCount) return FALSE; monitorDefArray = (MONITOR_DEF*) calloc(monitorCount, sizeof(MONITOR_DEF)); @@ -720,9 +721,8 @@ BOOL rdp_recv_monitor_layout_pdu(rdpRdp* rdp, wStream* s) if (!monitorDefArray) return FALSE; - for (index = 0; index < monitorCount; index++) + for (monitor = monitorDefArray, index = 0; index < monitorCount; index++, monitor++) { - monitor = &(monitorDefArray[index]); Stream_Read_UINT32(s, monitor->left); /* left (4 bytes) */ Stream_Read_UINT32(s, monitor->top); /* top (4 bytes) */ Stream_Read_UINT32(s, monitor->right); /* right (4 bytes) */ @@ -730,27 +730,30 @@ BOOL rdp_recv_monitor_layout_pdu(rdpRdp* rdp, wStream* s) Stream_Read_UINT32(s, monitor->flags); /* flags (4 bytes) */ } + IFCALLRET(rdp->update->RemoteMonitors, ret, rdp->context, monitorCount, monitorDefArray); + free(monitorDefArray); - return TRUE; + return ret; } -BOOL rdp_write_monitor_layout_pdu(wStream* s, UINT32 monitorCount, MONITOR_DEF* monitorDefArray) +BOOL rdp_write_monitor_layout_pdu(wStream* s, UINT32 monitorCount, const rdpMonitor* monitorDefArray) { UINT32 index; - MONITOR_DEF* monitor; + const rdpMonitor* monitor; + if (!Stream_EnsureRemainingCapacity(s, 4 + (monitorCount * 20))) return FALSE; + Stream_Write_UINT32(s, monitorCount); /* monitorCount (4 bytes) */ - for (index = 0; index < monitorCount; index++) + for (index = 0, monitor = monitorDefArray; index < monitorCount; index++, monitor++) { - monitor = &(monitorDefArray[index]); - Stream_Write_UINT32(s, monitor->left); /* left (4 bytes) */ - Stream_Write_UINT32(s, monitor->top); /* top (4 bytes) */ - Stream_Write_UINT32(s, monitor->right); /* right (4 bytes) */ - Stream_Write_UINT32(s, monitor->bottom); /* bottom (4 bytes) */ - Stream_Write_UINT32(s, monitor->flags); /* flags (4 bytes) */ + Stream_Write_UINT32(s, monitor->x); /* left (4 bytes) */ + Stream_Write_UINT32(s, monitor->y); /* top (4 bytes) */ + Stream_Write_UINT32(s, monitor->x + monitor->width - 1); /* right (4 bytes) */ + Stream_Write_UINT32(s, monitor->y + monitor->height - 1); /* bottom (4 bytes) */ + Stream_Write_UINT32(s, monitor->is_primary ? 0x01 : 0x00); /* flags (4 bytes) */ } return TRUE; diff --git a/libfreerdp/core/rdp.h b/libfreerdp/core/rdp.h index f756220..ad24bd4 100644 --- a/libfreerdp/core/rdp.h +++ b/libfreerdp/core/rdp.h @@ -214,6 +214,8 @@ int rdp_recv_out_of_sequence_pdu(rdpRdp* rdp, wStream* s); void rdp_read_flow_control_pdu(wStream* s, UINT16* type); +BOOL rdp_write_monitor_layout_pdu(wStream* s, UINT32 monitorCount, const rdpMonitor* monitorDefArray); + int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra); int rdp_check_fds(rdpRdp* rdp); diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c index 0ddd7d2..456a4e3 100644 --- a/libfreerdp/core/settings.c +++ b/libfreerdp/core/settings.c @@ -295,6 +295,7 @@ rdpSettings* freerdp_settings_new(DWORD flags) if (!settings->ChannelDefArray) goto out_fail; + settings->SupportMonitorLayoutPdu = TRUE; settings->MonitorCount = 0; settings->MonitorDefArraySize = 32; settings->MonitorDefArray = (rdpMonitor*) calloc(settings->MonitorDefArraySize, sizeof(rdpMonitor)); -- 2.7.4