Added RDP 10.7 large pointer support
authorArmin Novak <armin.novak@thincast.com>
Thu, 19 Dec 2019 08:35:53 +0000 (09:35 +0100)
committerArmin Novak <armin.novak@thincast.com>
Thu, 19 Dec 2019 08:53:40 +0000 (09:53 +0100)
* Implements [MS-RDPBCGR] version 51 large pointer support.
* Logs unknown large pointer capability flags as warning.

Signed-off-by: Armin Novak <armin.novak@thincast.com>
15 files changed:
client/common/cmdline.c
include/freerdp/message.h
include/freerdp/pointer.h
libfreerdp/cache/pointer.c
libfreerdp/cache/pointer.h
libfreerdp/core/capabilities.c
libfreerdp/core/capabilities.h
libfreerdp/core/fastpath.c
libfreerdp/core/fastpath.h
libfreerdp/core/message.c
libfreerdp/core/message.h
libfreerdp/core/settings.c
libfreerdp/core/update.c
libfreerdp/core/update.h
server/proxy/pf_update.c

index 9757b13..fe402f4 100644 (file)
@@ -36,7 +36,6 @@
 #include <freerdp/client/channels.h>
 #include <freerdp/crypto/crypto.h>
 #include <freerdp/locale/keyboard.h>
-
 #include <freerdp/utils/passphrase.h>
 
 #include <freerdp/client/cmdline.h>
@@ -3136,7 +3135,8 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
        if (settings->RemoteFxCodec || settings->NSCodec || settings->SupportGraphicsPipeline)
        {
                settings->FastPathOutput = TRUE;
-               settings->LargePointerFlag = TRUE;
+               settings->LargePointerFlag =
+                   0x0002; /* (LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384); */
                settings->FrameMarkerCommandEnabled = TRUE;
                settings->ColorDepth = 32;
        }
index ee1fa1f..2c277a5 100644 (file)
 #define PointerUpdate_PointerColor 3
 #define PointerUpdate_PointerNew 4
 #define PointerUpdate_PointerCached 5
+#define PointerUpdate_PointerLarge 6
 
 #define FREERDP_POINTER_UPDATE_ POINTER_POSITION MakeMessageId(PointerUpdate, PointerPosition)
 #define FREERDP_POINTER_UPDATE_POINTER_SYSTEM MakeMessageId(PointerUpdate, PointerSystem)
 #define FREERDP_POINTER_UPDATE_POINTER_COLOR MakeMessageId(PointerUpdate, PointerColor)
 #define FREERDP_POINTER_UPDATE_POINTER_NEW MakeMessageId(PointerUpdate, PointerNew)
 #define FREERDP_POINTER_UPDATE_POINTER_CACHED MakeMessageId(PointerUpdate, PointerCached)
+#define FREERDP_POINTER_UPDATE_POINTER_LARGE MakeMessageId(PointerUpdate, PointerLarge)
 
 /**
  * Input Message Queue
index 0a78876..5ea720b 100644 (file)
@@ -27,6 +27,7 @@
 #define PTR_MSG_TYPE_COLOR 0x0006
 #define PTR_MSG_TYPE_CACHED 0x0007
 #define PTR_MSG_TYPE_POINTER 0x0008
+#define PTR_MSG_TYPE_POINTER_LARGE 0x0009
 
 #define SYSPTR_NULL 0x00000000
 #define SYSPTR_DEFAULT 0x00007F00
@@ -58,6 +59,21 @@ struct _POINTER_COLOR_UPDATE
 };
 typedef struct _POINTER_COLOR_UPDATE POINTER_COLOR_UPDATE;
 
+struct _POINTER_LARGE_UPDATE
+{
+       UINT16 xorBpp;
+       UINT16 cacheIndex;
+       UINT16 hotSpotX;
+       UINT16 hotSpotY;
+       UINT16 width;
+       UINT16 height;
+       UINT32 lengthAndMask;
+       UINT32 lengthXorMask;
+       BYTE* xorMaskData;
+       BYTE* andMaskData;
+};
+typedef struct _POINTER_LARGE_UPDATE POINTER_LARGE_UPDATE;
+
 struct _POINTER_NEW_UPDATE
 {
        UINT32 xorBpp;
@@ -77,6 +93,7 @@ typedef BOOL (*pPointerSystem)(rdpContext* context, const POINTER_SYSTEM_UPDATE*
 typedef BOOL (*pPointerColor)(rdpContext* context, const POINTER_COLOR_UPDATE* pointer_color);
 typedef BOOL (*pPointerNew)(rdpContext* context, const POINTER_NEW_UPDATE* pointer_new);
 typedef BOOL (*pPointerCached)(rdpContext* context, const POINTER_CACHED_UPDATE* pointer_cached);
+typedef BOOL (*pPointerLarge)(rdpContext* context, const POINTER_LARGE_UPDATE* pointer_large);
 
 struct rdp_pointer_update
 {
@@ -88,7 +105,8 @@ struct rdp_pointer_update
        pPointerColor PointerColor;       /* 18 */
        pPointerNew PointerNew;           /* 19 */
        pPointerCached PointerCached;     /* 20 */
