Merge pull request #2739 from realjiangms/shadow_resize

server/shadow: Enhancement regarding the screen and resolution - addresize support and fix subRect feature
This commit is contained in:
Marc-André Moreau 2015-08-27 10:19:25 -04:00
commit 97c38e7d8c
11 changed files with 337 additions and 94 deletions

View File

@ -90,7 +90,6 @@ struct rdp_shadow_client
CRITICAL_SECTION lock;
REGION16 invalidRegion;
rdpShadowServer* server;
rdpShadowSurface* lobby;
rdpShadowEncoder* encoder;
rdpShadowSubsystem* subsystem;
@ -112,6 +111,7 @@ struct rdp_shadow_server
wArrayList* clients;
rdpShadowScreen* screen;
rdpShadowSurface* surface;
rdpShadowSurface* lobby;
rdpShadowCapture* capture;
rdpShadowSubsystem* subsystem;
@ -282,6 +282,8 @@ FREERDP_API int shadow_client_boardcast_quit(rdpShadowServer* server, int nExitC
FREERDP_API int shadow_encoder_preferred_fps(rdpShadowEncoder* encoder);
FREERDP_API UINT32 shadow_encoder_inflight_frames(rdpShadowEncoder* encoder);
FREERDP_API BOOL shadow_screen_resize(rdpShadowScreen* screen);
#ifdef __cplusplus
}
#endif

View File

