shadow: add RefreshRect/SuppressOutput support

This commit is contained in:
Marc-André Moreau 2014-09-18 22:18:58 -04:00
parent aa7571648c
commit 09fc388e03
9 changed files with 210 additions and 131 deletions

View File

@ -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

View File

@ -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; \

View File

@ -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;

View File

@ -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;
}

View File

@ -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))

View File

@ -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)

View File

@ -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)

View File

@ -24,7 +24,22 @@
#include <winpr/crt.h>
#include <winpr/synch.h>
#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" {

View File

@ -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);
}