diff --git a/include/freerdp/codec/region.h b/include/freerdp/codec/region.h index 44bfb2558..bced79140 100644 --- a/include/freerdp/codec/region.h +++ b/include/freerdp/codec/region.h @@ -43,6 +43,13 @@ struct _REGION16 { }; typedef struct _REGION16 REGION16; +/** computes if two rectangles are equal + * @param r1 first rectangle + * @param r2 second rectangle + * @return if the two rectangles are equal + */ +FREERDP_API BOOL rectangles_equal(const RECTANGLE_16 *r1, const RECTANGLE_16 *r2); + /** computes if two rectangles intersect * @param r1 first rectangle * @param r2 second rectangle diff --git a/include/freerdp/server/shadow.h b/include/freerdp/server/shadow.h index 496342965..f76f5e2f7 100644 --- a/include/freerdp/server/shadow.h +++ b/include/freerdp/server/shadow.h @@ -50,7 +50,7 @@ typedef struct rdp_shadow_subsystem rdpShadowSubsystem; typedef struct _RDP_SHADOW_ENTRY_POINTS RDP_SHADOW_ENTRY_POINTS; typedef int (*pfnShadowSubsystemEntry)(RDP_SHADOW_ENTRY_POINTS* pEntryPoints); -typedef rdpShadowSubsystem* (*pfnShadowSubsystemNew)(); +typedef rdpShadowSubsystem* (*pfnShadowSubsystemNew)(void); typedef void (*pfnShadowSubsystemFree)(rdpShadowSubsystem* subsystem); typedef int (*pfnShadowSubsystemInit)(rdpShadowSubsystem* subsystem); @@ -61,9 +61,6 @@ typedef int (*pfnShadowSubsystemStop)(rdpShadowSubsystem* subsystem); typedef int (*pfnShadowEnumMonitors)(MONITOR_DEF* monitors, int maxMonitors); -typedef int (*pfnShadowSurfaceCopy)(rdpShadowSubsystem* subsystem); -typedef int (*pfnShadowSurfaceUpdate)(rdpShadowSubsystem* subsystem, REGION16* subRect); - typedef int (*pfnShadowSynchronizeEvent)(rdpShadowSubsystem* subsystem, UINT32 flags); typedef int (*pfnShadowKeyboardEvent)(rdpShadowSubsystem* subsystem, UINT16 flags, UINT16 code); typedef int (*pfnShadowUnicodeKeyboardEvent)(rdpShadowSubsystem* subsystem, UINT16 flags, UINT16 code); @@ -139,6 +136,7 @@ struct _RDP_SHADOW_ENTRY_POINTS MONITOR_DEF monitors[16]; \ MONITOR_DEF virtualScreen; \ HANDLE updateEvent; \ + BOOL suppressOutput; \ REGION16 invalidRegion; \ wMessagePipe* MsgPipe; \ SYNCHRONIZATION_BARRIER barrier; \ diff --git a/libfreerdp/codec/region.c b/libfreerdp/codec/region.c index c1d433760..79f00147a 100644 --- a/libfreerdp/codec/region.c +++ b/libfreerdp/codec/region.c @@ -143,6 +143,12 @@ BOOL region16_is_empty(const REGION16 *region) return (region->data->nbRects == 0); } +BOOL rectangles_equal(const RECTANGLE_16 *r1, const RECTANGLE_16 *r2) +{ + return ((r1->left == r2->left) && (r1->top == r2->top) && + (r1->right == r2->right) && (r1->bottom == r2->bottom)) ? TRUE : FALSE; +} + BOOL rectangles_intersects(const RECTANGLE_16 *r1, const RECTANGLE_16 *r2) { RECTANGLE_16 tmp; diff --git a/libfreerdp/core/gcc.c b/libfreerdp/core/gcc.c index 23b14174c..79a966f8d 100644 --- a/libfreerdp/core/gcc.c +++ b/libfreerdp/core/gcc.c @@ -388,7 +388,7 @@ BOOL gcc_read_client_data_blocks(wStream* s, rdpMcs* mcs, int length) if (endPos != (begPos + blockLength)) { WLog_ERR(TAG, "Error parsing GCC client data block 0x%04X: Actual Offset: %d Expected Offset: %d", - type, endPos, begPos + blockLength); + type, endPos, begPos + blockLength); } length -= blockLength; @@ -1337,6 +1337,15 @@ BOOL gcc_read_client_cluster_data(wStream* s, rdpMcs* mcs, UINT16 blockLength) if (flags & REDIRECTED_SESSIONID_FIELD_VALID) settings->RedirectedSessionId = redirectedSessionId; + if (blockLength != 8) + { + if (Stream_GetRemainingLength(s) >= (blockLength - 8)) + { + /* The old Microsoft Mac RDP client can send a pad here */ + Stream_Seek(s, (blockLength - 8)); + } + } + return TRUE; } diff --git a/server/shadow/X11/x11_shadow.c b/server/shadow/X11/x11_shadow.c index 2dbdcec1d..1edf22abc 100644 --- a/server/shadow/X11/x11_shadow.c +++ b/server/shadow/X11/x11_shadow.c @@ -288,23 +288,6 @@ void x11_shadow_validate_region(x11ShadowSubsystem* subsystem, int x, int y, int #endif } -int x11_shadow_invalidate_region(x11ShadowSubsystem* subsystem, int x, int y, int width, int height) -{ - rdpShadowServer* server; - RECTANGLE_16 invalidRect; - - server = subsystem->server; - - invalidRect.left = x; - invalidRect.top = y; - invalidRect.right = x + width; - invalidRect.bottom = y + height; - - region16_union_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &invalidRect); - - return 1; -} - int x11_shadow_blend_cursor(x11ShadowSubsystem* subsystem) { int x, y; @@ -443,110 +426,123 @@ int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem) if (count < 1) return 1; + if ((count == 1) && subsystem->suppressOutput) + return 1; + surfaceRect.left = 0; surfaceRect.top = 0; surfaceRect.right = surface->width; surfaceRect.bottom = surface->height; + XLockDisplay(subsystem->display); + if (subsystem->use_xshm) { - XLockDisplay(subsystem->display); + image = subsystem->fb_image; XCopyArea(subsystem->display, subsystem->root_window, subsystem->fb_pixmap, subsystem->xshm_gc, 0, 0, subsystem->width, subsystem->height, 0, 0); - XSync(subsystem->display, False); - - XUnlockDisplay(subsystem->display); - - image = subsystem->fb_image; - status = shadow_capture_compare(surface->data, surface->scanline, surface->width, surface->height, (BYTE*) &(image->data[surface->width * 4]), image->bytes_per_line, &invalidRect); - - region16_union_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &invalidRect); - region16_intersect_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &surfaceRect); - - if (!region16_is_empty(&(subsystem->invalidRegion))) - { - extents = region16_extents(&(subsystem->invalidRegion)); - - x = extents->left; - y = extents->top; - width = extents->right - extents->left; - height = extents->bottom - extents->top; - - freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32, - surface->scanline, x - surface->x, y - surface->y, width, height, - (BYTE*) image->data, PIXEL_FORMAT_XRGB32, - image->bytes_per_line, x, y, NULL); - - x11_shadow_blend_cursor(subsystem); - - count = ArrayList_Count(server->clients); - - InitializeSynchronizationBarrier(&(subsystem->barrier), count + 1, -1); - - SetEvent(subsystem->updateEvent); - - EnterSynchronizationBarrier(&(subsystem->barrier), 0); - - DeleteSynchronizationBarrier(&(subsystem->barrier)); - - ResetEvent(subsystem->updateEvent); - - region16_clear(&(subsystem->invalidRegion)); - } } else { - XLockDisplay(subsystem->display); - image = XGetImage(subsystem->display, subsystem->root_window, - surface->x, surface->y, surface->width, surface->height, AllPlanes, ZPixmap); - - XUnlockDisplay(subsystem->display); + surface->x, surface->y, surface->width, surface->height, AllPlanes, ZPixmap); status = shadow_capture_compare(surface->data, surface->scanline, surface->width, surface->height, (BYTE*) image->data, image->bytes_per_line, &invalidRect); - - region16_union_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &invalidRect); - region16_intersect_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &surfaceRect); - - if (!region16_is_empty(&(subsystem->invalidRegion))) - { - extents = region16_extents(&(subsystem->invalidRegion)); - - x = extents->left; - y = extents->top; - width = extents->right - extents->left; - height = extents->bottom - extents->top; - - freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32, - surface->scanline, x, y, width, height, - (BYTE*) image->data, PIXEL_FORMAT_XRGB32, - image->bytes_per_line, x, y, NULL); - - x11_shadow_blend_cursor(subsystem); - - count = ArrayList_Count(server->clients); - - InitializeSynchronizationBarrier(&(subsystem->barrier), count + 1, -1); - - SetEvent(subsystem->updateEvent); - - EnterSynchronizationBarrier(&(subsystem->barrier), 0); - - DeleteSynchronizationBarrier(&(subsystem->barrier)); - - ResetEvent(subsystem->updateEvent); - - region16_clear(&(subsystem->invalidRegion)); - } - - XDestroyImage(image); } + XSync(subsystem->display, False); + + XUnlockDisplay(subsystem->display); + + region16_union_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &invalidRect); + region16_intersect_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &surfaceRect); + + if (!region16_is_empty(&(subsystem->invalidRegion))) + { + extents = region16_extents(&(subsystem->invalidRegion)); + + x = extents->left; + y = extents->top; + width = extents->right - extents->left; + height = extents->bottom - extents->top; + + freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32, + surface->scanline, x, y, width, height, + (BYTE*) image->data, PIXEL_FORMAT_XRGB32, + image->bytes_per_line, x, y, NULL); + + x11_shadow_blend_cursor(subsystem); + + count = ArrayList_Count(server->clients); + + InitializeSynchronizationBarrier(&(subsystem->barrier), count + 1, -1); + + SetEvent(subsystem->updateEvent); + + EnterSynchronizationBarrier(&(subsystem->barrier), 0); + + DeleteSynchronizationBarrier(&(subsystem->barrier)); + + ResetEvent(subsystem->updateEvent); + + region16_clear(&(subsystem->invalidRegion)); + } + + if (!subsystem->use_xshm) + XDestroyImage(image); + + return 1; +} + +int x11_shadow_subsystem_process_message(x11ShadowSubsystem* subsystem, wMessage* message) +{ + if (message->id == SHADOW_MSG_IN_REFRESH_OUTPUT_ID) + { + UINT32 index; + SHADOW_MSG_IN_REFRESH_OUTPUT* msg = (SHADOW_MSG_IN_REFRESH_OUTPUT*) message->wParam; + + if (msg->numRects) + { + for (index = 0; index < msg->numRects; index++) + { + region16_union_rect(&(subsystem->invalidRegion), + &(subsystem->invalidRegion), &msg->rects[index]); + } + } + else + { + RECTANGLE_16 refreshRect; + + refreshRect.left = 0; + refreshRect.top = 0; + refreshRect.right = subsystem->width; + refreshRect.bottom = subsystem->height; + + region16_union_rect(&(subsystem->invalidRegion), + &(subsystem->invalidRegion), &refreshRect); + } + } + else if (message->id == SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID) + { + SHADOW_MSG_IN_SUPPRESS_OUTPUT* msg = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) message->wParam; + + subsystem->suppressOutput = (msg->allow) ? FALSE : TRUE; + + if (msg->allow) + { + region16_union_rect(&(subsystem->invalidRegion), + &(subsystem->invalidRegion), &(msg->rect)); + } + } + + if (message->Free) + message->Free(message); + return 1; } @@ -588,24 +584,17 @@ void* x11_shadow_subsystem_thread(x11ShadowSubsystem* subsystem) if (message.id == WMQ_QUIT) break; - if (message.id == 1) - { - RECTANGLE_16 refreshRect; - - refreshRect.left = 0; - refreshRect.top = 0; - refreshRect.right = subsystem->width; - refreshRect.bottom = subsystem->height; - - region16_union_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &refreshRect); - } + x11_shadow_subsystem_process_message(subsystem, &message); } } if (WaitForSingleObject(subsystem->event, 0) == WAIT_OBJECT_0) { - XNextEvent(subsystem->display, &xevent); - x11_shadow_handle_xevent(subsystem, &xevent); + if (XEventsQueued(subsystem->display, QueuedAlready)) + { + XNextEvent(subsystem->display, &xevent); + x11_shadow_handle_xevent(subsystem, &xevent); + } } if ((status == WAIT_TIMEOUT) || (GetTickCount64() > frameTime)) diff --git a/server/shadow/shadow_client.c b/server/shadow/shadow_client.c index 6aa5b6a02..24dab2d51 100644 --- a/server/shadow/shadow_client.c +++ b/server/shadow/shadow_client.c @@ -104,6 +104,22 @@ void shadow_client_context_free(freerdp_peer* peer, rdpShadowClient* client) } } +void shadow_client_message_free(wMessage* message) +{ + if (message->id == SHADOW_MSG_IN_REFRESH_OUTPUT_ID) + { + SHADOW_MSG_IN_REFRESH_OUTPUT* wParam = (SHADOW_MSG_IN_REFRESH_OUTPUT*) message->wParam; + + free(wParam->rects); + free(wParam); + } + else if (message->id == SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID) + { + SHADOW_MSG_IN_SUPPRESS_OUTPUT* wParam = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) message->wParam; + free(wParam); + } +} + BOOL shadow_client_capabilities(freerdp_peer* peer) { return TRUE; @@ -168,20 +184,59 @@ BOOL shadow_client_post_connect(freerdp_peer* peer) void shadow_client_refresh_rect(rdpShadowClient* client, BYTE count, RECTANGLE_16* areas) { + wMessage message = { 0 }; + SHADOW_MSG_IN_REFRESH_OUTPUT* wParam; wMessagePipe* MsgPipe = client->subsystem->MsgPipe; - printf("RefreshRect: %d\n", count); + wParam = (SHADOW_MSG_IN_REFRESH_OUTPUT*) calloc(1, sizeof(SHADOW_MSG_IN_REFRESH_OUTPUT)); - MessageQueue_Post(MsgPipe->In, (void*) client, 1, NULL, NULL); + if (!wParam) + return; + + wParam->numRects = (UINT32) count; + + if (wParam->numRects) + { + wParam->rects = (RECTANGLE_16*) calloc(wParam->numRects, sizeof(RECTANGLE_16)); + + if (!wParam->rects) + return; + } + + CopyMemory(wParam->rects, areas, wParam->numRects * sizeof(RECTANGLE_16)); + + message.id = SHADOW_MSG_IN_REFRESH_OUTPUT_ID; + message.wParam = (void*) wParam; + message.lParam = NULL; + message.context = (void*) client; + message.Free = shadow_client_message_free; + + MessageQueue_Dispatch(MsgPipe->In, &message); } void shadow_client_suppress_output(rdpShadowClient* client, BYTE allow, RECTANGLE_16* area) { + wMessage message = { 0 }; + SHADOW_MSG_IN_SUPPRESS_OUTPUT* wParam; wMessagePipe* MsgPipe = client->subsystem->MsgPipe; - printf("SuppressOutput: %d\n", allow); + wParam = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) calloc(1, sizeof(SHADOW_MSG_IN_SUPPRESS_OUTPUT)); - MessageQueue_Post(MsgPipe->In, (void*) client, 2, NULL, NULL); + if (!wParam) + return; + + wParam->allow = (UINT32) allow; + + if (area) + CopyMemory(&(wParam->rect), area, sizeof(RECTANGLE_16)); + + message.id = SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID; + message.wParam = (void*) wParam; + message.lParam = NULL; + message.context = (void*) client; + message.Free = shadow_client_message_free; + + MessageQueue_Dispatch(MsgPipe->In, &message); } BOOL shadow_client_activate(freerdp_peer* peer) diff --git a/server/shadow/shadow_subsystem.c b/server/shadow/shadow_subsystem.c index 9d41a8f7e..0a08c7c1f 100644 --- a/server/shadow/shadow_subsystem.c +++ b/server/shadow/shadow_subsystem.c @@ -137,8 +137,9 @@ int shadow_subsystem_init(rdpShadowSubsystem* subsystem, rdpShadowServer* server subsystem->server = server; subsystem->selectedMonitor = server->selectedMonitor; - subsystem->updateEvent = CreateEvent(NULL, TRUE, FALSE, NULL); subsystem->MsgPipe = MessagePipe_New(); + subsystem->updateEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + region16_init(&(subsystem->invalidRegion)); if (!subsystem->ep.Init) @@ -155,22 +156,20 @@ void shadow_subsystem_uninit(rdpShadowSubsystem* subsystem) if (subsystem->ep.Uninit) subsystem->ep.Uninit(subsystem); - if (subsystem->updateEvent) - { - CloseHandle(subsystem->updateEvent); - subsystem->updateEvent = NULL; - } - if (subsystem->MsgPipe) { MessagePipe_Free(subsystem->MsgPipe); subsystem->MsgPipe = NULL; } - if (subsystem->invalidRegion.data) + if (subsystem->updateEvent) { - region16_uninit(&(subsystem->invalidRegion)); + CloseHandle(subsystem->updateEvent); + subsystem->updateEvent = NULL; } + + if (subsystem->invalidRegion.data) + region16_uninit(&(subsystem->invalidRegion)); } int shadow_subsystem_start(rdpShadowSubsystem* subsystem) diff --git a/server/shadow/shadow_subsystem.h b/server/shadow/shadow_subsystem.h index 9e61d6ce3..2ddbce864 100644 --- a/server/shadow/shadow_subsystem.h +++ b/server/shadow/shadow_subsystem.h @@ -24,7 +24,22 @@ #include #include -#include "shadow_subsystem.h" +#define SHADOW_MSG_IN_REFRESH_OUTPUT_ID 1001 +#define SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID 1002 + +struct _SHADOW_MSG_IN_REFRESH_OUTPUT +{ + UINT32 numRects; + RECTANGLE_16* rects; +}; +typedef struct _SHADOW_MSG_IN_REFRESH_OUTPUT SHADOW_MSG_IN_REFRESH_OUTPUT; + +struct _SHADOW_MSG_IN_SUPPRESS_OUTPUT +{ + BOOL allow; + RECTANGLE_16 rect; +}; +typedef struct _SHADOW_MSG_IN_SUPPRESS_OUTPUT SHADOW_MSG_IN_SUPPRESS_OUTPUT; #ifdef __cplusplus extern "C" { diff --git a/winpr/libwinpr/utils/collections/MessageQueue.c b/winpr/libwinpr/utils/collections/MessageQueue.c index b4dc6c295..8b8ec1e15 100644 --- a/winpr/libwinpr/utils/collections/MessageQueue.c +++ b/winpr/libwinpr/utils/collections/MessageQueue.c @@ -111,6 +111,7 @@ void MessageQueue_Post(wMessageQueue* queue, void* context, UINT32 type, void* w message.id = type; message.wParam = wParam; message.lParam = lParam; + message.Free = NULL; MessageQueue_Dispatch(queue, &message); }