@ -51,6 +51,8 @@
#define TAG SERVER_TAG("shadow.x11")
int x11_shadow_enum_monitors(MONITOR_DEF* monitors, int maxMonitors);
#ifdef WITH_PAM
#include <security/pam_appl.h>
@ -273,12 +275,6 @@ void x11_shadow_input_mouse_event(x11ShadowSubsystem* subsystem, UINT16 flags, U
x += surface->x;
y += surface->y;
if (server->shareSubRect)
{
x += server->subRect.left;
y += server->subRect.top;
}
XTestGrabControl(subsystem->display, True);
if (flags & PTR_FLAGS_WHEEL)
@ -332,12 +328,6 @@ void x11_shadow_input_extended_mouse_event(x11ShadowSubsystem* subsystem, UINT16
x += surface->x;
y += surface->y;
if (server->shareSubRect)
{
x += server->subRect.left;
y += server->subRect.top;
}
XTestGrabControl(subsystem->display, True);
XTestFakeMotionEvent(subsystem->display, 0, x, y, CurrentTime);
@ -495,6 +485,13 @@ int x11_shadow_query_cursor(x11ShadowSubsystem* subsystem, BOOL getImage)
y = root_y;
}
/* Convert to offset based on current surface */
if (surface)
{
x -= surface->x;
y -= surface->y;
}
if ((x != subsystem->pointerX) || (y != subsystem->pointerY))
{
subsystem->pointerX = x;
@ -572,8 +569,8 @@ int x11_shadow_blend_cursor(x11ShadowSubsystem* subsystem)
nWidth = subsystem->cursorWidth;
nHeight = subsystem->cursorHeight;
nXDst = subsystem->pointerX - surface->x - subsystem->cursorHotX;
nYDst = subsystem->pointerY - surface->y - subsystem->cursorHotY;
nXDst = subsystem->pointerX - subsystem->cursorHotX;
nYDst = subsystem->pointerY - subsystem->cursorHotY;
if (nXDst >= surface->width)
return 1;
@ -659,6 +656,51 @@ int x11_shadow_blend_cursor(x11ShadowSubsystem* subsystem)
return 1;
}
BOOL x11_shadow_check_resize(x11ShadowSubsystem* subsystem)
{
MONITOR_DEF* virtualScreen;
XWindowAttributes attr;
XGetWindowAttributes(subsystem->display, subsystem->root_window, &attr);
if (attr.width != subsystem->width || attr.height != subsystem->height)
{
/* Screen size changed. Refresh monitor definitions and trigger screen resize */
subsystem->numMonitors = x11_shadow_enum_monitors(subsystem->monitors, 16);
shadow_screen_resize(subsystem->server->screen);
subsystem->width = attr.width;
subsystem->height = attr.height;
virtualScreen = &(subsystem->virtualScreen);
virtualScreen->left = 0;
virtualScreen->top = 0;
virtualScreen->right = subsystem->width;
virtualScreen->bottom = subsystem->height;
virtualScreen->flags = 1;
return TRUE;
}
return FALSE;
}
static int x11_shadow_error_handler_for_capture(Display * display, XErrorEvent * event)
{
char msg[256];
XGetErrorText(display, event->error_code, (char *) &msg, sizeof(msg));
WLog_ERR(TAG, "X11 error: %s Error code: %x, request code: %x, minor code: %x",
msg, event->error_code, event->request_code, event->minor_code);
/* Ignore BAD MATCH error during image capture. Abort in other case */
if (event->error_code != BadMatch)
{
abort();
}
return 0;
}
int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem)
{
int count;
@ -692,6 +734,12 @@ int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem)
XLockDisplay(subsystem->display);
/*
* Ignore BadMatch error during image capture. The screen size may be
* changed outside. We will resize to correct resolution at next frame
*/
XSetErrorHandler(x11_shadow_error_handler_for_capture);
if (subsystem->use_xshm)
{
image = subsystem->fb_image;
@ -707,10 +755,22 @@ int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem)
image = XGetImage(subsystem->display, subsystem->root_window,
surface->x, surface->y, surface->width, surface->height, AllPlanes, ZPixmap);
if (!image)
{
/*
* BadMatch error happened. The size may have been changed again.
* Give up this frame and we will resize again in next frame
*/
goto fail_capture;
}
status = shadow_capture_compare(surface->data, surface->scanline, surface->width, surface->height,
(BYTE*) image->data, image->bytes_per_line, &invalidRect);
}
/* Restore the default error handler */
XSetErrorHandler(NULL);
XSync(subsystem->display, False);
XUnlockDisplay(subsystem->display);
@ -757,6 +817,12 @@ int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem)
XDestroyImage(image);
return 1;
fail_capture:
XSetErrorHandler(NULL);
XSync(subsystem->display, False);
XUnlockDisplay(subsystem->display);
return 0;
}
int x11_shadow_subsystem_process_message(x11ShadowSubsystem* subsystem, wMessage* message)
@ -866,6 +932,7 @@ void* x11_shadow_subsystem_thread(x11ShadowSubsystem* subsystem)
if ((status == WAIT_TIMEOUT) || (GetTickCount64() > frameTime))
{
x11_shadow_check_resize(subsystem);
x11_shadow_screen_grab(subsystem);
x11_shadow_query_cursor(subsystem, FALSE);
@ -1127,6 +1194,8 @@ int x11_shadow_enum_monitors(MONITOR_DEF* monitors, int maxMonitors)
}
#endif
XCloseDisplay(display);
if (numMonitors < 1)
{
index = 0;

View File

@ -150,12 +150,6 @@ void shadow_client_context_free(freerdp_peer* peer, rdpShadowClient* client)
MessageQueue_Clear(client->MsgQueue);
MessageQueue_Free(client->MsgQueue);
if (client->lobby)
{
shadow_surface_free(client->lobby);
client->lobby = NULL;
}
if (client->encoder)
{
shadow_encoder_free(client->encoder);
@ -188,6 +182,19 @@ BOOL shadow_client_capabilities(freerdp_peer* peer)
return TRUE;
}
static INLINE void shadow_client_calc_desktop_size(rdpShadowServer* server, int* pWidth, int* pHeight)
{
RECTANGLE_16 viewport = {0, 0, server->screen->width, server->screen->height};
if (server->shareSubRect)
{
rectangles_intersection(&viewport, &(server->subRect), &viewport);
}
(*pWidth) = viewport.right - viewport.left;
(*pHeight) = viewport.bottom - viewport.top;
}
BOOL shadow_client_post_connect(freerdp_peer* peer)
{
int authStatus;
@ -203,17 +210,7 @@ BOOL shadow_client_post_connect(freerdp_peer* peer)
server = client->server;
subsystem = server->subsystem;
if (!server->shareSubRect)
{
width = server->screen->width;
height = server->screen->height;
}
else
{
width = server->subRect.right - server->subRect.left;
height = server->subRect.bottom - server->subRect.top;
}
shadow_client_calc_desktop_size(server, &width, &height);
settings->DesktopWidth = width;
settings->DesktopHeight = height;
@ -232,13 +229,11 @@ BOOL shadow_client_post_connect(freerdp_peer* peer)
invalidRect.left = 0;
invalidRect.top = 0;
invalidRect.right = width;
invalidRect.bottom = height;
invalidRect.right = server->screen->width;
invalidRect.bottom = server->screen->height;
region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &invalidRect);
shadow_client_init_lobby(client);
authStatus = -1;
if (settings->Username && settings->Password)
@ -270,6 +265,30 @@ BOOL shadow_client_post_connect(freerdp_peer* peer)
return TRUE;
}
/* Convert rects in sub rect coordinate to client/surface coordinate */
static INLINE void shadow_client_convert_rects(rdpShadowClient* client,
RECTANGLE_16* dst, RECTANGLE_16* src, UINT32 numRects)
{
if (client->server->shareSubRect)
{
int i = 0;
UINT16 offsetX = client->server->subRect.left;
UINT16 offsetY = client->server->subRect.top;
for (i = 0; i < numRects; i++)
{
dst[i].left = src[i].left + offsetX;
dst[i].right = src[i].right + offsetX;
dst[i].top = src[i].top + offsetY;
dst[i].bottom = src[i].bottom + offsetY;
}
}
else
{
CopyMemory(dst, src, numRects * sizeof(RECTANGLE_16));
}
}
BOOL shadow_client_refresh_rect(rdpShadowClient* client, BYTE count, RECTANGLE_16* areas)
{
wMessage message = { 0 };
@ -294,7 +313,7 @@ BOOL shadow_client_refresh_rect(rdpShadowClient* client, BYTE count, RECTANGLE_1
return FALSE;
}
CopyMemory(wParam->rects, areas, wParam->numRects * sizeof(RECTANGLE_16));
shadow_client_convert_rects(client, wParam->rects, areas, wParam->numRects);
}
message.id = SHADOW_MSG_IN_REFRESH_OUTPUT_ID;
@ -319,7 +338,7 @@ BOOL shadow_client_suppress_output(rdpShadowClient* client, BYTE allow, RECTANGL
wParam->allow = (UINT32) allow;
if (area)
CopyMemory(&(wParam->rect), area, sizeof(RECTANGLE_16));
shadow_client_convert_rects(client, &(wParam->rect), area, 1);
message.id = SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID;
message.wParam = (void*) wParam;
@ -445,7 +464,7 @@ int shadow_client_send_surface_bits(rdpShadowClient* client, rdpShadowSurface* s
rect.height = nHeight;
if (!(messages = rfx_encode_messages(encoder->rfx, &rect, 1, pSrcData,
surface->width, surface->height, nSrcStep, &numMessages,
settings->DesktopWidth, settings->DesktopHeight, nSrcStep, &numMessages,
settings->MultifragMaxRequestSize)))
{
return 0;
@ -455,12 +474,12 @@ int shadow_client_send_surface_bits(rdpShadowClient* client, rdpShadowSurface* s
cmd.destLeft = 0;
cmd.destTop = 0;
cmd.destRight = surface->width;
cmd.destBottom = surface->height;
cmd.destRight = settings->DesktopWidth;
cmd.destBottom = settings->DesktopHeight;
cmd.bpp = 32;
cmd.width = surface->width;
cmd.height = surface->height;
cmd.width = settings->DesktopWidth;
cmd.height = settings->DesktopHeight;
cmd.skipCompression = TRUE;
if (numMessages > 0)
@ -569,6 +588,21 @@ int shadow_client_send_bitmap_update(rdpShadowClient* client, rdpShadowSurface*
nSrcStep = surface->scanline;
SrcFormat = PIXEL_FORMAT_RGB32;
if (server->shareSubRect)
{
int subX, subY;
int subWidth, subHeight;
subX = server->subRect.left;
subY = server->subRect.top;
subWidth = server->subRect.right - server->subRect.left;
subHeight = server->subRect.bottom - server->subRect.top;
nXSrc -= subX;
nYSrc -= subY;
pSrcData = &pSrcData[(subY * nSrcStep) + (subX * 4)];
}
if ((nXSrc % 4) != 0)
{
nWidth += (nXSrc % 4);
@ -747,7 +781,7 @@ int shadow_client_send_surface_update(rdpShadowClient* client)
server = client->server;
encoder = client->encoder;
surface = client->inLobby ? client->lobby : server->surface;
surface = client->inLobby ? server->lobby : server->surface;
EnterCriticalSection(&(client->lock));
@ -915,6 +949,12 @@ int shadow_client_subsystem_process_message(rdpShadowClient* client, wMessage* m
pointerPosition.xPos = msg->xPos;
pointerPosition.yPos = msg->yPos;
if (client->server->shareSubRect)
{
pointerPosition.xPos -= client->server->subRect.left;
pointerPosition.yPos -= client->server->subRect.top;
}
if (client->activated)
{
if ((msg->xPos != client->pointerX) || (msg->yPos != client->pointerY))
@ -1060,15 +1100,44 @@ void* shadow_client_thread(rdpShadowClient* client)
int index;
int numRects = 0;
const RECTANGLE_16* rects;
int width, height;
rects = region16_rects(&(subsystem->invalidRegion), &numRects);
for (index = 0; index < numRects; index++)
/* Check resize */
shadow_client_calc_desktop_size(server, &width, &height);
if (settings->DesktopWidth != (UINT32)width || settings->DesktopHeight != (UINT32)height)
{
region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &rects[index]);
}
/* Screen size changed, do resize */
settings->DesktopWidth = width;
settings->DesktopHeight = height;
shadow_client_send_surface_update(client);
/**
* Unset client activated flag to avoid sending update message during
* resize. DesktopResize will reactive the client and
* shadow_client_activate would be invoked later.
*/
client->activated = FALSE;
/* Send Resize */
peer->update->DesktopResize(peer->update->context); // update_send_desktop_resize
/* Clear my invalidRegion. shadow_client_activate refreshes fullscreen */
region16_clear(&(client->invalidRegion));
WLog_ERR(TAG, "Client from %s is resized (%dx%d@%d)",
peer->hostname, settings->DesktopWidth, settings->DesktopHeight, settings->ColorDepth);
}
else
{
/* Send frame */
rects = region16_rects(&(subsystem->invalidRegion), &numRects);
for (index = 0; index < numRects; index++)
{
region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &rects[index]);
}
shadow_client_send_surface_update(client);
}
}
/*

View File

@ -224,6 +224,9 @@ int shadow_encoder_init_interleaved(rdpShadowEncoder* encoder)
int shadow_encoder_init(rdpShadowEncoder* encoder)
{
encoder->width = encoder->server->screen->width;
encoder->height = encoder->server->screen->height;
encoder->maxTileWidth = 64;
encoder->maxTileHeight = 64;
@ -401,9 +404,6 @@ rdpShadowEncoder* shadow_encoder_new(rdpShadowClient* client)
encoder->fps = 16;
encoder->maxFps = 32;
encoder->width = server->screen->width;
encoder->height = server->screen->height;
if (shadow_encoder_init(encoder) < 0)
{
free (encoder);

View File

@ -72,6 +72,12 @@ BOOL shadow_input_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
rdpShadowClient* client = (rdpShadowClient*) input->context;
rdpShadowSubsystem* subsystem = client->server->subsystem;
if (client->server->shareSubRect)
{
x += client->server->subRect.left;
y += client->server->subRect.top;
}
if (!(flags & PTR_FLAGS_WHEEL))
{
client->pointerX = x;
@ -102,6 +108,12 @@ BOOL shadow_input_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x,
rdpShadowClient* client = (rdpShadowClient*) input->context;
rdpShadowSubsystem* subsystem = client->server->subsystem;
if (client->server->shareSubRect)
{
x += client->server->subRect.left;
y += client->server->subRect.top;
}
client->pointerX = x;
client->pointerY = y;

View File

@ -26,31 +26,44 @@
#include "shadow_lobby.h"
int shadow_client_init_lobby(rdpShadowClient* client)
BOOL shadow_client_init_lobby(rdpShadowServer* server)
{
int width;
int height;
rdtkEngine* engine;
rdtkSurface* surface;
RECTANGLE_16 invalidRect;
rdpShadowSurface* lobby;
rdpContext* context = (rdpContext*) client;
rdpSettings* settings = context->settings;
rdpShadowSurface* lobby = server->lobby;
width = settings->DesktopWidth;
height = settings->DesktopHeight;
if (!lobby)
return FALSE;
lobby = client->lobby = shadow_surface_new(client->server, 0, 0, width, height);
if (!(engine = rdtk_engine_new()))
{
return FALSE;
}
if (!client->lobby)
return -1;
if (!(surface = rdtk_surface_new(engine, lobby->data, lobby->width, lobby->height, lobby->scanline)))
{
rdtk_engine_free(engine);
return FALSE;
}
engine = rdtk_engine_new();
invalidRect.left = 0;
invalidRect.top = 0;
invalidRect.right = lobby->width;
invalidRect.bottom = lobby->height;
if (server->shareSubRect)
{
/* If we have shared sub rect setting, only fill shared rect */
rectangles_intersection(&invalidRect, &(server->subRect), &invalidRect);
}
surface = rdtk_surface_new(engine, lobby->data, lobby->width, lobby->height, lobby->scanline);
width = invalidRect.right - invalidRect.left;
height = invalidRect.bottom - invalidRect.top;
rdtk_surface_fill(surface, invalidRect.left, invalidRect.top, width, height, 0x3BB9FF);
rdtk_surface_fill(surface, 0, 0, width, height, 0x3BB9FF);
//rdtk_label_draw(surface, 16, 16, 128, 32, NULL, "label", 0, 0);
rdtk_label_draw(surface, invalidRect.left, invalidRect.top, width, height, NULL, "Welcome", 0, 0);
//rdtk_button_draw(surface, 16, 64, 128, 32, NULL, "button");
//rdtk_text_field_draw(surface, 16, 128, 128, 32, NULL, "text field");
@ -58,12 +71,7 @@ int shadow_client_init_lobby(rdpShadowClient* client)
rdtk_engine_free(engine);
invalidRect.left = 0;
invalidRect.top = 0;
invalidRect.right = width;
invalidRect.bottom = height;
region16_union_rect(&(lobby->invalidRegion), &(lobby->invalidRegion), &invalidRect);
return 1;
return TRUE;
}

View File

@ -30,7 +30,7 @@
extern "C" {
#endif
int shadow_client_init_lobby(rdpShadowClient* client);
BOOL shadow_client_init_lobby(rdpShadowServer* server);
#ifdef __cplusplus
}

View File

@ -23,6 +23,7 @@
#include "shadow_surface.h"
#include "shadow_screen.h"
#include "shadow_lobby.h"
rdpShadowScreen* shadow_screen_new(rdpShadowServer* server)
{
@ -30,35 +31,27 @@ rdpShadowScreen* shadow_screen_new(rdpShadowServer* server)
int width, height;
rdpShadowScreen* screen;
rdpShadowSubsystem* subsystem;
MONITOR_DEF* primary;
screen = (rdpShadowScreen*) calloc(1, sizeof(rdpShadowScreen));
if (!screen)
return NULL;
goto out_error;
screen->server = server;
subsystem = server->subsystem;
if (!InitializeCriticalSectionAndSpinCount(&(screen->lock), 4000))
return NULL;
goto out_free;
region16_init(&(screen->invalidRegion));
if (server->shareSubRect) {
x = server->subRect.left;
y = server->subRect.top;
width = server->subRect.right - server->subRect.left;
height = server->subRect.bottom - server->subRect.top;
} else {
MONITOR_DEF* primary;
primary = &(subsystem->monitors[subsystem->selectedMonitor]);
primary = &(subsystem->monitors[subsystem->selectedMonitor]);
x = primary->left;
y = primary->top;
width = primary->right - primary->left;
height = primary->bottom - primary->top;
}
x = primary->left;
y = primary->top;
width = primary->right - primary->left;
height = primary->bottom - primary->top;
screen->width = width;
screen->height = height;
@ -66,11 +59,31 @@ rdpShadowScreen* shadow_screen_new(rdpShadowServer* server)
screen->primary = shadow_surface_new(server, x, y, width, height);
if (!screen->primary)
return NULL;
goto out_free_region;
server->surface = screen->primary;
screen->lobby = shadow_surface_new(server, x, y, width, height);
if (!screen->lobby)
goto out_free_primary;
server->lobby = screen->lobby;
shadow_client_init_lobby(server);
return screen;
out_free_primary:
shadow_surface_free(screen->primary);
server->surface = screen->primary = NULL;
out_free_region:
region16_uninit(&(screen->invalidRegion));
DeleteCriticalSection(&(screen->lock));
out_free:
free(screen);
out_error:
return NULL;
}
void shadow_screen_free(rdpShadowScreen* screen)
@ -88,6 +101,45 @@ void shadow_screen_free(rdpShadowScreen* screen)
screen->primary = NULL;
}
if (screen->lobby)
{
shadow_surface_free(screen->lobby);
screen->lobby = NULL;
}
free(screen);
}
BOOL shadow_screen_resize(rdpShadowScreen* screen)
{
int x, y;
int width, height;
MONITOR_DEF* primary;
rdpShadowSubsystem* subsystem;
if (!screen)
return FALSE;
subsystem = screen->server->subsystem;
primary = &(subsystem->monitors[subsystem->selectedMonitor]);
x = primary->left;
y = primary->top;
width = primary->right - primary->left;
height = primary->bottom - primary->top;
if (shadow_surface_resize(screen->primary, x, y, width, height)
&& shadow_surface_resize(screen->lobby, x, y, width, height))
{
if ((width != screen->width) || (height != screen->height))
{
/* screen size is changed. Store new size and reinit lobby */
screen->width = width;
screen->height = height;
shadow_client_init_lobby(screen->server);
}
return TRUE;
}
return FALSE;
}

