Add better handling of monitors
authordavewheel <dave@wheel>
Wed, 20 Jan 2016 15:54:15 +0000 (16:54 +0100)
committerdavewheel <dave@wheel>
Wed, 20 Jan 2016 15:56:04 +0000 (16:56 +0100)
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
libfreerdp/core/activation.c
libfreerdp/core/gcc.c
libfreerdp/core/rdp.c
libfreerdp/core/rdp.h
libfreerdp/core/settings.c

index 527d291..16829b1 100644 (file)
@@ -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 */
index 97ea426..2db0566 100644 (file)
@@ -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;
 
index af0b9c3..f4b0bee 100644 (file)
@@ -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 */
 
index f49ae99..655a032 100644 (file)
@@ -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;
index f756220..ad24bd4 100644 (file)
@@ -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);
index 0ddd7d2..456a4e3 100644 (file)
@@ -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));