-       UINT32 paddingB[32 - 21];         /* 21 */
+       pPointerLarge PointerLarge;       /* 21 */
+       UINT32 paddingB[32 - 22];         /* 22 */
 };
 typedef struct rdp_pointer_update rdpPointerUpdate;
 
index 7545c13..3169486 100644 (file)
@@ -147,6 +147,57 @@ out_fail:
        return FALSE;
 }
 
+static BOOL update_pointer_large(rdpContext* context, const POINTER_LARGE_UPDATE* pointer_large)
+{
+       rdpPointer* pointer;
+       rdpCache* cache = context->cache;
+       pointer = Pointer_Alloc(context);
+
+       if (pointer != NULL)
+       {
+               pointer->xorBpp = pointer_large->xorBpp;
+               pointer->xPos = pointer_large->hotSpotX;
+               pointer->yPos = pointer_large->hotSpotY;
+               pointer->width = pointer_large->width;
+               pointer->height = pointer_large->height;
+               pointer->lengthAndMask = pointer_large->lengthAndMask;
+               pointer->lengthXorMask = pointer_large->lengthXorMask;
+
+               if (pointer->lengthAndMask && pointer_large->andMaskData)
+               {
+                       pointer->andMaskData = (BYTE*)malloc(pointer->lengthAndMask);
+
+                       if (!pointer->andMaskData)
+                               goto out_fail;
+
+                       CopyMemory(pointer->andMaskData, pointer_large->andMaskData, pointer->lengthAndMask);
+               }
+
+               if (pointer->lengthXorMask && pointer_large->xorMaskData)
+               {
+                       pointer->xorMaskData = (BYTE*)malloc(pointer->lengthXorMask);
+
+                       if (!pointer->xorMaskData)
+                               goto out_fail;
+
+                       CopyMemory(pointer->xorMaskData, pointer_large->xorMaskData, pointer->lengthXorMask);
+               }
+
+               if (!IFCALLRESULT(TRUE, pointer->New, context, pointer))
+                       goto out_fail;
+
+               if (!pointer_cache_put(cache->pointer, pointer_large->cacheIndex, pointer))
+                       goto out_fail;
+
+               return IFCALLRESULT(TRUE, pointer->Set, context, pointer);
+       }
+
+       return FALSE;
+out_fail:
+       pointer_free(context, pointer);
+       return FALSE;
+}
+
 static BOOL update_pointer_new(rdpContext* context, const POINTER_NEW_UPDATE* pointer_new)
 {
        rdpPointer* pointer;
@@ -251,6 +302,7 @@ void pointer_cache_register_callbacks(rdpUpdate* update)
        pointer->PointerPosition = update_pointer_position;
        pointer->PointerSystem = update_pointer_system;
        pointer->PointerColor = update_pointer_color;
+       pointer->PointerLarge = update_pointer_large;
        pointer->PointerNew = update_pointer_new;
        pointer->PointerCached = update_pointer_cached;
 }
