shadow: hook X11 input

This commit is contained in:
Marc-André Moreau 2014-07-12 01:18:08 -04:00
parent c865fed299
commit e9818e95ac
11 changed files with 185 additions and 121 deletions

View File

@ -26,6 +26,9 @@
#include <freerdp/settings.h>
#include <freerdp/listener.h>
#include <freerdp/codec/color.h>
#include <freerdp/codec/region.h>
typedef struct rdp_shadow_client rdpShadowClient;
typedef struct rdp_shadow_server rdpShadowServer;
typedef struct rdp_shadow_screen rdpShadowScreen;
@ -39,6 +42,7 @@ struct rdp_shadow_client
HANDLE thread;
BOOL activated;
HANDLE StopEvent;
rdpShadowServer* server;
};
@ -46,6 +50,7 @@ struct rdp_shadow_server
{
void* ext;
HANDLE thread;
HANDLE StopEvent;
rdpShadowScreen* screen;
rdpShadowSurface* surface;
rdpShadowEncoder* encoder;
@ -57,6 +62,7 @@ struct rdp_shadow_server
#define RDP_SHADOW_SUBSYSTEM_COMMON() \
rdpShadowServer* server; \
HANDLE event; \
int monitorCount; \
MONITOR_DEF monitors[16]

View File

@ -30,7 +30,7 @@
void x11_shadow_input_synchronize_event(x11ShadowSubsystem* subsystem, UINT32 flags)
{
fprintf(stderr, "Client sent a synchronize event (flags:0x%X)\n", flags);
}
void x11_shadow_input_keyboard_event(x11ShadowSubsystem* subsystem, UINT16 flags, UINT16 code)
@ -65,7 +65,7 @@ void x11_shadow_input_keyboard_event(x11ShadowSubsystem* subsystem, UINT16 flags
void x11_shadow_input_unicode_keyboard_event(x11ShadowSubsystem* subsystem, UINT16 flags, UINT16 code)
{
fprintf(stderr, "Client sent a unicode keyboard event (flags:0x%X code:0x%X)\n", flags, code);
}
void x11_shadow_input_mouse_event(x11ShadowSubsystem* subsystem, UINT16 flags, UINT16 x, UINT16 y)

View File

@ -191,7 +191,7 @@ int x11_shadow_subsystem_init(x11ShadowSubsystem* subsystem)
* To see if your X11 server supports shared pixmaps, use:
* xdpyinfo -ext MIT-SHM | grep "shared pixmaps"
*/
subsystem->use_xshm = TRUE;
subsystem->use_xshm = FALSE;
setenv("DISPLAY", ":0", 1); /* Set DISPLAY variable if not already set */
@ -276,6 +276,8 @@ int x11_shadow_subsystem_init(x11ShadowSubsystem* subsystem)
x11_shadow_cursor_init(subsystem);
subsystem->event = CreateFileDescriptorEvent(NULL, FALSE, FALSE, subsystem->xfds);
subsystem->monitorCount = 1;
subsystem->monitors[0].left = 0;
subsystem->monitors[0].top = 0;
@ -297,6 +299,12 @@ int x11_shadow_subsystem_uninit(x11ShadowSubsystem* subsystem)
subsystem->display = NULL;
}
if (subsystem->event)
{
CloseHandle(subsystem->event);
subsystem->event = NULL;
}
return 1;
}

View File

