diff --git a/.gitignore b/.gitignore index 2f957d723..00fb8eddc 100644 --- a/.gitignore +++ b/.gitignore @@ -5,15 +5,10 @@ config.h install_manifest.txt CTestTestfile.cmake freerdp.pc - -*.cmake -/**/*.cmake -/**/**/*.cmake -/**/**/**/*.cmake -/**/**/**/**/*.cmake - -# Make Makefile +cmake_install.cmake +CPackConfig.cmake +CPackSourceConfig.cmake # Eclipse *.project @@ -48,3 +43,7 @@ client/test/freerdp-test client/DirectFB/dfreerdp server/test/tfreerdp-server server/X11/xfreerdp-server + +# Other +*~ + diff --git a/cmake/FindXTest.cmake b/cmake/FindXTest.cmake new file mode 100644 index 000000000..ea00dcff8 --- /dev/null +++ b/cmake/FindXTest.cmake @@ -0,0 +1,49 @@ +# - Find XTEST +# Find the XTEST libraries +# +# This module defines the following variables: +# XTEST_FOUND - true if XTEST_INCLUDE_DIR & XTEST_LIBRARY are found +# XTEST_LIBRARIES - Set when XTEST_LIBRARY is found +# XTEST_INCLUDE_DIRS - Set when XTEST_INCLUDE_DIR is found +# +# XTEST_INCLUDE_DIR - where to find XTest.h, etc. +# XTEST_LIBRARY - the XTEST library +# + +#============================================================================= +# Copyright 2011 O.S. Systems Software Ltda. +# Copyright 2011 Otavio Salvador +# Copyright 2011 Marc-Andre Moreau +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============================================================================= + +find_path(XTEST_INCLUDE_DIR NAMES XTest.h + PATH_SUFFIXES X11/extensions + DOC "The XTest include directory" +) + +find_library(XTEST_LIBRARY NAMES Xtst + DOC "The XTest library" +) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(XTEST DEFAULT_MSG XTEST_LIBRARY XTEST_INCLUDE_DIR) + +if(XTEST_FOUND) + set( XTEST_LIBRARIES ${XTEST_LIBRARY} ) + set( XTEST_INCLUDE_DIRS ${XTEST_INCLUDE_DIR} ) +endif() + +mark_as_advanced(XTEST_INCLUDE_DIR XTEST_LIBRARY) + diff --git a/server/X11/CMakeLists.txt b/server/X11/CMakeLists.txt index 1f115f1e7..230df3922 100644 --- a/server/X11/CMakeLists.txt +++ b/server/X11/CMakeLists.txt @@ -45,7 +45,15 @@ if(XFIXES_FOUND) target_link_libraries(xfreerdp-server ${XFIXES_LIBRARIES}) endif() +find_suggested_package(XTest) +if(XTEST_FOUND) + add_definitions(-DWITH_XTEST) + include_directories(${XTEST_INCLUDE_DIRS}) + target_link_libraries(xfreerdp-server ${XTEST_LIBRARIES}) +endif() + target_link_libraries(xfreerdp-server freerdp-core) target_link_libraries(xfreerdp-server freerdp-codec) target_link_libraries(xfreerdp-server freerdp-utils) +target_link_libraries(xfreerdp-server freerdp-gdi) target_link_libraries(xfreerdp-server ${X11_LIBRARIES}) diff --git a/server/X11/xf_peer.c b/server/X11/xf_peer.c index 2aaa09160..1f49dd3ad 100644 --- a/server/X11/xf_peer.c +++ b/server/X11/xf_peer.c @@ -21,13 +21,14 @@ #include #include #include +#include #include #include #include +#include #include #include #include -#include extern char* xf_pcap_file; extern boolean xf_pcap_dump_realtime; @@ -107,6 +108,8 @@ xfInfo* xf_info_init() xfi->display = XOpenDisplay(NULL); + XInitThreads(); + if (xfi->display == NULL) { printf("failed to open display: %s\n", XDisplayName(NULL)); @@ -201,10 +204,35 @@ void xf_peer_context_free(freerdp_peer* client, xfPeerContext* context) void xf_peer_init(freerdp_peer* client) { + xfPeerContext* xfp; + client->context_size = sizeof(xfPeerContext); client->ContextNew = (psPeerContextNew) xf_peer_context_new; client->ContextFree = (psPeerContextFree) xf_peer_context_free; freerdp_peer_context_new(client); + + xfp = (xfPeerContext*) client->context; + + xfp->pipe_fd[0] = -1; + xfp->pipe_fd[1] = -1; + + if (pipe(xfp->pipe_fd) < 0) + printf("xf_peer_init: pipe failed\n"); + + xfp->thread = 0; + xfp->activations = 0; + + xfp->stopwatch = stopwatch_create(); + + xfp->hdc = gdi_GetDC(); + + xfp->hdc->hwnd = (HGDI_WND) malloc(sizeof(GDI_WND)); + xfp->hdc->hwnd->invalid = gdi_CreateRectRgn(0, 0, 0, 0); + xfp->hdc->hwnd->invalid->null = 1; + + xfp->hdc->hwnd->count = 32; + xfp->hdc->hwnd->cinvalid = (HGDI_RGN) malloc(sizeof(GDI_RGN) * xfp->hdc->hwnd->count); + xfp->hdc->hwnd->ninvalid = 0; } STREAM* xf_peer_stream_init(xfPeerContext* context) @@ -214,78 +242,132 @@ STREAM* xf_peer_stream_init(xfPeerContext* context) return context->s; } -void xf_peer_live_rfx(freerdp_peer* client) +int xf_is_event_set(xfPeerContext* xfp) { - STREAM* s; - uint8* data; - xfInfo* xfi; - XImage* image; - XEvent xevent; - RFX_RECT rect; - rdpUpdate* update; - xfPeerContext* xfp; - SURFACE_BITS_COMMAND* cmd; + fd_set rfds; + int num_set; + struct timeval time; - update = client->update; - xfp = (xfPeerContext*) client->context; - xfi = (xfInfo*) xfp->info; - cmd = &update->surface_bits_command; - data = (uint8*) xmalloc(xfi->width * xfi->height * 3); + FD_ZERO(&rfds); + FD_SET(xfp->pipe_fd[0], &rfds); + memset(&time, 0, sizeof(time)); + num_set = select(xfp->pipe_fd[0] + 1, &rfds, 0, 0, &time); - while (XPending(xfi->display)) + return (num_set == 1); +} + +void xf_signal_event(xfPeerContext* xfp) +{ + int length; + + length = write(xfp->pipe_fd[1], "sig", 4); + + if (length != 4) + printf("xf_signal_event: error\n"); +} + +void xf_clear_event(xfPeerContext* xfp) +{ + int length; + + while (xf_is_event_set(xfp)) { - memset(&xevent, 0, sizeof(xevent)); - XNextEvent(xfi->display, &xevent); + length = read(xfp->pipe_fd[0], &length, 4); - if (xevent.type == xfi->xdamage_notify_event) + if (length != 4) + printf("xf_clear_event: error\n"); + } +} + +void* xf_monitor_graphics(void* param) +{ + xfInfo* xfi; + XEvent xevent; + uint32 sec, usec; + XRectangle region; + xfPeerContext* xfp; + freerdp_peer* client; + int x, y, width, height; + XDamageNotifyEvent* notify; + + client = (freerdp_peer*) param; + xfp = (xfPeerContext*) client->context; + xfi = xfp->info; + + xfp->capture_buffer = (uint8*) xmalloc(xfi->width * xfi->height * 3); + + pthread_detach(pthread_self()); + + stopwatch_start(xfp->stopwatch); + + while (1) + { + while (XPending(xfi->display)) { - XRectangle region; - int x, y, width, height; - XDamageNotifyEvent* notify; - - notify = (XDamageNotifyEvent*) &xevent; - - x = notify->area.x; - y = notify->area.y; - width = notify->area.width; - height = notify->area.height; + memset(&xevent, 0, sizeof(xevent)); + XNextEvent(xfi->display, &xevent); - region.x = x; - region.y = y; - region.width = width; - region.height = height; + if (xevent.type == xfi->xdamage_notify_event) + { + notify = (XDamageNotifyEvent*) &xevent; + + x = notify->area.x; + y = notify->area.y; + width = notify->area.width; + height = notify->area.height; + + region.x = x; + region.y = y; + region.width = width; + region.height = height; #ifdef WITH_XFIXES - XFixesSetRegion(xfi->display, xfi->xdamage_region, ®ion, 1); - XDamageSubtract(xfi->display, xfi->xdamage, xfi->xdamage_region, None); + XFixesSetRegion(xfi->display, xfi->xdamage_region, ®ion, 1); + XDamageSubtract(xfi->display, xfi->xdamage, xfi->xdamage_region, None); #endif - - printf("XDamageNotify: x:%d y:%d width:%d height:%d\n", x, y, width, height); - s = xf_peer_stream_init(xfp); - - image = xf_snapshot(xfi, x, y, width, height); - freerdp_image_convert((uint8*) image->data, data, width, height, 32, 24, xfi->clrconv); - - rect.x = 0; - rect.y = 0; - rect.width = width; - rect.height = height; - rfx_compose_message(xfp->rfx_context, s, &rect, 1, data, width, height, width * 3); - - cmd->destLeft = x; - cmd->destTop = y; - cmd->destRight = width; - cmd->destBottom = height; - cmd->bpp = 32; - cmd->codecID = client->settings->rfx_codec_id; - cmd->width = width; - cmd->height = height; - cmd->bitmapDataLength = stream_get_length(s); - cmd->bitmapData = stream_get_head(s); - update->SurfaceBits(update->context, cmd); + gdi_InvalidateRegion(xfp->hdc, x, y, width, height); + + stopwatch_stop(xfp->stopwatch); + stopwatch_get_elapsed_time_in_useconds(xfp->stopwatch, &sec, &usec); + + if ((sec > 0) || (usec > 100)) + break; + } } + + stopwatch_stop(xfp->stopwatch); + stopwatch_get_elapsed_time_in_useconds(xfp->stopwatch, &sec, &usec); + + if ((sec > 0) || (usec > 100)) + { + HGDI_RGN region; + + stopwatch_reset(xfp->stopwatch); + stopwatch_start(xfp->stopwatch); + + region = xfp->hdc->hwnd->invalid; + + xf_signal_event(xfp); + + while (region->null == 0) + { + freerdp_usleep(33); + } + } + + freerdp_usleep(33); } + + return NULL; +} + +void xf_peer_live_rfx(freerdp_peer* client) +{ + xfPeerContext* xfp = (xfPeerContext*) client->context; + + if (xfp->activations == 1) + pthread_create(&(xfp->thread), 0, xf_monitor_graphics, (void*) client); } static boolean xf_peer_sleep_tsdiff(uint32 *old_sec, uint32 *old_usec, uint32 new_sec, uint32 new_usec) @@ -363,6 +445,96 @@ void xf_peer_dump_rfx(freerdp_peer* client) } } +void xf_peer_rfx_update(freerdp_peer* client, int x, int y, int width, int height) +{ + STREAM* s; + xfInfo* xfi; + RFX_RECT rect; + XImage* image; + rdpUpdate* update; + xfPeerContext* xfp; + SURFACE_BITS_COMMAND* cmd; + + update = client->update; + xfp = (xfPeerContext*) client->context; + cmd = &update->surface_bits_command; + xfi = xfp->info; + + if (width * height <= 0) + return; + + s = xf_peer_stream_init(xfp); + + image = xf_snapshot(xfi, x, y, width, height); + + freerdp_image_convert((uint8*) image->data, xfp->capture_buffer, width, height, 32, 24, xfi->clrconv); + + rect.x = 0; + rect.y = 0; + rect.width = width; + rect.height = height; + + rfx_compose_message(xfp->rfx_context, s, &rect, 1, xfp->capture_buffer, width, height, width * 3); + + cmd->destLeft = x; + cmd->destTop = y; + cmd->destRight = width; + cmd->destBottom = height; + cmd->bpp = 32; + cmd->codecID = client->settings->rfx_codec_id; + cmd->width = width; + cmd->height = height; + cmd->bitmapDataLength = stream_get_length(s); + cmd->bitmapData = stream_get_head(s); + + update->SurfaceBits(update->context, cmd); +} + +boolean xf_peer_get_fds(freerdp_peer* client, void** rfds, int* rcount) +{ + xfPeerContext* xfp = (xfPeerContext*) client->context; + + if (xfp->pipe_fd[0] == -1) + return true; + + rfds[*rcount] = (void *)(long) xfp->pipe_fd[0]; + (*rcount)++; + + return true; +} + +boolean xf_peer_check_fds(freerdp_peer* client) +{ + xfInfo* xfi; + xfPeerContext* xfp; + + xfp = (xfPeerContext*) client->context; + xfi = xfp->info; + + if (xfp->pipe_fd[0] == -1) + return true; + + if (xfp->activated == false) + return true; + + if (xf_is_event_set(xfp)) + { + HGDI_RGN region; + + xf_clear_event(xfp); + + region = xfp->hdc->hwnd->invalid; + + if (region->null) + return true; + + xf_peer_rfx_update(client, region->x, region->y, region->w, region->h); + region->null = true; + } + + return true; +} + boolean xf_peer_capabilities(freerdp_peer* client) { return true; @@ -423,6 +595,7 @@ boolean xf_peer_activate(freerdp_peer* client) else { xf_peer_live_rfx(client); + xfp->activations++; } return true; @@ -465,11 +638,21 @@ void xf_peer_unicode_keyboard_event(rdpInput* input, uint16 code) void xf_peer_mouse_event(rdpInput* input, uint16 flags, uint16 x, uint16 y) { +#ifdef WITH_XTEST + //xfInfo* xfi = ((xfPeerContext*) input->context)->info; + //XTestFakeMotionEvent(xfi->display, 0, x, y, CurrentTime); +#endif + printf("Client sent a mouse event (flags:0x%X pos:%d,%d)\n", flags, x, y); } void xf_peer_extended_mouse_event(rdpInput* input, uint16 flags, uint16 x, uint16 y) { +#ifdef WITH_XTEST + //xfInfo* xfi = ((xfPeerContext*) input->context)->info; + //XTestFakeMotionEvent(xfi->display, 0, x, y, CurrentTime); +#endif + printf("Client sent an extended mouse event (flags:0x%X pos:%d,%d)\n", flags, x, y); } @@ -516,6 +699,11 @@ void* xf_peer_main_loop(void* arg) printf("Failed to get FreeRDP file descriptor\n"); break; } + if (xf_peer_get_fds(client, rfds, &rcount) != true) + { + printf("Failed to get xfreerdp file descriptor\n"); + break; + } max_fds = 0; FD_ZERO(&rfds_set); @@ -547,7 +735,15 @@ void* xf_peer_main_loop(void* arg) } if (client->CheckFileDescriptor(client) != true) + { + printf("Failed to check freerdp file descriptor\n"); break; + } + if ((xf_peer_check_fds(client)) != true) + { + printf("Failed to check xfreerdp file descriptor\n"); + break; + } } printf("Client %s disconnected.\n", client->hostname); diff --git a/server/X11/xf_peer.h b/server/X11/xf_peer.h index 8a17a544f..0a412c552 100644 --- a/server/X11/xf_peer.h +++ b/server/X11/xf_peer.h @@ -20,9 +20,13 @@ #ifndef __XF_PEER_H #define __XF_PEER_H +#include +#include +#include #include #include #include +#include #include "xfreerdp.h" @@ -30,10 +34,16 @@ struct xf_peer_context { rdpContext _p; + HGDI_DC hdc; STREAM* s; xfInfo* info; + int pipe_fd[2]; boolean activated; RFX_CONTEXT* rfx_context; + uint8* capture_buffer; + pthread_t thread; + int activations; + STOPWATCH* stopwatch; }; typedef struct xf_peer_context xfPeerContext; diff --git a/server/X11/xfreerdp.h b/server/X11/xfreerdp.h index 67ce624eb..a647c8dc4 100644 --- a/server/X11/xfreerdp.h +++ b/server/X11/xfreerdp.h @@ -26,6 +26,10 @@ #include #endif +#ifdef WITH_XTEST +#include +#endif + #ifdef WITH_XDAMAGE #include #endif