@@ -341,6 +393,53 @@ void free_pointer_color_update(rdpContext* context, POINTER_COLOR_UPDATE* pointe
        free(pointer);
 }
 
+POINTER_LARGE_UPDATE* copy_pointer_large_update(rdpContext* context,
+                                                const POINTER_LARGE_UPDATE* src)
+{
+       POINTER_LARGE_UPDATE* dst = calloc(1, sizeof(POINTER_LARGE_UPDATE));
+
+       if (!dst || !src)
+               goto fail;
+
+       *dst = *src;
+
+       if (src->lengthAndMask > 0)
+       {
+               dst->andMaskData = calloc(src->lengthAndMask, sizeof(BYTE));
+
+               if (!dst->andMaskData)
+                       goto fail;
+
+               memcpy(dst->andMaskData, src->andMaskData, src->lengthAndMask);
+       }
+
+       if (src->lengthXorMask > 0)
+       {
+               dst->xorMaskData = calloc(src->lengthXorMask, sizeof(BYTE));
+
+               if (!dst->xorMaskData)
+                       goto fail;
+
+               memcpy(dst->xorMaskData, src->xorMaskData, src->lengthXorMask);
+       }
+
+       return dst;
+fail:
+       free_pointer_large_update(context, dst);
+       return NULL;
+}
+
+void free_pointer_large_update(rdpContext* context, POINTER_LARGE_UPDATE* pointer)
+{
+       WINPR_UNUSED(context);
+       if (!pointer)
+               return;
+
+       free(pointer->xorMaskData);
+       free(pointer->andMaskData);
+       free(pointer);
+}
+
 POINTER_NEW_UPDATE* copy_pointer_new_update(rdpContext* context, const POINTER_NEW_UPDATE* src)
 {
        POINTER_NEW_UPDATE* dst = calloc(1, sizeof(POINTER_NEW_UPDATE));
index 599dc04..95ba34f 100644 (file)
@@ -28,6 +28,10 @@ FREERDP_LOCAL POINTER_COLOR_UPDATE* copy_pointer_color_update(rdpContext* contex
                                                               const POINTER_COLOR_UPDATE* pointer);
 FREERDP_LOCAL void free_pointer_color_update(rdpContext* context, POINTER_COLOR_UPDATE* pointer);
 
+FREERDP_LOCAL POINTER_LARGE_UPDATE* copy_pointer_large_update(rdpContext* context,
+                                                              const POINTER_LARGE_UPDATE* pointer);
+FREERDP_LOCAL void free_pointer_large_update(rdpContext* context, POINTER_LARGE_UPDATE* pointer);
+
 FREERDP_LOCAL POINTER_NEW_UPDATE* copy_pointer_new_update(rdpContext* context,
                                                           const POINTER_NEW_UPDATE* pointer);
 FREERDP_LOCAL void free_pointer_new_update(rdpContext* context, POINTER_NEW_UPDATE* pointer);
index 0602f4b..ca09e3a 100644 (file)
@@ -2479,7 +2479,16 @@ static BOOL rdp_read_large_pointer_capability_set(wStream* s, UINT16 length, rdp
                return FALSE;
 
        Stream_Read_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */
-       settings->LargePointerFlag = (largePointerSupportFlags & LARGE_POINTER_FLAG_96x96) ? 1 : 0;
+       settings->LargePointerFlag =
+           largePointerSupportFlags & (LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384);
+       if ((largePointerSupportFlags & ~(LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384)) != 0)
+       {
+               WLog_WARN(
+                   TAG,
+                   "TS_LARGE_POINTER_CAPABILITYSET with unsupported flags %04X (all flags %04X) received",
+                   largePointerSupportFlags & ~(LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384),
+                   largePointerSupportFlags);
+       }
        return TRUE;
 }
 
@@ -2499,7 +2508,8 @@ static BOOL rdp_write_large_pointer_capability_set(wStream* s, const rdpSettings
                return FALSE;
 
        header = rdp_capability_set_start(s);
-       largePointerSupportFlags = (settings->LargePointerFlag) ? LARGE_POINTER_FLAG_96x96 : 0;
+       largePointerSupportFlags =
+           settings->LargePointerFlag & (LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384);
        Stream_Write_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */
        rdp_capability_set_finish(s, header, CAPSET_TYPE_LARGE_POINTER);
        return TRUE;
index 4174a8e..8765519 100644 (file)
 
 /* Large Pointer Support Flags */
 #define LARGE_POINTER_FLAG_96x96 0x00000001
+#define LARGE_POINTER_FLAG_384x384 0x00000002
 
 /* Surface Commands Flags */
 #define SURFCMDS_SET_SURFACE_BITS 0x00000002
index a4506d0..6e815c2 100644 (file)
@@ -470,6 +470,17 @@ static int fastpath_recv_update(rdpFastPath* fastpath, BYTE updateCode, wStream*
                }
                break;
 
+               case FASTPATH_UPDATETYPE_LARGE_POINTER:
+               {
+                       POINTER_LARGE_UPDATE* pointer_large = update_read_pointer_large(update, s);
+
+                       if (pointer_large)
+                       {
+                               rc = IFCALLRESULT(FALSE, pointer->PointerLarge, context, pointer_large);
+                               free_pointer_large_update(context, pointer_large);
+                       }
+               }
+               break;
                default:
                        break;
        }
index ce2811a..752a92e 100644 (file)
@@ -79,7 +79,8 @@ enum FASTPATH_UPDATETYPE
        FASTPATH_UPDATETYPE_PTR_POSITION = 0x8,
        FASTPATH_UPDATETYPE_COLOR = 0x9,
        FASTPATH_UPDATETYPE_CACHED = 0xA,
-       FASTPATH_UPDATETYPE_POINTER = 0xB
+       FASTPATH_UPDATETYPE_POINTER = 0xB,
+       FASTPATH_UPDATETYPE_LARGE_POINTER = 0xC
 };
 
 enum FASTPATH_FRAGMENT