@ -29,8 +29,6 @@ typedef struct x11_shadow_subsystem x11ShadowSubsystem;
#include <winpr/stream.h>
#include <winpr/collections.h>
#include <freerdp/codec/rfx.h>
#include <X11/Xlib.h>
#ifdef WITH_XSHM
@ -89,6 +87,15 @@ struct x11_shadow_subsystem
extern "C" {
#endif
int x11_shadow_check_event(x11ShadowSubsystem* subsystem);
int x11_shadow_surface_copy(x11ShadowSubsystem* subsystem, int x, int y, int width, int height);
void x11_shadow_input_synchronize_event(x11ShadowSubsystem* subsystem, UINT32 flags);
void x11_shadow_input_keyboard_event(x11ShadowSubsystem* subsystem, UINT16 flags, UINT16 code);
void x11_shadow_input_unicode_keyboard_event(x11ShadowSubsystem* subsystem, UINT16 flags, UINT16 code);
void x11_shadow_input_mouse_event(x11ShadowSubsystem* subsystem, UINT16 flags, UINT16 x, UINT16 y);
void x11_shadow_input_extended_mouse_event(x11ShadowSubsystem* subsystem, UINT16 flags, UINT16 x, UINT16 y);
rdpShadowSubsystem* x11_shadow_subsystem_new(rdpShadowServer* server);
void x11_shadow_subsystem_free(rdpShadowSubsystem* subsystem);

View File

@ -24,9 +24,13 @@
#include <winpr/synch.h>
#include <winpr/sysinfo.h>
#include <freerdp/codec/color.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "../shadow_surface.h"
#include "x11_shadow.h"
XImage* x11_shadow_snapshot(x11ShadowSubsystem* subsystem, int x, int y, int width, int height)
@ -35,12 +39,14 @@ XImage* x11_shadow_snapshot(x11ShadowSubsystem* subsystem, int x, int y, int wid
if (subsystem->use_xshm)
{
XCopyArea(subsystem->display, subsystem->root_window, subsystem->fb_pixmap, subsystem->xdamage_gc, x, y, width, height, x, y);
XCopyArea(subsystem->display, subsystem->root_window, subsystem->fb_pixmap,
subsystem->xdamage_gc, x, y, width, height, x, y);
image = subsystem->fb_image;
}
else
{
image = XGetImage(subsystem->display, subsystem->root_window, x, y, width, height, AllPlanes, ZPixmap);
image = XGetImage(subsystem->display, subsystem->root_window,
x, y, width, height, AllPlanes, ZPixmap);
}
return image;
@ -61,100 +67,76 @@ void x11_shadow_xdamage_subtract_region(x11ShadowSubsystem* subsystem, int x, in
#endif
}
int x11_shadow_update_encode(x11ShadowSubsystem* subsystem, int x, int y, int width, int height)
int x11_shadow_surface_copy(x11ShadowSubsystem* subsystem, int x, int y, int width, int height)
{
BYTE* data;
XImage* image;
RFX_RECT rect;
rdpShadowServer* server;
rdpShadowSurface* surface;
RECTANGLE_16 invalidRect;
server = subsystem->server;
surface = server->surface;
printf("x11_shadow_surface_copy: x: %d y: %d width: %d height: %d\n",
x, y, width, height);
if (subsystem->use_xshm)
{
/**
* Passing an offset source rectangle to rfx_compose_message()
* leads to protocol errors, so offset the data pointer instead.
*/
rect.x = 0;
rect.y = 0;
rect.width = width;
rect.height = height;
image = x11_shadow_snapshot(subsystem, x, y, width, height);
data = (BYTE*) image->data;
data = &data[(y * image->bytes_per_line) + (x * image->bits_per_pixel / 8)];
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);
}
else
{
rect.x = 0;
rect.y = 0;
rect.width = width;
rect.height = height;
image = x11_shadow_snapshot(subsystem, x, y, width, height);
data = (BYTE*) image->data;
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);
XDestroyImage(image);
}
return 0;
invalidRect.left = x;
invalidRect.top = y;
invalidRect.right = width;
invalidRect.bottom = height;
region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect);
return 1;
}
void* x11_shadow_update_thread(x11ShadowSubsystem* subsystem)
int x11_shadow_check_event(x11ShadowSubsystem* subsystem)
{
HANDLE event;
XEvent xevent;
DWORD beg, end;
DWORD diff, rate;
XFixesCursorImage* ci;
int x, y, width, height;
XDamageNotifyEvent* notify;
rate = 1000 / 10;
event = CreateFileDescriptorEvent(NULL, FALSE, FALSE, subsystem->xfds);
while (WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0)
while (XPending(subsystem->display) > 0)
{
beg = GetTickCount();
ZeroMemory(&xevent, sizeof(xevent));
XNextEvent(subsystem->display, &xevent);
while (XPending(subsystem->display) > 0)
if (xevent.type == subsystem->xdamage_notify_event)
{
ZeroMemory(&xevent, sizeof(xevent));
XNextEvent(subsystem->display, &xevent);
notify = (XDamageNotifyEvent*) &xevent;
if (xevent.type == subsystem->xdamage_notify_event)
x = notify->area.x;
y = notify->area.y;
width = notify->area.width;
height = notify->area.height;
if (x11_shadow_surface_copy(subsystem, x, y, width, height) > 0)
{
notify = (XDamageNotifyEvent*) &xevent;
x = notify->area.x;
y = notify->area.y;
width = notify->area.width;
height = notify->area.height;
if (x11_shadow_update_encode(subsystem, x, y, width, height) >= 0)
{
x11_shadow_xdamage_subtract_region(subsystem, x, y, width, height);
/* send update */
}
x11_shadow_xdamage_subtract_region(subsystem, x, y, width, height);
}
#ifdef WITH_XFIXES
else if (xevent.type == subsystem->xfixes_notify_event)
{
ci = XFixesGetCursorImage(subsystem->display);
XFree(ci);
}
#endif
}
end = GetTickCount();
diff = end - beg;
if (diff < rate)
Sleep(rate - diff);
}
return NULL;
return 1;
}