View File

@ -35,6 +35,7 @@ struct rdp_shadow_screen
REGION16 invalidRegion;
rdpShadowSurface* primary;
rdpShadowSurface* lobby;
};
#ifdef __cplusplus

View File

@ -41,16 +41,13 @@ rdpShadowSurface* shadow_surface_new(rdpShadowServer* server, int x, int y, int
surface->height = height;
surface->scanline = (surface->width + (surface->width % 4)) * 4;
surface->data = (BYTE*) malloc(surface->scanline * surface->height);
surface->data = (BYTE*) calloc(1, surface->scanline * surface->height);
if (!surface->data)
{
free (surface);
return NULL;
}
ZeroMemory(surface->data, surface->scanline * surface->height);
if (!InitializeCriticalSectionAndSpinCount(&(surface->lock), 4000))
{
free (surface->data);
@ -76,3 +73,35 @@ void shadow_surface_free(rdpShadowSurface* surface)
free(surface);
}
BOOL shadow_surface_resize(rdpShadowSurface *surface, int x, int y, int width, int height)
{
BYTE* buffer = NULL;
int scanline = (width + (width % 4)) * 4;
if (!surface)
return FALSE;
if ((width == surface->width) && (height == surface->height))
{
/* We don't need to reset frame buffer, just update left top */
surface->x = x;
surface->y = y;
return TRUE;
}
buffer = (BYTE*) realloc(surface->data, scanline * height);
if (buffer)
{
surface->x = x;
surface->y = y;
surface->width = width;
surface->height = height;
surface->scanline = scanline;
surface->data = buffer;
return TRUE;
}
return FALSE;
}

View File

@ -45,6 +45,7 @@ extern "C" {
rdpShadowSurface* shadow_surface_new(rdpShadowServer* server, int x, int y, int width, int height);
void shadow_surface_free(rdpShadowSurface* surface);
BOOL shadow_surface_resize(rdpShadowSurface *surface, int x, int y, int width, int height);
#ifdef __cplusplus
}