index 7b88d7d..8f64d47 100644 (file)
@@ -1440,6 +1440,22 @@ static BOOL update_message_PointerColor(rdpContext* context,
                                 MakeMessageId(PointerUpdate, PointerColor), (void*)wParam, NULL);
 }
 
+static BOOL update_message_PointerLarge(rdpContext* context, const POINTER_LARGE_UPDATE* pointer)
+{
+       POINTER_LARGE_UPDATE* wParam;
+
+       if (!context || !context->update || !pointer)
+               return FALSE;
+
+       wParam = copy_pointer_large_update(context, pointer);
+
+       if (!wParam)
+               return FALSE;
+
+       return MessageQueue_Post(context->update->queue, (void*)context,
+                                MakeMessageId(PointerUpdate, PointerLarge), (void*)wParam, NULL);
+}
+
 static BOOL update_message_PointerNew(rdpContext* context, const POINTER_NEW_UPDATE* pointerNew)
 {
        POINTER_NEW_UPDATE* wParam;
@@ -2640,11 +2656,13 @@ static BOOL update_message_register_interface(rdpUpdateProxy* message, rdpUpdate
        message->PointerPosition = pointer->PointerPosition;
        message->PointerSystem = pointer->PointerSystem;
        message->PointerColor = pointer->PointerColor;
+       message->PointerLarge = pointer->PointerLarge;
        message->PointerNew = pointer->PointerNew;
        message->PointerCached = pointer->PointerCached;
        pointer->PointerPosition = update_message_PointerPosition;
        pointer->PointerSystem = update_message_PointerSystem;
        pointer->PointerColor = update_message_PointerColor;
+       pointer->PointerLarge = update_message_PointerLarge;
        pointer->PointerNew = update_message_PointerNew;
        pointer->PointerCached = update_message_PointerCached;
        return TRUE;
index 4de0862..33a78d5 100644 (file)
@@ -123,6 +123,7 @@ struct rdp_update_proxy
        pPointerColor PointerColor;
        pPointerNew PointerNew;
        pPointerCached PointerCached;
+       pPointerLarge PointerLarge;
 
        HANDLE thread;
 };
index 9fc9ee7..195c6b3 100644 (file)
@@ -421,7 +421,7 @@ rdpSettings* freerdp_settings_new(DWORD flags)
        gethostname(settings->ClientHostname, 31);
        settings->ClientHostname[31] = 0;
        settings->ColorPointerFlag = TRUE;
-       settings->LargePointerFlag = TRUE;
+       settings->LargePointerFlag = (LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384);
        settings->PointerCacheSize = 20;
        settings->SoundBeepsEnabled = TRUE;
        settings->DrawGdiPlusEnabled = FALSE;
index a330f20..2dd0a9a 100644 (file)
@@ -489,6 +489,130 @@ fail:
        return NULL;
 }
 