View File

@ -32,9 +32,11 @@ void* shadow_server_thread(rdpShadowServer* server)
DWORD status;
DWORD nCount;
HANDLE events[32];
HANDLE StopEvent;
freerdp_listener* listener;
listener = server->listener;
StopEvent = server->StopEvent;
while (1)
{
@ -46,8 +48,15 @@ void* shadow_server_thread(rdpShadowServer* server)
break;
}
events[nCount++] = server->StopEvent;
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
if (WaitForSingleObject(server->StopEvent, 0) == WAIT_OBJECT_0)
{
break;
}
if (!listener->CheckFileDescriptor(listener))
{
fprintf(stderr, "Failed to check FreeRDP file descriptor\n");
@ -81,9 +90,10 @@ int shadow_server_stop(rdpShadowServer* server)
{
if (server->thread)
{
TerminateThread(server->thread, 0);
SetEvent(server->StopEvent);
WaitForSingleObject(server->thread, INFINITE);
CloseHandle(server->thread);
server->thread = NULL;
server->listener->Close(server->listener);
}
@ -91,11 +101,6 @@ int shadow_server_stop(rdpShadowServer* server)
return 0;
}
HANDLE shadow_server_get_thread(rdpShadowServer* server)
{
return server->thread;
}
rdpShadowServer* shadow_server_new(int argc, char** argv)
{
rdpShadowServer* server;
@ -107,6 +112,8 @@ rdpShadowServer* shadow_server_new(int argc, char** argv)
server->port = 3389;
server->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
server->listener = freerdp_listener_new();
if (!server->listener)
@ -138,6 +145,8 @@ void shadow_server_free(rdpShadowServer* server)
if (!server)
return;
shadow_server_stop(server);
freerdp_listener_free(server->listener);
shadow_encoder_free(server->encoder);
@ -149,7 +158,6 @@ void shadow_server_free(rdpShadowServer* server)
int main(int argc, char* argv[])
{
HANDLE thread;
DWORD dwExitCode;
rdpShadowServer* server;
@ -160,11 +168,9 @@ int main(int argc, char* argv[])
shadow_server_start(server);
thread = shadow_server_get_thread(server);
WaitForSingleObject(server->thread, INFINITE);
WaitForSingleObject(thread, INFINITE);
GetExitCodeThread(thread, &dwExitCode);
GetExitCodeThread(server->thread, &dwExitCode);
shadow_server_free(server);

View File

@ -36,11 +36,13 @@ void shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client)
server = (rdpShadowServer*) peer->ContextExtra;
client->server = server;
client->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
}
void shadow_client_context_free(freerdp_peer* peer, rdpShadowClient* client)
{
CloseHandle(client->StopEvent);
}
BOOL shadow_client_capabilities(freerdp_peer* peer)
@ -54,24 +56,7 @@ BOOL shadow_client_post_connect(freerdp_peer* peer)
client = (rdpShadowClient*) peer->context;
fprintf(stderr, "Client %s is activated", peer->hostname);
if (peer->settings->AutoLogonEnabled)
{
fprintf(stderr, " and wants to login automatically as %s\\%s",
peer->settings->Domain ? peer->settings->Domain : "",
peer->settings->Username);
}
fprintf(stderr, "\n");
fprintf(stderr, "Client requested desktop: %dx%d@%d\n",
peer->settings->DesktopWidth, peer->settings->DesktopHeight, peer->settings->ColorDepth);
if (!peer->settings->RemoteFxCodec)
{
fprintf(stderr, "Client does not support RemoteFX\n");
return FALSE;
}
fprintf(stderr, "Client from %s is activated\n", peer->hostname);
peer->settings->DesktopWidth = client->server->screen->width;
peer->settings->DesktopHeight = client->server->screen->height;
@ -97,6 +82,12 @@ int shadow_client_send_surface_bits(rdpShadowClient* client)
{
int i;
wStream* s;
int nXSrc;
int nYSrc;
int nWidth;
int nHeight;
int nSrcStep;
BYTE* pSrcData;
int numMessages;
rdpUpdate* update;
rdpContext* context;
@ -104,14 +95,9 @@ int shadow_client_send_surface_bits(rdpShadowClient* client)
rdpShadowServer* server;
rdpShadowSurface* surface;
rdpShadowEncoder* encoder;
RECTANGLE_16 surfaceRect;
SURFACE_BITS_COMMAND cmd;
BYTE* pSrcData;
int nSrcStep;
int nXSrc;
int nYSrc;
int nWidth;
int nHeight;
const RECTANGLE_16* extents;
context = (rdpContext*) client;
update = context->update;
@ -121,12 +107,24 @@ int shadow_client_send_surface_bits(rdpShadowClient* client)
encoder = server->encoder;
surface = server->surface;
surfaceRect.left = 0;
surfaceRect.top = 0;
surfaceRect.right = surface->width;
surfaceRect.bottom = surface->height;
region16_intersect_rect(&(surface->invalidRegion), &(surface->invalidRegion), &surfaceRect);
if (region16_is_empty(&(surface->invalidRegion)))
return 1;
extents = region16_extents(&(surface->invalidRegion));
nXSrc = extents->left;
nYSrc = extents->top;
nWidth = extents->right - extents->left;
nHeight = extents->bottom - extents->top;
pSrcData = surface->data;
nSrcStep = surface->scanline;
nWidth = surface->width;
nHeight = surface->height;
nXSrc = 0;
nYSrc = 0;
if (settings->RemoteFxCodec)
{
@ -168,8 +166,6 @@ int shadow_client_send_surface_bits(rdpShadowClient* client)
}
free(messages);
return 0;
}
else if (settings->NSCodec)
{
@ -205,10 +201,10 @@ int shadow_client_send_surface_bits(rdpShadowClient* client)
}
free(messages);
return 0;
}
region16_clear(&(surface->invalidRegion));
return 0;
}
@ -263,9 +259,18 @@ void* shadow_client_thread(rdpShadowClient* client)
DWORD status;
DWORD nCount;
HANDLE events[32];
HANDLE StopEvent;
HANDLE ClientEvent;
HANDLE SubsystemEvent;
freerdp_peer* peer;
rdpSettings* settings;
rdpShadowServer* server;
rdpShadowSurface* surface;
rdpShadowSubsystem* subsystem;
server = client->server;
surface = server->surface;
subsystem = server->subsystem;
peer = ((rdpContext*) client)->peer;
settings = peer->settings;
@ -287,14 +292,23 @@ void* shadow_client_thread(rdpShadowClient* client)
peer->Initialize(peer);
StopEvent = client->StopEvent;
ClientEvent = peer->GetEventHandle(peer);
SubsystemEvent = subsystem->event;
while (1)
{
nCount = 0;
events[nCount++] = StopEvent;
events[nCount++] = ClientEvent;
events[nCount++] = SubsystemEvent;
status = WaitForMultipleObjects(nCount, events, FALSE, 100);
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
if (WaitForSingleObject(client->StopEvent, 0) == WAIT_OBJECT_0)
{
break;
}
if (WaitForSingleObject(ClientEvent, 0) == WAIT_OBJECT_0)
{
@ -305,8 +319,15 @@ void* shadow_client_thread(rdpShadowClient* client)
}
}
if (client->activated)
shadow_client_send_surface_bits(client);
if (WaitForSingleObject(SubsystemEvent, 0) == WAIT_OBJECT_0)
{
x11_shadow_check_event((x11ShadowSubsystem*) subsystem);
if (client->activated)
{
shadow_client_send_surface_bits(client);
}
}
}
peer->Disconnect(peer);
@ -321,7 +342,6 @@ void* shadow_client_thread(rdpShadowClient* client)
void shadow_client_accepted(freerdp_listener* listener, freerdp_peer* peer)
{
HANDLE thread;
rdpShadowClient* client;
rdpShadowServer* server;
@ -335,6 +355,6 @@ void shadow_client_accepted(freerdp_listener* listener, freerdp_peer* peer)
client = (rdpShadowClient*) peer->context;
thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)
client->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)
shadow_client_thread, client, 0, NULL);
}

