diff --git a/libfreerdp/core/update.c b/libfreerdp/core/update.c index 5039e29b7..629ed9d7b 100644 --- a/libfreerdp/core/update.c +++ b/libfreerdp/core/update.c @@ -1506,9 +1506,25 @@ static void update_send_pointer_system(rdpContext* context, POINTER_SYSTEM_UPDAT Stream_Release(s); } +static void update_send_pointer_position(rdpContext* context, POINTER_POSITION_UPDATE* pointerPosition) +{ + wStream* s; + rdpRdp* rdp = context->rdp; + + s = fastpath_update_pdu_init(rdp->fastpath); + + Stream_EnsureRemainingCapacity(s, 16); + + Stream_Write_UINT16(s, pointerPosition->xPos); /* xPos (2 bytes) */ + Stream_Write_UINT16(s, pointerPosition->yPos); /* yPos (2 bytes) */ + + fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_PTR_POSITION, s); + Stream_Release(s); +} + static void update_write_pointer_color(wStream* s, POINTER_COLOR_UPDATE* pointer_color) { - Stream_EnsureRemainingCapacity(s, 15 + (int) pointer_color->lengthAndMask + (int) pointer_color->lengthXorMask); + Stream_EnsureRemainingCapacity(s, 32 + (int) pointer_color->lengthAndMask + (int) pointer_color->lengthXorMask); Stream_Write_UINT16(s, pointer_color->cacheIndex); Stream_Write_UINT16(s, pointer_color->xPos); @@ -1544,8 +1560,12 @@ static void update_send_pointer_new(rdpContext* context, POINTER_NEW_UPDATE* poi rdpRdp* rdp = context->rdp; s = fastpath_update_pdu_init(rdp->fastpath); + + Stream_EnsureRemainingCapacity(s, 16); + Stream_Write_UINT16(s, pointer_new->xorBpp); /* xorBpp (2 bytes) */ update_write_pointer_color(s, &pointer_new->colorPtrAttr); + fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_POINTER, s); Stream_Release(s); } @@ -1614,14 +1634,14 @@ BOOL update_read_suppress_output(rdpUpdate* update, wStream* s) static void update_send_set_keyboard_indicators(rdpContext* context, UINT16 led_flags) { - wStream* s; - rdpRdp* rdp = context->rdp; + wStream* s; + rdpRdp* rdp = context->rdp; - s = rdp_data_pdu_init(rdp); - Stream_Write_UINT16(s, 0); /* unitId should be 0 according to MS-RDPBCGR 2.2.8.2.1.1 */ - Stream_Write_UINT16(s, led_flags); /* ledFlags (2 bytes) */ - rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_SET_KEYBOARD_INDICATORS, rdp->mcs->userId); - Stream_Release(s); + s = rdp_data_pdu_init(rdp); + Stream_Write_UINT16(s, 0); /* unitId should be 0 according to MS-RDPBCGR 2.2.8.2.1.1 */ + Stream_Write_UINT16(s, led_flags); /* ledFlags (2 bytes) */ + rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_SET_KEYBOARD_INDICATORS, rdp->mcs->userId); + Stream_Release(s); } void update_register_server_callbacks(rdpUpdate* update) @@ -1655,6 +1675,7 @@ void update_register_server_callbacks(rdpUpdate* update) update->altsec->CreateOffscreenBitmap = update_send_create_offscreen_bitmap_order; update->altsec->SwitchSurface = update_send_switch_surface_order; update->pointer->PointerSystem = update_send_pointer_system; + update->pointer->PointerPosition = update_send_pointer_position; update->pointer->PointerColor = update_send_pointer_color; update->pointer->PointerNew = update_send_pointer_new; update->pointer->PointerCached = update_send_pointer_cached; diff --git a/server/shadow/X11/x11_shadow.c b/server/shadow/X11/x11_shadow.c index 943bc0b63..c3187bfd9 100644 --- a/server/shadow/X11/x11_shadow.c +++ b/server/shadow/X11/x11_shadow.c @@ -341,6 +341,55 @@ void x11_shadow_input_extended_mouse_event(x11ShadowSubsystem* subsystem, UINT16 #endif } +int x11_shadow_pointer_position_update(x11ShadowSubsystem* subsystem) +{ + SHADOW_MSG_OUT_POINTER_POSITION_UPDATE* msg; + UINT32 msgId = SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID; + wMessagePipe* MsgPipe = subsystem->MsgPipe; + + msg = (SHADOW_MSG_OUT_POINTER_POSITION_UPDATE*) calloc(1, sizeof(SHADOW_MSG_OUT_POINTER_POSITION_UPDATE)); + + if (!msg) + return -1; + + msg->xPos = subsystem->cursorX; + msg->yPos = subsystem->cursorY; + + MessageQueue_Post(MsgPipe->Out, NULL, msgId, (void*) msg, NULL); + + return 1; +} + +int x11_shadow_pointer_alpha_update(x11ShadowSubsystem* subsystem) +{ + SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE* msg; + UINT32 msgId = SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID; + wMessagePipe* MsgPipe = subsystem->MsgPipe; + + msg = (SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE*) calloc(1, sizeof(SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE)); + + if (!msg) + return -1; + + msg->xHot = subsystem->cursorHotX; + msg->yHot = subsystem->cursorHotY; + msg->width = subsystem->cursorWidth; + msg->height = subsystem->cursorHeight; + msg->scanline = msg->width * 4; + + msg->pixels = (BYTE*) malloc(msg->scanline * msg->height); + + if (!msg->pixels) + return -1; + + CopyMemory(msg->pixels, subsystem->cursorPixels, msg->scanline * msg->height); + msg->premultiplied = TRUE; + + MessageQueue_Post(MsgPipe->Out, NULL, msgId, (void*) msg, NULL); + + return 1; +} + int x11_shadow_query_cursor(x11ShadowSubsystem* subsystem, BOOL getImage) { int x, y, n, k; @@ -385,6 +434,8 @@ int x11_shadow_query_cursor(x11ShadowSubsystem* subsystem, BOOL getImage) } XFree(ci); + + x11_shadow_pointer_alpha_update(subsystem); #endif } else @@ -407,6 +458,8 @@ int x11_shadow_query_cursor(x11ShadowSubsystem* subsystem, BOOL getImage) subsystem->cursorX = x; subsystem->cursorY = y; + x11_shadow_pointer_position_update(subsystem); + return 1; } @@ -633,7 +686,7 @@ int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem) (BYTE*) image->data, PIXEL_FORMAT_XRGB32, image->bytes_per_line, x, y, NULL); - x11_shadow_blend_cursor(subsystem); + //x11_shadow_blend_cursor(subsystem); count = ArrayList_Count(server->clients); diff --git a/server/shadow/shadow_client.c b/server/shadow/shadow_client.c index d3b8b1ebe..32cb1152d 100644 --- a/server/shadow/shadow_client.c +++ b/server/shadow/shadow_client.c @@ -736,10 +736,144 @@ int shadow_client_surface_update(rdpShadowClient* client, REGION16* region) return 1; } +int shadow_client_convert_alpha_pointer_data(BYTE* pixels, BOOL premultiplied, + UINT32 width, UINT32 height, POINTER_COLOR_UPDATE* pointerColor) +{ + UINT32 x, y; + BYTE* pSrc8; + BYTE* pDst8; + int xorStep; + int andStep; + UINT32 andBit; + BYTE* andBits; + UINT32 andPixel; + BYTE A, R, G, B; + + xorStep = (width * 3); + xorStep += (xorStep % 2); + + andStep = ((width + 7) / 8); + andStep += (andStep % 2); + + pointerColor->lengthXorMask = height * xorStep; + pointerColor->xorMaskData = (BYTE*) calloc(1, pointerColor->lengthXorMask); + + if (!pointerColor->xorMaskData) + return -1; + + pointerColor->lengthAndMask = height * andStep; + pointerColor->andMaskData = (BYTE*) calloc(1, pointerColor->lengthAndMask); + + if (!pointerColor->andMaskData) + return -1; + + for (y = 0; y < height; y++) + { + pSrc8 = &pixels[(width * 4) * (height - 1 - y)]; + pDst8 = &(pointerColor->xorMaskData[y * xorStep]); + + andBit = 0x80; + andBits = &(pointerColor->andMaskData[andStep * y]); + + for (x = 0; x < width; x++) + { + B = *pSrc8++; + G = *pSrc8++; + R = *pSrc8++; + A = *pSrc8++; + + andPixel = 0; + + if (A < 64) + A = 0; /* pixel cannot be partially transparent */ + + if (!A) + { + /* transparent pixel: XOR = black, AND = 1 */ + andPixel = 1; + B = G = R = 0; + } + else + { + if (premultiplied) + { + B = (B * 0xFF ) / A; + G = (G * 0xFF ) / A; + R = (R * 0xFF ) / A; + } + } + + *pDst8++ = B; + *pDst8++ = G; + *pDst8++ = R; + + if (andPixel) *andBits |= andBit; + if (!(andBit >>= 1)) { andBits++; andBit = 0x80; } + } + } + + return 1; +} + +int shadow_client_subsystem_process_message(rdpShadowClient* client, wMessage* message) +{ + rdpContext* context = (rdpContext*) client; + rdpUpdate* update = context->update; + + /* FIXME: the pointer updates appear to be broken when used with bulk compression and mstsc */ + + if (message->id == SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID) + { + POINTER_POSITION_UPDATE pointerPosition; + SHADOW_MSG_OUT_POINTER_POSITION_UPDATE* msg = (SHADOW_MSG_OUT_POINTER_POSITION_UPDATE*) message->wParam; + + pointerPosition.xPos = msg->xPos; + pointerPosition.yPos = msg->yPos; + + if (0) + { + IFCALL(update->pointer->PointerPosition, context, &pointerPosition); + } + + free(msg); + } + else if (message->id == SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID) + { + POINTER_NEW_UPDATE pointerNew; + POINTER_COLOR_UPDATE* pointerColor; + SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE* msg = (SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE*) message->wParam; + + ZeroMemory(&pointerNew, sizeof(POINTER_NEW_UPDATE)); + + pointerNew.xorBpp = 24; + pointerColor = &(pointerNew.colorPtrAttr); + + pointerColor->cacheIndex = 0; + pointerColor->xPos = msg->xHot; + pointerColor->yPos = msg->yHot; + pointerColor->width = msg->width; + pointerColor->height = msg->height; + + shadow_client_convert_alpha_pointer_data(msg->pixels, msg->premultiplied, + msg->width, msg->height, pointerColor); + + if (0) + { + IFCALL(update->pointer->PointerNew, context, &pointerNew); + } + + free(msg->pixels); + free(msg); + } + + return 1; +} + void* shadow_client_thread(rdpShadowClient* client) { DWORD status; DWORD nCount; + wMessage message; HANDLE events[32]; HANDLE StopEvent; HANDLE ClientEvent; @@ -752,6 +886,7 @@ void* shadow_client_thread(rdpShadowClient* client) rdpShadowScreen* screen; rdpShadowEncoder* encoder; rdpShadowSubsystem* subsystem; + wMessagePipe* MsgPipe = client->subsystem->MsgPipe; server = client->server; screen = server->screen; @@ -786,6 +921,7 @@ void* shadow_client_thread(rdpShadowClient* client) events[nCount++] = UpdateEvent; events[nCount++] = ClientEvent; events[nCount++] = ChannelEvent; + events[nCount++] = MessageQueue_Event(MsgPipe->Out); status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); @@ -833,12 +969,23 @@ void* shadow_client_thread(rdpShadowClient* client) if (WaitForSingleObject(ChannelEvent, 0) == WAIT_OBJECT_0) { - if (WTSVirtualChannelManagerCheckFileDescriptor(client->vcm) != TRUE) + if (!WTSVirtualChannelManagerCheckFileDescriptor(client->vcm)) { WLog_ERR(TAG, "WTSVirtualChannelManagerCheckFileDescriptor failure"); break; } } + + if (WaitForSingleObject(MessageQueue_Event(MsgPipe->Out), 0) == WAIT_OBJECT_0) + { + if (MessageQueue_Peek(MsgPipe->Out, &message, TRUE)) + { + if (message.id == WMQ_QUIT) + break; + + shadow_client_subsystem_process_message(client, &message); + } + } } peer->Disconnect(peer); diff --git a/server/shadow/shadow_subsystem.h b/server/shadow/shadow_subsystem.h index 2ddbce864..9ad710475 100644 --- a/server/shadow/shadow_subsystem.h +++ b/server/shadow/shadow_subsystem.h @@ -41,6 +41,28 @@ struct _SHADOW_MSG_IN_SUPPRESS_OUTPUT }; typedef struct _SHADOW_MSG_IN_SUPPRESS_OUTPUT SHADOW_MSG_IN_SUPPRESS_OUTPUT; +#define SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID 2001 +#define SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID 2002 + +struct _SHADOW_MSG_OUT_POINTER_POSITION_UPDATE +{ + UINT32 xPos; + UINT32 yPos; +}; +typedef struct _SHADOW_MSG_OUT_POINTER_POSITION_UPDATE SHADOW_MSG_OUT_POINTER_POSITION_UPDATE; + +struct _SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE +{ + UINT32 xHot; + UINT32 yHot; + UINT32 width; + UINT32 height; + BYTE* pixels; + int scanline; + BOOL premultiplied; +}; +typedef struct _SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE; + #ifdef __cplusplus extern "C" { #endif