+static BOOL _update_read_pointer_large(wStream* s, POINTER_LARGE_UPDATE* pointer)
+{
+       BYTE* newMask;
+       UINT32 scanlineSize;
+
+       if (!pointer)
+               goto fail;
+
+       if (Stream_GetRemainingLength(s) < 14)
+               goto fail;
+
+       Stream_Read_UINT16(s, pointer->xorBpp);
+       Stream_Read_UINT16(s, pointer->cacheIndex); /* cacheIndex (2 bytes) */
+       Stream_Read_UINT16(s, pointer->hotSpotX);   /* xPos (2 bytes) */
+       Stream_Read_UINT16(s, pointer->hotSpotY);   /* yPos (2 bytes) */
+
+       Stream_Read_UINT16(s, pointer->width);  /* width (2 bytes) */
+       Stream_Read_UINT16(s, pointer->height); /* height (2 bytes) */
+
+       if ((pointer->width > 384) || (pointer->height > 384))
+               goto fail;
+
+       Stream_Read_UINT16(s, pointer->lengthAndMask); /* lengthAndMask (2 bytes) */
+       Stream_Read_UINT16(s, pointer->lengthXorMask); /* lengthXorMask (2 bytes) */
+
+       if (pointer->hotSpotX >= pointer->width)
+               pointer->hotSpotX = 0;
+
+       if (pointer->hotSpotY >= pointer->height)
+               pointer->hotSpotY = 0;
+
+       if (pointer->lengthXorMask > 0)
+       {
+               /**
+                * Spec states that:
+                *
+                * xorMaskData (variable): A variable-length array of bytes. Contains the 24-bpp, bottom-up
+                * XOR mask scan-line data. The XOR mask is padded to a 2-byte boundary for each encoded
+                * scan-line. For example, if a 3x3 pixel cursor is being sent, then each scan-line will
+                * consume 10 bytes (3 pixels per scan-line multiplied by 3 bytes per pixel, rounded up to
+                * the next even number of bytes).
+                *
+                * In fact instead of 24-bpp, the bpp parameter is given by the containing packet.
+                */
+               if (Stream_GetRemainingLength(s) < pointer->lengthXorMask)
+                       goto fail;
+
+               scanlineSize = (7 + pointer->xorBpp * pointer->width) / 8;
+               scanlineSize = ((scanlineSize + 1) / 2) * 2;
+
+               if (scanlineSize * pointer->height != pointer->lengthXorMask)
+               {
+                       WLog_ERR(TAG,
+                                "invalid lengthXorMask: width=%" PRIu32 " height=%" PRIu32 ", %" PRIu32
+                                " instead of %" PRIu32 "",
+                                pointer->width, pointer->height, pointer->lengthXorMask,
+                                scanlineSize * pointer->height);
+                       goto fail;
+               }
+
+               newMask = realloc(pointer->xorMaskData, pointer->lengthXorMask);
+
+               if (!newMask)
+                       goto fail;
+
+               pointer->xorMaskData = newMask;
+               Stream_Read(s, pointer->xorMaskData, pointer->lengthXorMask);
+       }
+
+       if (pointer->lengthAndMask > 0)
+       {
+               /**
+                * andMaskData (variable): A variable-length array of bytes. Contains the 1-bpp, bottom-up
+                * AND mask scan-line data. The AND mask is padded to a 2-byte boundary for each encoded
+                * scan-line. For example, if a 7x7 pixel cursor is being sent, then each scan-line will
+                * consume 2 bytes (7 pixels per scan-line multiplied by 1 bpp, rounded up to the next even
+                * number of bytes).
+                */
+               if (Stream_GetRemainingLength(s) < pointer->lengthAndMask)
+                       goto fail;
+
+               scanlineSize = ((7 + pointer->width) / 8);
+               scanlineSize = ((1 + scanlineSize) / 2) * 2;
+
+               if (scanlineSize * pointer->height != pointer->lengthAndMask)
+               {
+                       WLog_ERR(TAG, "invalid lengthAndMask: %" PRIu32 " instead of %" PRIu32 "",
+                                pointer->lengthAndMask, scanlineSize * pointer->height);
+                       goto fail;
+               }
+
+               newMask = realloc(pointer->andMaskData, pointer->lengthAndMask);
+
+               if (!newMask)
+                       goto fail;
+
+               pointer->andMaskData = newMask;
+               Stream_Read(s, pointer->andMaskData, pointer->lengthAndMask);
+       }
+
+       if (Stream_GetRemainingLength(s) > 0)
+               Stream_Seek_UINT8(s); /* pad (1 byte) */
+
+       return TRUE;
+fail:
+       return FALSE;
+}
+
+POINTER_LARGE_UPDATE* update_read_pointer_large(rdpUpdate* update, wStream* s)
+{
+       POINTER_LARGE_UPDATE* pointer = calloc(1, sizeof(POINTER_LARGE_UPDATE));
+
+       if (!pointer)
+               goto fail;
+
+       if (!_update_read_pointer_large(s, pointer))
+               goto fail;
+
+       return pointer;
+fail:
+       free_pointer_large_update(update->context, pointer);
+       return NULL;
+}
+
 POINTER_NEW_UPDATE* update_read_pointer_new(rdpUpdate* update, wStream* s)
 {
        POINTER_NEW_UPDATE* pointer_new = calloc(1, sizeof(POINTER_NEW_UPDATE));
@@ -585,6 +709,18 @@ BOOL update_recv_pointer(rdpUpdate* update, wStream* s)
                }
                break;
 