View File

@ -24,27 +24,42 @@
void shadow_input_synchronize_event(rdpInput* input, UINT32 flags)
{
rdpShadowClient* client = (rdpShadowClient*) input->context;
rdpShadowSubsystem* subsystem = client->server->subsystem;
x11_shadow_input_synchronize_event((x11ShadowSubsystem*) subsystem, flags);
}
void shadow_input_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
{
rdpShadowClient* client = (rdpShadowClient*) input->context;
rdpShadowSubsystem* subsystem = client->server->subsystem;
x11_shadow_input_keyboard_event((x11ShadowSubsystem*) subsystem, flags, code);
}
void shadow_input_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
{
rdpShadowClient* client = (rdpShadowClient*) input->context;
rdpShadowSubsystem* subsystem = client->server->subsystem;
x11_shadow_input_unicode_keyboard_event((x11ShadowSubsystem*) subsystem, flags, code);
}
void shadow_input_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
{
rdpShadowClient* client = (rdpShadowClient*) input->context;
rdpShadowSubsystem* subsystem = client->server->subsystem;
x11_shadow_input_mouse_event((x11ShadowSubsystem*) subsystem, flags, x, y);
}
void shadow_input_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
{
rdpShadowClient* client = (rdpShadowClient*) input->context;
rdpShadowSubsystem* subsystem = client->server->subsystem;
x11_shadow_input_extended_mouse_event((x11ShadowSubsystem*) subsystem, flags, x, y);
}
void shadow_input_register_callbacks(rdpInput* input)

View File

@ -56,5 +56,13 @@ void shadow_screen_free(rdpShadowScreen* screen)
{
if (!screen)
return;
if (screen->primary)
{
shadow_surface_free(screen->primary);
screen->primary = NULL;
}
free(screen);
}

View File

@ -20,6 +20,8 @@
#include "config.h"
#endif
#include "shadow.h"
#include "shadow_surface.h"
rdpShadowSurface* shadow_surface_new(rdpShadowServer* server, int width, int height)
@ -44,6 +46,8 @@ rdpShadowSurface* shadow_surface_new(rdpShadowServer* server, int width, int hei
ZeroMemory(surface->data, surface->scanline * surface->height);
region16_init(&(surface->invalidRegion));
return surface;
}
@ -51,4 +55,10 @@ void shadow_surface_free(rdpShadowSurface* surface)
{
if (!surface)
return;
free(surface->data);
region16_uninit(&(surface->invalidRegion));
free(surface);
}

View File

@ -29,6 +29,8 @@ struct rdp_shadow_surface
int height;
int scanline;
BYTE* data;
REGION16 invalidRegion;
};
#ifdef __cplusplus