2 * FreeRDP: A Remote Desktop Protocol Implementation
4 * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
23 #include <winpr/crt.h>
24 #include <winpr/file.h>
25 #include <winpr/path.h>
26 #include <winpr/synch.h>
27 #include <winpr/thread.h>
28 #include <winpr/sysinfo.h>
30 #include <freerdp/log.h>
34 #define TAG CLIENT_TAG("shadow")
36 BOOL shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client)
38 rdpSettings* settings;
39 rdpShadowServer* server;
41 server = (rdpShadowServer*) peer->ContextExtra;
42 client->server = server;
43 client->subsystem = server->subsystem;
45 settings = peer->settings;
47 settings->ColorDepth = 32;
48 settings->NSCodec = TRUE;
49 settings->RemoteFxCodec = TRUE;
50 settings->BitmapCacheV3Enabled = TRUE;
51 settings->FrameMarkerCommandEnabled = TRUE;
52 settings->SurfaceFrameMarkerEnabled = TRUE;
53 settings->SupportGraphicsPipeline = FALSE;
55 settings->DrawAllowSkipAlpha = TRUE;
56 settings->DrawAllowColorSubsampling = TRUE;
57 settings->DrawAllowDynamicColorFidelity = TRUE;
59 settings->CompressionLevel = PACKET_COMPR_TYPE_RDP6;
61 settings->RdpSecurity = TRUE;
62 settings->TlsSecurity = TRUE;
63 settings->NlaSecurity = FALSE;
65 if (!(settings->CertificateFile = _strdup(server->CertificateFile)))
67 if (!(settings->PrivateKeyFile = _strdup(server->PrivateKeyFile)))
68 goto fail_privkey_file;
69 if (!(settings->RdpKeyFile = _strdup(settings->PrivateKeyFile)))
70 goto fail_rdpkey_file;
73 if (server->ipcSocket)
75 settings->LyncRdpMode = TRUE;
76 settings->CompressionEnabled = FALSE;
79 client->inLobby = TRUE;
80 client->mayView = server->mayView;
81 client->mayInteract = server->mayInteract;
83 if (!InitializeCriticalSectionAndSpinCount(&(client->lock), 4000))
84 goto fail_client_lock;
86 region16_init(&(client->invalidRegion));
88 client->vcm = WTSOpenServerA((LPSTR) peer->context);
89 if (!client->vcm || client->vcm == INVALID_HANDLE_VALUE)
90 goto fail_open_server;
92 if (!(client->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
95 if (!(client->encoder = shadow_encoder_new(client)))
96 goto fail_encoder_new;
98 if (ArrayList_Add(server->clients, (void*) client) >= 0)
101 shadow_encoder_free(client->encoder);
102 client->encoder = NULL;
104 CloseHandle(client->StopEvent);
105 client->StopEvent = NULL;
107 WTSCloseServer((HANDLE) client->vcm);
110 DeleteCriticalSection(&(client->lock));
112 free(settings->RdpKeyFile);
113 settings->RdpKeyFile = NULL;
115 free(settings->PrivateKeyFile);
116 settings->PrivateKeyFile = NULL;
118 free(settings->CertificateFile);
119 settings->CertificateFile = NULL;
125 void shadow_client_context_free(freerdp_peer* peer, rdpShadowClient* client)
127 rdpShadowServer* server = client->server;
129 ArrayList_Remove(server->clients, (void*) client);
131 DeleteCriticalSection(&(client->lock));
133 region16_uninit(&(client->invalidRegion));
135 WTSCloseServer((HANDLE) client->vcm);
137 CloseHandle(client->StopEvent);
141 shadow_surface_free(client->lobby);
142 client->lobby = NULL;
147 shadow_encoder_free(client->encoder);
148 client->encoder = NULL;
151 shadow_client_encomsp_uninit(client);
153 shadow_client_remdesk_uninit(client);
156 void shadow_client_message_free(wMessage* message)
158 if (message->id == SHADOW_MSG_IN_REFRESH_OUTPUT_ID)
160 SHADOW_MSG_IN_REFRESH_OUTPUT* wParam = (SHADOW_MSG_IN_REFRESH_OUTPUT*) message->wParam;
165 else if (message->id == SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID)
167 SHADOW_MSG_IN_SUPPRESS_OUTPUT* wParam = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) message->wParam;
172 BOOL shadow_client_capabilities(freerdp_peer* peer)
177 BOOL shadow_client_post_connect(freerdp_peer* peer)
181 rdpSettings* settings;
182 rdpShadowClient* client;
183 rdpShadowServer* server;
184 RECTANGLE_16 invalidRect;
185 rdpShadowSubsystem* subsystem;
187 client = (rdpShadowClient*) peer->context;
188 settings = peer->settings;
189 server = client->server;
190 subsystem = server->subsystem;
192 if (!server->shareSubRect)
194 width = server->screen->width;
195 height = server->screen->height;
199 width = server->subRect.right - server->subRect.left;
200 height = server->subRect.bottom - server->subRect.top;
203 settings->DesktopWidth = width;
204 settings->DesktopHeight = height;
206 if (settings->ColorDepth == 24)
207 settings->ColorDepth = 16; /* disable 24bpp */
209 if (settings->MultifragMaxRequestSize < 0x3F0000)
210 settings->NSCodec = FALSE; /* NSCodec compressor does not support fragmentation yet */
212 WLog_ERR(TAG, "Client from %s is activated (%dx%d@%d)",
213 peer->hostname, settings->DesktopWidth, settings->DesktopHeight, settings->ColorDepth);
215 peer->update->DesktopResize(peer->update->context);
217 shadow_client_channels_post_connect(client);
219 invalidRect.left = 0;
221 invalidRect.right = width;
222 invalidRect.bottom = height;
224 region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &invalidRect);
226 shadow_client_init_lobby(client);
230 if (settings->Username && settings->Password)
231 settings->AutoLogonEnabled = TRUE;
233 if (settings->AutoLogonEnabled && server->authentication)
235 if (subsystem->Authenticate)
237 authStatus = subsystem->Authenticate(subsystem,
238 settings->Username, settings->Domain, settings->Password);
242 if (server->authentication)
246 WLog_ERR(TAG, "client authentication failure: %d", authStatus);
254 BOOL shadow_client_refresh_rect(rdpShadowClient* client, BYTE count, RECTANGLE_16* areas)
256 wMessage message = { 0 };
257 SHADOW_MSG_IN_REFRESH_OUTPUT* wParam;
258 wMessagePipe* MsgPipe = client->subsystem->MsgPipe;
263 if (!(wParam = (SHADOW_MSG_IN_REFRESH_OUTPUT*) calloc(1, sizeof(SHADOW_MSG_IN_REFRESH_OUTPUT))))
266 wParam->numRects = (UINT32) count;
268 if (wParam->numRects)
270 wParam->rects = (RECTANGLE_16*) calloc(wParam->numRects, sizeof(RECTANGLE_16));
279 CopyMemory(wParam->rects, areas, wParam->numRects * sizeof(RECTANGLE_16));
281 message.id = SHADOW_MSG_IN_REFRESH_OUTPUT_ID;
282 message.wParam = (void*) wParam;
283 message.lParam = NULL;
284 message.context = (void*) client;
285 message.Free = shadow_client_message_free;
287 return MessageQueue_Dispatch(MsgPipe->In, &message);
290 BOOL shadow_client_suppress_output(rdpShadowClient* client, BYTE allow, RECTANGLE_16* area)
292 wMessage message = { 0 };
293 SHADOW_MSG_IN_SUPPRESS_OUTPUT* wParam;
294 wMessagePipe* MsgPipe = client->subsystem->MsgPipe;
296 wParam = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) calloc(1, sizeof(SHADOW_MSG_IN_SUPPRESS_OUTPUT));
300 wParam->allow = (UINT32) allow;
303 CopyMemory(&(wParam->rect), area, sizeof(RECTANGLE_16));
305 message.id = SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID;
306 message.wParam = (void*) wParam;
307 message.lParam = NULL;
308 message.context = (void*) client;
309 message.Free = shadow_client_message_free;
311 return MessageQueue_Dispatch(MsgPipe->In, &message);
314 BOOL shadow_client_activate(freerdp_peer* peer)
316 rdpSettings* settings = peer->settings;
317 rdpShadowClient* client = (rdpShadowClient*) peer->context;
319 if (settings->ClientDir && (strcmp(settings->ClientDir, "librdp") == 0))
321 /* Hack for Mac/iOS/Android Microsoft RDP clients */
323 settings->RemoteFxCodec = FALSE;
325 settings->NSCodec = FALSE;
326 settings->NSCodecAllowSubsampling = FALSE;
328 settings->SurfaceFrameMarkerEnabled = FALSE;
331 client->activated = TRUE;
332 client->inLobby = client->mayView ? FALSE : TRUE;
334 shadow_encoder_reset(client->encoder);
336 return shadow_client_refresh_rect(client, 0, NULL);
339 BOOL shadow_client_surface_frame_acknowledge(rdpShadowClient* client, UINT32 frameId)
341 SURFACE_FRAME* frame;
342 wListDictionary* frameList;
344 frameList = client->encoder->frameList;
345 frame = (SURFACE_FRAME*) ListDictionary_GetItemValue(frameList, (void*) (size_t) frameId);
349 ListDictionary_Remove(frameList, (void*) (size_t) frameId);
355 int shadow_client_send_surface_frame_marker(rdpShadowClient* client, UINT32 action, UINT32 id)
357 SURFACE_FRAME_MARKER surfaceFrameMarker;
358 rdpContext* context = (rdpContext*) client;
359 rdpUpdate* update = context->update;
361 surfaceFrameMarker.frameAction = action;
362 surfaceFrameMarker.frameId = id;
364 IFCALL(update->SurfaceFrameMarker, context, &surfaceFrameMarker);
369 int shadow_client_send_surface_bits(rdpShadowClient* client, rdpShadowSurface* surface, int nXSrc, int nYSrc, int nWidth, int nHeight)
381 rdpSettings* settings;
382 rdpShadowServer* server;
383 rdpShadowEncoder* encoder;
384 SURFACE_BITS_COMMAND cmd;
386 context = (rdpContext*) client;
387 update = context->update;
388 settings = context->settings;
390 server = client->server;
391 encoder = client->encoder;
393 pSrcData = surface->data;
394 nSrcStep = surface->scanline;
396 if (server->shareSubRect)
399 int subWidth, subHeight;
401 subX = server->subRect.left;
402 subY = server->subRect.top;
403 subWidth = server->subRect.right - server->subRect.left;
404 subHeight = server->subRect.bottom - server->subRect.top;
408 pSrcData = &pSrcData[(subY * nSrcStep) + (subX * 4)];
411 if (encoder->frameAck)
412 frameId = (UINT32) shadow_encoder_create_frame_id(encoder);
414 if (settings->RemoteFxCodec)
417 RFX_MESSAGE* messages;
418 RFX_RECT *messageRects = NULL;
420 shadow_encoder_prepare(encoder, FREERDP_CODEC_REMOTEFX);
427 rect.height = nHeight;
429 if (!(messages = rfx_encode_messages(encoder->rfx, &rect, 1, pSrcData,
430 surface->width, surface->height, nSrcStep, &numMessages,
431 settings->MultifragMaxRequestSize)))
436 cmd.codecID = settings->RemoteFxCodecId;
440 cmd.destRight = surface->width;
441 cmd.destBottom = surface->height;
444 cmd.width = surface->width;
445 cmd.height = surface->height;
446 cmd.skipCompression = TRUE;
449 messageRects = messages[0].rects;
451 for (i = 0; i < numMessages; i++)
453 Stream_SetPosition(s, 0);
454 if (!rfx_write_message(encoder->rfx, s, &messages[i]))
456 while (i < numMessages)
458 rfx_message_free(encoder->rfx, &messages[i++]);
462 rfx_message_free(encoder->rfx, &messages[i]);
464 cmd.bitmapDataLength = Stream_GetPosition(s);
465 cmd.bitmapData = Stream_Buffer(s);
467 first = (i == 0) ? TRUE : FALSE;
468 last = ((i + 1) == numMessages) ? TRUE : FALSE;
470 if (!encoder->frameAck)
471 IFCALL(update->SurfaceBits, update->context, &cmd);
473 IFCALL(update->SurfaceFrameBits, update->context, &cmd, first, last, frameId);
479 else if (settings->NSCodec)
481 shadow_encoder_prepare(encoder, FREERDP_CODEC_NSCODEC);
484 Stream_SetPosition(s, 0);
486 pSrcData = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 4)];
488 nsc_compose_message(encoder->nsc, s, pSrcData, nWidth, nHeight, nSrcStep);
491 cmd.codecID = settings->NSCodecId;
492 cmd.destLeft = nXSrc;
494 cmd.destRight = cmd.destLeft + nWidth;
495 cmd.destBottom = cmd.destTop + nHeight;
497 cmd.height = nHeight;
499 cmd.bitmapDataLength = Stream_GetPosition(s);
500 cmd.bitmapData = Stream_Buffer(s);
505 if (!encoder->frameAck)
506 IFCALL(update->SurfaceBits, update->context, &cmd);
508 IFCALL(update->SurfaceFrameBits, update->context, &cmd, first, last, frameId);
514 int shadow_client_send_bitmap_update(rdpShadowClient* client, rdpShadowSurface* surface, int nXSrc, int nYSrc, int nWidth, int nHeight)
527 rdpSettings* settings;
528 UINT32 maxUpdateSize;
529 UINT32 totalBitmapSize;
530 UINT32 updateSizeEstimate;
531 BITMAP_DATA* bitmapData;
532 BITMAP_UPDATE bitmapUpdate;
533 rdpShadowServer* server;
534 rdpShadowEncoder* encoder;
536 context = (rdpContext*) client;
537 update = context->update;
538 settings = context->settings;
540 server = client->server;
541 encoder = client->encoder;
543 maxUpdateSize = settings->MultifragMaxRequestSize;
545 if (settings->ColorDepth < 32)
546 shadow_encoder_prepare(encoder, FREERDP_CODEC_INTERLEAVED);
548 shadow_encoder_prepare(encoder, FREERDP_CODEC_PLANAR);
550 pSrcData = surface->data;
551 nSrcStep = surface->scanline;
552 SrcFormat = PIXEL_FORMAT_RGB32;
554 if ((nXSrc % 4) != 0)
556 nWidth += (nXSrc % 4);
557 nXSrc -= (nXSrc % 4);
560 if ((nYSrc % 4) != 0)
562 nHeight += (nYSrc % 4);
563 nYSrc -= (nYSrc % 4);
566 rows = (nHeight / 64) + ((nHeight % 64) ? 1 : 0);
567 cols = (nWidth / 64) + ((nWidth % 64) ? 1 : 0);
572 bitmapUpdate.count = bitmapUpdate.number = rows * cols;
573 bitmapData = (BITMAP_DATA*) malloc(sizeof(BITMAP_DATA) * bitmapUpdate.number);
574 bitmapUpdate.rectangles = bitmapData;
579 if ((nWidth % 4) != 0)
581 nXSrc -= (nWidth % 4);
582 nWidth += (nWidth % 4);
585 if ((nHeight % 4) != 0)
587 nYSrc -= (nHeight % 4);
588 nHeight += (nHeight % 4);
591 for (yIdx = 0; yIdx < rows; yIdx++)
593 for (xIdx = 0; xIdx < cols; xIdx++)
595 bitmap = &bitmapData[k];
599 bitmap->destLeft = nXSrc + (xIdx * 64);
600 bitmap->destTop = nYSrc + (yIdx * 64);
602 if ((bitmap->destLeft + bitmap->width) > (nXSrc + nWidth))
603 bitmap->width = (nXSrc + nWidth) - bitmap->destLeft;
605 if ((bitmap->destTop + bitmap->height) > (nYSrc + nHeight))
606 bitmap->height = (nYSrc + nHeight) - bitmap->destTop;
608 bitmap->destRight = bitmap->destLeft + bitmap->width - 1;
609 bitmap->destBottom = bitmap->destTop + bitmap->height - 1;
610 bitmap->compressed = TRUE;
612 if ((bitmap->width < 4) || (bitmap->height < 4))
615 if (settings->ColorDepth < 32)
617 int bitsPerPixel = settings->ColorDepth;
618 int bytesPerPixel = (bitsPerPixel + 7) / 8;
620 DstSize = 64 * 64 * 4;
621 buffer = encoder->grid[k];
623 interleaved_compress(encoder->interleaved, buffer, &DstSize, bitmap->width, bitmap->height,
624 pSrcData, SrcFormat, nSrcStep, bitmap->destLeft, bitmap->destTop, NULL, bitsPerPixel);
626 bitmap->bitmapDataStream = buffer;
627 bitmap->bitmapLength = DstSize;
628 bitmap->bitsPerPixel = bitsPerPixel;
629 bitmap->cbScanWidth = bitmap->width * bytesPerPixel;
630 bitmap->cbUncompressedSize = bitmap->width * bitmap->height * bytesPerPixel;
636 buffer = encoder->grid[k];
637 data = &pSrcData[(bitmap->destTop * nSrcStep) + (bitmap->destLeft * 4)];
639 buffer = freerdp_bitmap_compress_planar(encoder->planar, data, SrcFormat,
640 bitmap->width, bitmap->height, nSrcStep, buffer, &dstSize);
642 bitmap->bitmapDataStream = buffer;
643 bitmap->bitmapLength = dstSize;
644 bitmap->bitsPerPixel = 32;
645 bitmap->cbScanWidth = bitmap->width * 4;
646 bitmap->cbUncompressedSize = bitmap->width * bitmap->height * 4;
649 bitmap->cbCompFirstRowSize = 0;
650 bitmap->cbCompMainBodySize = bitmap->bitmapLength;
652 totalBitmapSize += bitmap->bitmapLength;
657 bitmapUpdate.count = bitmapUpdate.number = k;
659 updateSizeEstimate = totalBitmapSize + (k * bitmapUpdate.count) + 16;
661 if (updateSizeEstimate > maxUpdateSize)
665 UINT32 newUpdateSize;
666 BITMAP_DATA* fragBitmapData;
668 fragBitmapData = (BITMAP_DATA*) malloc(sizeof(BITMAP_DATA) * k);
669 bitmapUpdate.rectangles = fragBitmapData;
676 newUpdateSize = updateSize + (bitmapData[i].bitmapLength + 16);
678 if ((newUpdateSize < maxUpdateSize) && ((i + 1) < k))
680 CopyMemory(&fragBitmapData[j++], &bitmapData[i++], sizeof(BITMAP_DATA));
681 updateSize = newUpdateSize;
687 CopyMemory(&fragBitmapData[j++], &bitmapData[i++], sizeof(BITMAP_DATA));
688 updateSize = newUpdateSize;
691 bitmapUpdate.count = bitmapUpdate.number = j;
692 IFCALL(update->BitmapUpdate, context, &bitmapUpdate);
698 free(fragBitmapData);
702 IFCALL(update->BitmapUpdate, context, &bitmapUpdate);
710 int shadow_client_send_surface_update(rdpShadowClient* client)
716 rdpSettings* settings;
717 rdpShadowServer* server;
718 rdpShadowSurface* surface;
719 rdpShadowEncoder* encoder;
720 REGION16 invalidRegion;
721 RECTANGLE_16 surfaceRect;
722 const RECTANGLE_16* extents;
724 context = (rdpContext*) client;
725 settings = context->settings;
726 server = client->server;
727 encoder = client->encoder;
729 surface = client->inLobby ? client->lobby : server->surface;
731 EnterCriticalSection(&(client->lock));
733 region16_init(&invalidRegion);
734 region16_copy(&invalidRegion, &(client->invalidRegion));
735 region16_clear(&(client->invalidRegion));
737 LeaveCriticalSection(&(client->lock));
739 surfaceRect.left = 0;
741 surfaceRect.right = surface->width;
742 surfaceRect.bottom = surface->height;
744 region16_intersect_rect(&invalidRegion, &invalidRegion, &surfaceRect);
746 if (server->shareSubRect)
748 region16_intersect_rect(&invalidRegion, &invalidRegion, &(server->subRect));
751 if (region16_is_empty(&invalidRegion))
753 region16_uninit(&invalidRegion);
757 extents = region16_extents(&invalidRegion);
759 nXSrc = extents->left - 0;
760 nYSrc = extents->top - 0;
761 nWidth = extents->right - extents->left;
762 nHeight = extents->bottom - extents->top;
764 //WLog_INFO(TAG, "shadow_client_send_surface_update: x: %d y: %d width: %d height: %d right: %d bottom: %d",
765 // nXSrc, nYSrc, nWidth, nHeight, nXSrc + nWidth, nYSrc + nHeight);
767 if (settings->RemoteFxCodec || settings->NSCodec)
769 status = shadow_client_send_surface_bits(client, surface, nXSrc, nYSrc, nWidth, nHeight);
773 status = shadow_client_send_bitmap_update(client, surface, nXSrc, nYSrc, nWidth, nHeight);
776 region16_uninit(&invalidRegion);
781 int shadow_client_surface_update(rdpShadowClient* client, REGION16* region)
785 const RECTANGLE_16* rects;
787 EnterCriticalSection(&(client->lock));
789 rects = region16_rects(region, &numRects);
791 for (index = 0; index < numRects; index++)
793 region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &rects[index]);
796 LeaveCriticalSection(&(client->lock));
801 int shadow_client_convert_alpha_pointer_data(BYTE* pixels, BOOL premultiplied,
802 UINT32 width, UINT32 height, POINTER_COLOR_UPDATE* pointerColor)
814 xorStep = (width * 3);
815 xorStep += (xorStep % 2);
817 andStep = ((width + 7) / 8);
818 andStep += (andStep % 2);
820 pointerColor->lengthXorMask = height * xorStep;
821 pointerColor->xorMaskData = (BYTE*) calloc(1, pointerColor->lengthXorMask);
823 if (!pointerColor->xorMaskData)
826 pointerColor->lengthAndMask = height * andStep;
827 pointerColor->andMaskData = (BYTE*) calloc(1, pointerColor->lengthAndMask);
829 if (!pointerColor->andMaskData)
832 for (y = 0; y < height; y++)
834 pSrc8 = &pixels[(width * 4) * (height - 1 - y)];
835 pDst8 = &(pointerColor->xorMaskData[y * xorStep]);
838 andBits = &(pointerColor->andMaskData[andStep * y]);
840 for (x = 0; x < width; x++)
850 A = 0; /* pixel cannot be partially transparent */
854 /* transparent pixel: XOR = black, AND = 1 */
872 if (andPixel) *andBits |= andBit;
873 if (!(andBit >>= 1)) { andBits++; andBit = 0x80; }
880 int shadow_client_subsystem_process_message(rdpShadowClient* client, wMessage* message)
882 rdpContext* context = (rdpContext*) client;
883 rdpUpdate* update = context->update;
885 /* FIXME: the pointer updates appear to be broken when used with bulk compression and mstsc */
887 if (message->id == SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID)
889 POINTER_POSITION_UPDATE pointerPosition;
890 SHADOW_MSG_OUT_POINTER_POSITION_UPDATE* msg = (SHADOW_MSG_OUT_POINTER_POSITION_UPDATE*) message->wParam;
892 pointerPosition.xPos = msg->xPos;
893 pointerPosition.yPos = msg->yPos;
895 if (client->activated)
897 if ((msg->xPos != client->pointerX) || (msg->yPos != client->pointerY))
899 IFCALL(update->pointer->PointerPosition, context, &pointerPosition);
901 client->pointerX = msg->xPos;
902 client->pointerY = msg->yPos;
908 else if (message->id == SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID)
910 POINTER_NEW_UPDATE pointerNew;
911 POINTER_COLOR_UPDATE* pointerColor;
912 POINTER_CACHED_UPDATE pointerCached;
913 SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE* msg = (SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE*) message->wParam;
915 ZeroMemory(&pointerNew, sizeof(POINTER_NEW_UPDATE));
917 pointerNew.xorBpp = 24;
918 pointerColor = &(pointerNew.colorPtrAttr);
920 pointerColor->cacheIndex = 0;
921 pointerColor->xPos = msg->xHot;
922 pointerColor->yPos = msg->yHot;
923 pointerColor->width = msg->width;
924 pointerColor->height = msg->height;
926 pointerCached.cacheIndex = pointerColor->cacheIndex;
928 if (client->activated)
930 shadow_client_convert_alpha_pointer_data(msg->pixels, msg->premultiplied,
931 msg->width, msg->height, pointerColor);
933 IFCALL(update->pointer->PointerNew, context, &pointerNew);
934 IFCALL(update->pointer->PointerCached, context, &pointerCached);
936 free(pointerColor->xorMaskData);
937 free(pointerColor->andMaskData);
947 void* shadow_client_thread(rdpShadowClient* client)
956 void* UpdateSubscriber;
960 rdpSettings* settings;
961 rdpShadowServer* server;
962 rdpShadowScreen* screen;
963 rdpShadowEncoder* encoder;
964 rdpShadowSubsystem* subsystem;
965 wMessagePipe* MsgPipe = client->subsystem->MsgPipe;
967 server = client->server;
968 screen = server->screen;
969 encoder = client->encoder;
970 subsystem = server->subsystem;
972 context = (rdpContext*) client;
973 peer = context->peer;
974 settings = peer->settings;
976 peer->Capabilities = shadow_client_capabilities;
977 peer->PostConnect = shadow_client_post_connect;
978 peer->Activate = shadow_client_activate;
980 shadow_input_register_callbacks(peer->input);
982 peer->Initialize(peer);
984 peer->update->RefreshRect = (pRefreshRect)shadow_client_refresh_rect;
985 peer->update->SuppressOutput = (pSuppressOutput)shadow_client_suppress_output;
986 peer->update->SurfaceFrameAcknowledge = (pSurfaceFrameAcknowledge)shadow_client_surface_frame_acknowledge;
988 if ((!client->StopEvent) || (!client->vcm) || (!subsystem->updateEvent))
991 UpdateSubscriber = shadow_multiclient_get_subscriber(subsystem->updateEvent);
992 if (!UpdateSubscriber)
995 StopEvent = client->StopEvent;
996 UpdateEvent = shadow_multiclient_getevent(UpdateSubscriber);
997 ClientEvent = peer->GetEventHandle(peer);
998 ChannelEvent = WTSVirtualChannelManagerGetEventHandle(client->vcm);
1003 events[nCount++] = StopEvent;
1004 events[nCount++] = UpdateEvent;
1005 events[nCount++] = ClientEvent;
1006 events[nCount++] = ChannelEvent;
1007 events[nCount++] = MessageQueue_Event(MsgPipe->Out);
1009 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
1011 if (WaitForSingleObject(StopEvent, 0) == WAIT_OBJECT_0)
1016 if (WaitForSingleObject(UpdateEvent, 0) == WAIT_OBJECT_0)
1018 if (client->activated)
1022 const RECTANGLE_16* rects;
1024 rects = region16_rects(&(subsystem->invalidRegion), &numRects);
1026 for (index = 0; index < numRects; index++)
1028 region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &rects[index]);
1031 shadow_client_send_surface_update(client);
1035 * The return value of shadow_multiclient_consume is whether or not the subscriber really consumes the event.
1036 * It's not cared currently.
1038 (void)shadow_multiclient_consume(UpdateSubscriber);
1041 if (WaitForSingleObject(ClientEvent, 0) == WAIT_OBJECT_0)
1043 if (!peer->CheckFileDescriptor(peer))
1045 WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
1050 if (WaitForSingleObject(ChannelEvent, 0) == WAIT_OBJECT_0)
1052 if (!WTSVirtualChannelManagerCheckFileDescriptor(client->vcm))
1054 WLog_ERR(TAG, "WTSVirtualChannelManagerCheckFileDescriptor failure");
1059 if (WaitForSingleObject(MessageQueue_Event(MsgPipe->Out), 0) == WAIT_OBJECT_0)
1061 if (MessageQueue_Peek(MsgPipe->Out, &message, TRUE))
1063 if (message.id == WMQ_QUIT)
1066 shadow_client_subsystem_process_message(client, &message);
1071 if (UpdateSubscriber)
1073 shadow_multiclient_release_subscriber(UpdateSubscriber);
1074 UpdateSubscriber = NULL;
1078 peer->Disconnect(peer);
1080 freerdp_peer_context_free(peer);
1081 freerdp_peer_free(peer);
1086 BOOL shadow_client_accepted(freerdp_listener* listener, freerdp_peer* peer)
1088 rdpShadowClient* client;
1089 rdpShadowServer* server;
1091 server = (rdpShadowServer*) listener->info;
1093 peer->ContextExtra = (void*) server;
1094 peer->ContextSize = sizeof(rdpShadowClient);
1095 peer->ContextNew = (psPeerContextNew) shadow_client_context_new;
1096 peer->ContextFree = (psPeerContextFree) shadow_client_context_free;
1098 if (!freerdp_peer_context_new(peer))
1101 client = (rdpShadowClient*) peer->context;
1103 if (!(client->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)
1104 shadow_client_thread, client, 0, NULL)))
1106 freerdp_peer_context_free(peer);