+               case PTR_MSG_TYPE_POINTER_LARGE:
+               {
+                       POINTER_LARGE_UPDATE* pointer_large = update_read_pointer_large(update, s);
+
+                       if (pointer_large)
+                       {
+                               rc = IFCALLRESULT(FALSE, pointer->PointerLarge, context, pointer_large);
+                               free_pointer_large_update(context, pointer_large);
+                       }
+               }
+               break;
+
                case PTR_MSG_TYPE_POINTER:
                {
                        POINTER_NEW_UPDATE* pointer_new = update_read_pointer_new(update, s);
@@ -1888,6 +2024,44 @@ out_fail:
        return ret;
 }
 
+static BOOL update_write_pointer_large(wStream* s, const POINTER_LARGE_UPDATE* pointer)
+{
+       if (!Stream_EnsureRemainingCapacity(s, 32 + pointer->lengthAndMask + pointer->lengthXorMask))
+               return FALSE;
+
+       Stream_Write_UINT16(s, pointer->xorBpp);
+       Stream_Write_UINT16(s, pointer->cacheIndex);
+       Stream_Write_UINT16(s, pointer->hotSpotX);
+       Stream_Write_UINT16(s, pointer->hotSpotY);
+       Stream_Write_UINT16(s, pointer->width);
+       Stream_Write_UINT16(s, pointer->height);
+       Stream_Write_UINT32(s, pointer->lengthAndMask);
+       Stream_Write_UINT32(s, pointer->lengthXorMask);
+       Stream_Write(s, pointer->xorMaskData, pointer->lengthXorMask);
+       Stream_Write(s, pointer->andMaskData, pointer->lengthAndMask);
+       Stream_Write_UINT8(s, 0); /* pad (1 byte) */
+       return TRUE;
+}
+
+static BOOL update_send_pointer_large(rdpContext* context, const POINTER_LARGE_UPDATE* pointer)
+{
+       wStream* s;
+       rdpRdp* rdp = context->rdp;
+       BOOL ret = FALSE;
+       s = fastpath_update_pdu_init(rdp->fastpath);
+
+       if (!s)
+               return FALSE;
+
+       if (!update_write_pointer_large(s, pointer))
+               goto out_fail;
+
+       ret = fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_LARGE_POINTER, s, FALSE);
+out_fail:
+       Stream_Release(s);
+       return ret;
+}
+
 static BOOL update_send_pointer_new(rdpContext* context, const POINTER_NEW_UPDATE* pointer_new)
 {
        wStream* s;
@@ -2635,6 +2809,7 @@ void update_register_server_callbacks(rdpUpdate* update)
        update->pointer->PointerSystem = update_send_pointer_system;
        update->pointer->PointerPosition = update_send_pointer_position;
        update->pointer->PointerColor = update_send_pointer_color;
+       update->pointer->PointerLarge = update_send_pointer_large;
        update->pointer->PointerNew = update_send_pointer_new;
        update->pointer->PointerCached = update_send_pointer_cached;
        update->window->WindowCreate = update_send_window_create;
index 057411c..747a89b 100644 (file)
@@ -55,6 +55,8 @@ FREERDP_LOCAL POINTER_SYSTEM_UPDATE* update_read_pointer_system(rdpUpdate* updat
 FREERDP_LOCAL POINTER_POSITION_UPDATE* update_read_pointer_position(rdpUpdate* update, wStream* s);
 FREERDP_LOCAL POINTER_COLOR_UPDATE* update_read_pointer_color(rdpUpdate* update, wStream* s,
                                                               BYTE xorBpp);
+FREERDP_LOCAL POINTER_LARGE_UPDATE* update_read_pointer_large(rdpUpdate* update, wStream* s);
+
 FREERDP_LOCAL POINTER_NEW_UPDATE* update_read_pointer_new(rdpUpdate* update, wStream* s);
 FREERDP_LOCAL POINTER_CACHED_UPDATE* update_read_pointer_cached(rdpUpdate* update, wStream* s);
 
index 6472aaa..37e4383 100644 (file)
@@ -152,6 +152,16 @@ static BOOL pf_client_send_pointer_color(rdpContext* context,
        return ps->update->pointer->PointerColor(ps, pointer_color);
 }
 
+static BOOL pf_client_send_pointer_large(rdpContext* context,
+                                         const POINTER_LARGE_UPDATE* pointer_large)
+{
+       pClientContext* pc = (pClientContext*)context;
+       proxyData* pdata = pc->pdata;
+       rdpContext* ps = (rdpContext*)pdata->ps;
+       WLog_DBG(TAG, __FUNCTION__);
+       return ps->update->pointer->PointerLarge(ps, pointer_large);
+}
+
 static BOOL pf_client_send_pointer_new(rdpContext* context, const POINTER_NEW_UPDATE* pointer_new)
 {
        pClientContext* pc = (pClientContext*)context;
@@ -324,6 +334,7 @@ void pf_client_register_update_callbacks(rdpUpdate* update)
        update->pointer->PointerSystem = pf_client_send_pointer_system;
        update->pointer->PointerPosition = pf_client_send_pointer_position;
        update->pointer->PointerColor = pf_client_send_pointer_color;
+       update->pointer->PointerLarge = pf_client_send_pointer_large;
        update->pointer->PointerNew = pf_client_send_pointer_new;
        update->pointer->PointerCached = pf_client_send_pointer_cached;
 }