Milestone 5: deliver embedded RDP sessions and lifecycle hardening
This commit is contained in:
196
third_party/FreeRDP/server/shadow/CMakeLists.txt
vendored
Normal file
196
third_party/FreeRDP/server/shadow/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP Shadow Server cmake build script
|
||||
#
|
||||
# Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
#
|
||||
# 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.
|
||||
|
||||
# freerdp-shadow library
|
||||
|
||||
set(MODULE_NAME "freerdp-shadow")
|
||||
|
||||
set(SRCS
|
||||
shadow_client.c
|
||||
shadow_client.h
|
||||
shadow_lobby.c
|
||||
shadow_lobby.h
|
||||
shadow_input.c
|
||||
shadow_input.h
|
||||
shadow_screen.c
|
||||
shadow_screen.h
|
||||
shadow_surface.c
|
||||
shadow_surface.h
|
||||
shadow_encoder.c
|
||||
shadow_encoder.h
|
||||
shadow_capture.c
|
||||
shadow_capture.h
|
||||
shadow_channels.c
|
||||
shadow_channels.h
|
||||
shadow_encomsp.c
|
||||
shadow_encomsp.h
|
||||
shadow_remdesk.c
|
||||
shadow_remdesk.h
|
||||
shadow_rdpsnd.c
|
||||
shadow_rdpsnd.h
|
||||
shadow_audin.c
|
||||
shadow_audin.h
|
||||
shadow_rdpgfx.c
|
||||
shadow_rdpgfx.h
|
||||
shadow_subsystem.c
|
||||
shadow_subsystem.h
|
||||
shadow_mcevent.c
|
||||
shadow_mcevent.h
|
||||
shadow_server.c
|
||||
shadow.h
|
||||
)
|
||||
|
||||
if(WITH_RDTK)
|
||||
if(NOT FREERDP_UNIFIED_BUILD)
|
||||
find_package(rdtk 0 REQUIRED)
|
||||
include_directories(SYSTEM ${RDTK_INCLUDE_DIR})
|
||||
else()
|
||||
include_directories(${PROJECT_SOURCE_DIR}/rdtk/include)
|
||||
include_directories(${PROJECT_BINARY_DIR}/rdtk/include)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
addtargetwithresourcefile(${MODULE_NAME} "FALSE" "${FREERDP_VERSION}" SRCS)
|
||||
|
||||
if(WITH_RDTK)
|
||||
target_compile_definitions(${MODULE_NAME} PRIVATE WITH_RDTK)
|
||||
list(APPEND LIBS rdtk)
|
||||
endif()
|
||||
|
||||
list(APPEND LIBS freerdp freerdp-server winpr winpr-tools)
|
||||
|
||||
target_include_directories(${MODULE_NAME} INTERFACE $<INSTALL_INTERFACE:include>)
|
||||
target_link_libraries(${MODULE_NAME} PRIVATE ${LIBS})
|
||||
|
||||
installwithrpath(
|
||||
TARGETS
|
||||
${MODULE_NAME}
|
||||
COMPONENT
|
||||
server
|
||||
EXPORT
|
||||
FreeRDP-ShadowTargets
|
||||
ARCHIVE
|
||||
DESTINATION
|
||||
${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY
|
||||
DESTINATION
|
||||
${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME
|
||||
DESTINATION
|
||||
${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Server/shadow")
|
||||
|
||||
# subsystem library
|
||||
|
||||
set(MODULE_NAME "freerdp-shadow-subsystem")
|
||||
|
||||
set(SRCS shadow_subsystem_builtin.c)
|
||||
|
||||
option(WITH_SHADOW_SUBSYSTEM "Build actual shadow platform subsystem implementation" ON)
|
||||
if(WITH_SHADOW_SUBSYSTEM)
|
||||
if(WIN32)
|
||||
add_subdirectory(Win)
|
||||
elseif(NOT APPLE)
|
||||
add_subdirectory(X11)
|
||||
elseif(APPLE AND NOT IOS)
|
||||
add_subdirectory(Mac)
|
||||
endif()
|
||||
else()
|
||||
add_subdirectory(Sample)
|
||||
endif()
|
||||
|
||||
addtargetwithresourcefile(${MODULE_NAME} FALSE "${FREERDP_VERSION}" SRCS)
|
||||
|
||||
list(APPEND LIBS freerdp-shadow-subsystem-impl freerdp-shadow freerdp winpr)
|
||||
|
||||
target_include_directories(${MODULE_NAME} INTERFACE $<INSTALL_INTERFACE:include>)
|
||||
target_link_libraries(${MODULE_NAME} PRIVATE ${LIBS})
|
||||
|
||||
if(NOT BUILD_SHARED_LIBS)
|
||||
installwithrpath(
|
||||
TARGETS freerdp-shadow-subsystem-impl DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT FreeRDP-ShadowTargets
|
||||
)
|
||||
endif()
|
||||
|
||||
installwithrpath(
|
||||
TARGETS
|
||||
${MODULE_NAME}
|
||||
COMPONENT
|
||||
server
|
||||
EXPORT
|
||||
FreeRDP-ShadowTargets
|
||||
ARCHIVE
|
||||
DESTINATION
|
||||
${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY
|
||||
DESTINATION
|
||||
${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME
|
||||
DESTINATION
|
||||
${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Server/shadow")
|
||||
|
||||
# command-line executable
|
||||
|
||||
option(WITH_SERVER_SHADOW_CLI "Build shadow server cli tool" ON)
|
||||
if(WITH_SERVER_SHADOW_CLI)
|
||||
add_subdirectory(cli)
|
||||
endif()
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Server/shadow")
|
||||
|
||||
# Do not set Requires.Private if not a static build
|
||||
if(NOT BUILD_SHARED_LIBS)
|
||||
set(FREERDP_SHADOW_PC_REQUIRES_PRIVATE "freerdp${FREERDP_API_VERSION}")
|
||||
set(FREERDP_SHADOW_PC_LIBRARY_PRIVATE "-ldl -lpthread")
|
||||
endif()
|
||||
set(FREERDP_SHADOW_PC_REQUIRES freerdp-server${FREERDP_API_VERSION})
|
||||
|
||||
include(pkg-config-install-prefix)
|
||||
cleaning_configure_file(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/freerdp-shadow.pc.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/freerdp-shadow${FREERDP_VERSION_MAJOR}.pc @ONLY
|
||||
)
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/freerdp-shadow${FREERDP_VERSION_MAJOR}.pc
|
||||
DESTINATION ${PKG_CONFIG_PC_INSTALL_DIR}
|
||||
)
|
||||
|
||||
export(PACKAGE freerdp-shadow)
|
||||
|
||||
setfreerdpcmakeinstalldir(FREERDP_SERVER_CMAKE_INSTALL_DIR "FreeRDP-Shadow${FREERDP_VERSION_MAJOR}")
|
||||
|
||||
configure_package_config_file(
|
||||
FreeRDP-ShadowConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/FreeRDP-ShadowConfig.cmake
|
||||
INSTALL_DESTINATION ${FREERDP_SERVER_CMAKE_INSTALL_DIR} PATH_VARS FREERDP_INCLUDE_DIR
|
||||
)
|
||||
|
||||
write_basic_package_version_file(
|
||||
${CMAKE_CURRENT_BINARY_DIR}/FreeRDP-ShadowConfigVersion.cmake VERSION ${FREERDP_VERSION}
|
||||
COMPATIBILITY SameMajorVersion
|
||||
)
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/FreeRDP-ShadowConfig.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/FreeRDP-ShadowConfigVersion.cmake
|
||||
DESTINATION ${FREERDP_SERVER_CMAKE_INSTALL_DIR}
|
||||
)
|
||||
|
||||
install(EXPORT FreeRDP-ShadowTargets DESTINATION ${FREERDP_SERVER_CMAKE_INSTALL_DIR})
|
||||
14
third_party/FreeRDP/server/shadow/FreeRDP-ShadowConfig.cmake.in
vendored
Normal file
14
third_party/FreeRDP/server/shadow/FreeRDP-ShadowConfig.cmake.in
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
include(CMakeFindDependencyMacro)
|
||||
find_dependency(WinPR @FREERDP_VERSION@)
|
||||
find_dependency(FreeRDP @FREERDP_VERSION@)
|
||||
find_dependency(FreeRDP-Server @FREERDP_VERSION@)
|
||||
|
||||
@PACKAGE_INIT@
|
||||
|
||||
set(FreeRDP-Shadow_VERSION_MAJOR "@FREERDP_VERSION_MAJOR@")
|
||||
set(FreeRDP-Shadow_VERSION_MINOR "@FREERDP_VERSION_MINOR@")
|
||||
set(FreeRDP-Shadow_VERSION_REVISION "@FREERDP_VERSION_REVISION@")
|
||||
|
||||
set_and_check(FreeRDP-Shadow_INCLUDE_DIR "@PACKAGE_FREERDP_INCLUDE_DIR@")
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/FreeRDP-ShadowTargets.cmake")
|
||||
21
third_party/FreeRDP/server/shadow/Mac/CMakeLists.txt
vendored
Normal file
21
third_party/FreeRDP/server/shadow/Mac/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
include(WarnUnmaintained)
|
||||
warn_unmaintained("mac shadow server subsystem" "-DWITH_SHADOW_SUBSYSTEM=OFF")
|
||||
|
||||
find_library(IOKIT IOKit REQUIRED)
|
||||
find_library(IOSURFACE IOSurface REQUIRED)
|
||||
find_library(CARBON Carbon REQUIRED)
|
||||
find_package(PAM)
|
||||
|
||||
set(LIBS ${IOKIT} ${IOSURFACE} ${CARBON})
|
||||
|
||||
if(PAM_FOUND)
|
||||
add_compile_definitions(WITH_PAM)
|
||||
include_directories(SYSTEM ${PAM_INCLUDE_DIR})
|
||||
list(APPEND LIBS ${PAM_LIBRARY})
|
||||
else()
|
||||
message("building without PAM authentication support")
|
||||
endif()
|
||||
|
||||
add_compile_definitions(WITH_SHADOW_MAC)
|
||||
add_library(freerdp-shadow-subsystem-impl STATIC mac_shadow.h mac_shadow.c)
|
||||
target_link_libraries(freerdp-shadow-subsystem-impl PRIVATE ${LIBS})
|
||||
681
third_party/FreeRDP/server/shadow/Mac/mac_shadow.c
vendored
Normal file
681
third_party/FreeRDP/server/shadow/Mac/mac_shadow.c
vendored
Normal file
@@ -0,0 +1,681 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/input.h>
|
||||
#include <winpr/sysinfo.h>
|
||||
|
||||
#include <freerdp/server/server-common.h>
|
||||
#include <freerdp/codec/color.h>
|
||||
#include <freerdp/codec/region.h>
|
||||
#include <freerdp/log.h>
|
||||
|
||||
#include "mac_shadow.h"
|
||||
|
||||
#define TAG SERVER_TAG("shadow.mac")
|
||||
|
||||
static macShadowSubsystem* g_Subsystem = nullptr;
|
||||
|
||||
static BOOL mac_shadow_input_synchronize_event(rdpShadowSubsystem* subsystem,
|
||||
rdpShadowClient* client, UINT32 flags)
|
||||
{
|
||||
if (!subsystem || !client)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL mac_shadow_input_keyboard_event(rdpShadowSubsystem* subsystem, rdpShadowClient* client,
|
||||
UINT16 flags, UINT8 code)
|
||||
{
|
||||
DWORD vkcode;
|
||||
DWORD keycode;
|
||||
BOOL extended;
|
||||
CGEventRef kbdEvent;
|
||||
CGEventSourceRef source;
|
||||
extended = (flags & KBD_FLAGS_EXTENDED) ? TRUE : FALSE;
|
||||
|
||||
if (!subsystem || !client)
|
||||
return FALSE;
|
||||
|
||||
if (extended)
|
||||
code |= KBDEXT;
|
||||
|
||||
vkcode = GetVirtualKeyCodeFromVirtualScanCode(code, 4);
|
||||
|
||||
if (extended)
|
||||
vkcode |= KBDEXT;
|
||||
|
||||
keycode = GetKeycodeFromVirtualKeyCode(vkcode, WINPR_KEYCODE_TYPE_APPLE);
|
||||
|
||||
source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
|
||||
|
||||
if (flags & KBD_FLAGS_DOWN)
|
||||
{
|
||||
kbdEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode)keycode, TRUE);
|
||||
CGEventPost(kCGHIDEventTap, kbdEvent);
|
||||
CFRelease(kbdEvent);
|
||||
}
|
||||
else if (flags & KBD_FLAGS_RELEASE)
|
||||
{
|
||||
kbdEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode)keycode, FALSE);
|
||||
CGEventPost(kCGHIDEventTap, kbdEvent);
|
||||
CFRelease(kbdEvent);
|
||||
}
|
||||
|
||||
CFRelease(source);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL mac_shadow_input_unicode_keyboard_event(rdpShadowSubsystem* subsystem,
|
||||
rdpShadowClient* client, UINT16 flags,
|
||||
UINT16 code)
|
||||
{
|
||||
if (!subsystem || !client)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL mac_shadow_input_mouse_event(rdpShadowSubsystem* subsystem, rdpShadowClient* client,
|
||||
UINT16 flags, UINT16 x, UINT16 y)
|
||||
{
|
||||
macShadowSubsystem* mac = (macShadowSubsystem*)subsystem;
|
||||
UINT32 scrollX = 0;
|
||||
UINT32 scrollY = 0;
|
||||
CGWheelCount wheelCount = 2;
|
||||
|
||||
if (!subsystem || !client)
|
||||
return FALSE;
|
||||
|
||||
if (flags & PTR_FLAGS_WHEEL)
|
||||
{
|
||||
scrollY = flags & WheelRotationMask;
|
||||
|
||||
if (flags & PTR_FLAGS_WHEEL_NEGATIVE)
|
||||
{
|
||||
scrollY = -(flags & WheelRotationMask) / 392;
|
||||
}
|
||||
else
|
||||
{
|
||||
scrollY = (flags & WheelRotationMask) / 120;
|
||||
}
|
||||
|
||||
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
|
||||
CGEventRef scroll = CGEventCreateScrollWheelEvent(source, kCGScrollEventUnitLine,
|
||||
wheelCount, scrollY, scrollX);
|
||||
CGEventPost(kCGHIDEventTap, scroll);
|
||||
CFRelease(scroll);
|
||||
CFRelease(source);
|
||||
}
|
||||
else
|
||||
{
|
||||
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
|
||||
CGEventType mouseType = kCGEventNull;
|
||||
CGMouseButton mouseButton = kCGMouseButtonLeft;
|
||||
|
||||
if (flags & PTR_FLAGS_MOVE)
|
||||
{
|
||||
if (mac->mouseDownLeft)
|
||||
mouseType = kCGEventLeftMouseDragged;
|
||||
else if (mac->mouseDownRight)
|
||||
mouseType = kCGEventRightMouseDragged;
|
||||
else if (mac->mouseDownOther)
|
||||
mouseType = kCGEventOtherMouseDragged;
|
||||
else
|
||||
mouseType = kCGEventMouseMoved;
|
||||
|
||||
CGEventRef move =
|
||||
CGEventCreateMouseEvent(source, mouseType, CGPointMake(x, y), mouseButton);
|
||||
CGEventPost(kCGHIDEventTap, move);
|
||||
CFRelease(move);
|
||||
}
|
||||
|
||||
if (flags & PTR_FLAGS_BUTTON1)
|
||||
{
|
||||
mouseButton = kCGMouseButtonLeft;
|
||||
|
||||
if (flags & PTR_FLAGS_DOWN)
|
||||
{
|
||||
mouseType = kCGEventLeftMouseDown;
|
||||
mac->mouseDownLeft = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
mouseType = kCGEventLeftMouseUp;
|
||||
mac->mouseDownLeft = FALSE;
|
||||
}
|
||||
}
|
||||
else if (flags & PTR_FLAGS_BUTTON2)
|
||||
{
|
||||
mouseButton = kCGMouseButtonRight;
|
||||
|
||||
if (flags & PTR_FLAGS_DOWN)
|
||||
{
|
||||
mouseType = kCGEventRightMouseDown;
|
||||
mac->mouseDownRight = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
mouseType = kCGEventRightMouseUp;
|
||||
mac->mouseDownRight = FALSE;
|
||||
}
|
||||
}
|
||||
else if (flags & PTR_FLAGS_BUTTON3)
|
||||
{
|
||||
mouseButton = kCGMouseButtonCenter;
|
||||
|
||||
if (flags & PTR_FLAGS_DOWN)
|
||||
{
|
||||
mouseType = kCGEventOtherMouseDown;
|
||||
mac->mouseDownOther = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
mouseType = kCGEventOtherMouseUp;
|
||||
mac->mouseDownOther = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
CGEventRef mouseEvent =
|
||||
CGEventCreateMouseEvent(source, mouseType, CGPointMake(x, y), mouseButton);
|
||||
CGEventPost(kCGHIDEventTap, mouseEvent);
|
||||
CFRelease(mouseEvent);
|
||||
CFRelease(source);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL mac_shadow_input_extended_mouse_event(rdpShadowSubsystem* subsystem,
|
||||
rdpShadowClient* client, UINT16 flags, UINT16 x,
|
||||
UINT16 y)
|
||||
{
|
||||
if (!subsystem || !client)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int mac_shadow_detect_monitors(macShadowSubsystem* subsystem)
|
||||
{
|
||||
size_t wide, high;
|
||||
MONITOR_DEF* monitor;
|
||||
CGDirectDisplayID displayId;
|
||||
displayId = CGMainDisplayID();
|
||||
CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displayId);
|
||||
subsystem->pixelWidth = CGDisplayModeGetPixelWidth(mode);
|
||||
subsystem->pixelHeight = CGDisplayModeGetPixelHeight(mode);
|
||||
wide = CGDisplayPixelsWide(displayId);
|
||||
high = CGDisplayPixelsHigh(displayId);
|
||||
CGDisplayModeRelease(mode);
|
||||
subsystem->retina = ((subsystem->pixelWidth / wide) == 2) ? TRUE : FALSE;
|
||||
|
||||
if (subsystem->retina)
|
||||
{
|
||||
subsystem->width = wide;
|
||||
subsystem->height = high;
|
||||
}
|
||||
else
|
||||
{
|
||||
subsystem->width = subsystem->pixelWidth;
|
||||
subsystem->height = subsystem->pixelHeight;
|
||||
}
|
||||
|
||||
subsystem->common.numMonitors = 1;
|
||||
monitor = &(subsystem->common.monitors[0]);
|
||||
monitor->left = 0;
|
||||
monitor->top = 0;
|
||||
monitor->right = subsystem->width;
|
||||
monitor->bottom = subsystem->height;
|
||||
monitor->flags = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int mac_shadow_capture_start(macShadowSubsystem* subsystem)
|
||||
{
|
||||
CGError err;
|
||||
err = CGDisplayStreamStart(subsystem->stream);
|
||||
|
||||
if (err != kCGErrorSuccess)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int mac_shadow_capture_stop(macShadowSubsystem* subsystem)
|
||||
{
|
||||
CGError err;
|
||||
err = CGDisplayStreamStop(subsystem->stream);
|
||||
|
||||
if (err != kCGErrorSuccess)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int mac_shadow_capture_get_dirty_region(macShadowSubsystem* subsystem)
|
||||
{
|
||||
size_t numRects;
|
||||
const CGRect* rects;
|
||||
RECTANGLE_16 invalidRect;
|
||||
rdpShadowSurface* surface = subsystem->common.server->surface;
|
||||
rects = CGDisplayStreamUpdateGetRects(subsystem->lastUpdate, kCGDisplayStreamUpdateDirtyRects,
|
||||
&numRects);
|
||||
|
||||
if (!numRects)
|
||||
return -1;
|
||||
|
||||
for (size_t index = 0; index < numRects; index++)
|
||||
{
|
||||
invalidRect.left = (UINT16)rects[index].origin.x;
|
||||
invalidRect.top = (UINT16)rects[index].origin.y;
|
||||
invalidRect.right = invalidRect.left + (UINT16)rects[index].size.width;
|
||||
invalidRect.bottom = invalidRect.top + (UINT16)rects[index].size.height;
|
||||
|
||||
if (subsystem->retina)
|
||||
{
|
||||
/* scale invalid rect */
|
||||
invalidRect.left /= 2;
|
||||
invalidRect.top /= 2;
|
||||
invalidRect.right /= 2;
|
||||
invalidRect.bottom /= 2;
|
||||
}
|
||||
|
||||
region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int freerdp_image_copy_from_retina(BYTE* pDstData, DWORD DstFormat, int nDstStep, int nXDst,
|
||||
int nYDst, int nWidth, int nHeight, BYTE* pSrcData,
|
||||
int nSrcStep, int nXSrc, int nYSrc)
|
||||
{
|
||||
BYTE* pSrcPixel;
|
||||
BYTE* pDstPixel;
|
||||
int nSrcPad;
|
||||
int nDstPad;
|
||||
int srcBitsPerPixel;
|
||||
int srcBytesPerPixel;
|
||||
int dstBitsPerPixel;
|
||||
int dstBytesPerPixel;
|
||||
srcBitsPerPixel = 24;
|
||||
srcBytesPerPixel = 8;
|
||||
|
||||
if (nSrcStep < 0)
|
||||
nSrcStep = srcBytesPerPixel * nWidth;
|
||||
|
||||
dstBitsPerPixel = FreeRDPGetBitsPerPixel(DstFormat);
|
||||
dstBytesPerPixel = FreeRDPGetBytesPerPixel(DstFormat);
|
||||
|
||||
if (nDstStep < 0)
|
||||
nDstStep = dstBytesPerPixel * nWidth;
|
||||
|
||||
nSrcPad = (nSrcStep - (nWidth * srcBytesPerPixel));
|
||||
nDstPad = (nDstStep - (nWidth * dstBytesPerPixel));
|
||||
pSrcPixel = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 4)];
|
||||
pDstPixel = &pDstData[(nYDst * nDstStep) + (nXDst * 4)];
|
||||
|
||||
for (int y = 0; y < nHeight; y++)
|
||||
{
|
||||
for (int x = 0; x < nWidth; x++)
|
||||
{
|
||||
UINT32 R, G, B;
|
||||
UINT32 color;
|
||||
/* simple box filter scaling, could be improved with better algorithm */
|
||||
B = pSrcPixel[0] + pSrcPixel[4] + pSrcPixel[nSrcStep + 0] + pSrcPixel[nSrcStep + 4];
|
||||
G = pSrcPixel[1] + pSrcPixel[5] + pSrcPixel[nSrcStep + 1] + pSrcPixel[nSrcStep + 5];
|
||||
R = pSrcPixel[2] + pSrcPixel[6] + pSrcPixel[nSrcStep + 2] + pSrcPixel[nSrcStep + 6];
|
||||
pSrcPixel += 8;
|
||||
color = FreeRDPGetColor(DstFormat, R >> 2, G >> 2, B >> 2, 0xFF);
|
||||
FreeRDPWriteColor(pDstPixel, DstFormat, color);
|
||||
pDstPixel += dstBytesPerPixel;
|
||||
}
|
||||
|
||||
pSrcPixel = &pSrcPixel[nSrcPad + nSrcStep];
|
||||
pDstPixel = &pDstPixel[nDstPad];
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void (^mac_capture_stream_handler)(
|
||||
CGDisplayStreamFrameStatus, uint64_t, IOSurfaceRef,
|
||||
CGDisplayStreamUpdateRef) = ^(CGDisplayStreamFrameStatus status, uint64_t displayTime,
|
||||
IOSurfaceRef frameSurface, CGDisplayStreamUpdateRef updateRef) {
|
||||
int x, y;
|
||||
int count;
|
||||
int width;
|
||||
int height;
|
||||
int nSrcStep;
|
||||
BOOL empty;
|
||||
BYTE* pSrcData;
|
||||
RECTANGLE_16 surfaceRect;
|
||||
const RECTANGLE_16* extents;
|
||||
macShadowSubsystem* subsystem = g_Subsystem;
|
||||
rdpShadowServer* server = subsystem->common.server;
|
||||
rdpShadowSurface* surface = server->surface;
|
||||
count = ArrayList_Count(server->clients);
|
||||
|
||||
if (count < 1)
|
||||
return;
|
||||
|
||||
EnterCriticalSection(&(surface->lock));
|
||||
mac_shadow_capture_get_dirty_region(subsystem);
|
||||
surfaceRect.left = 0;
|
||||
surfaceRect.top = 0;
|
||||
surfaceRect.right = surface->width;
|
||||
surfaceRect.bottom = surface->height;
|
||||
region16_intersect_rect(&(surface->invalidRegion), &(surface->invalidRegion), &surfaceRect);
|
||||
empty = region16_is_empty(&(surface->invalidRegion));
|
||||
LeaveCriticalSection(&(surface->lock));
|
||||
|
||||
if (!empty)
|
||||
{
|
||||
extents = region16_extents(&(surface->invalidRegion));
|
||||
x = extents->left;
|
||||
y = extents->top;
|
||||
width = extents->right - extents->left;
|
||||
height = extents->bottom - extents->top;
|
||||
IOSurfaceLock(frameSurface, kIOSurfaceLockReadOnly, nullptr);
|
||||
pSrcData = (BYTE*)IOSurfaceGetBaseAddress(frameSurface);
|
||||
nSrcStep = (int)IOSurfaceGetBytesPerRow(frameSurface);
|
||||
|
||||
if (subsystem->retina)
|
||||
{
|
||||
freerdp_image_copy_from_retina(surface->data, surface->format, surface->scanline, x, y,
|
||||
width, height, pSrcData, nSrcStep, x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
freerdp_image_copy_no_overlap(surface->data, surface->format, surface->scanline, x, y,
|
||||
width, height, pSrcData, PIXEL_FORMAT_BGRX32, nSrcStep, x,
|
||||
y, nullptr, FREERDP_FLIP_NONE);
|
||||
}
|
||||
LeaveCriticalSection(&(surface->lock));
|
||||
|
||||
IOSurfaceUnlock(frameSurface, kIOSurfaceLockReadOnly, nullptr);
|
||||
ArrayList_Lock(server->clients);
|
||||
count = ArrayList_Count(server->clients);
|
||||
shadow_subsystem_frame_update(&subsystem->common);
|
||||
|
||||
if (count == 1)
|
||||
{
|
||||
rdpShadowClient* client;
|
||||
client = (rdpShadowClient*)ArrayList_GetItem(server->clients, 0);
|
||||
|
||||
if (client)
|
||||
{
|
||||
subsystem->common.captureFrameRate = shadow_encoder_preferred_fps(client->encoder);
|
||||
}
|
||||
}
|
||||
|
||||
ArrayList_Unlock(server->clients);
|
||||
EnterCriticalSection(&(surface->lock));
|
||||
region16_clear(&(surface->invalidRegion));
|
||||
LeaveCriticalSection(&(surface->lock));
|
||||
}
|
||||
|
||||
if (status != kCGDisplayStreamFrameStatusFrameComplete)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case kCGDisplayStreamFrameStatusFrameIdle:
|
||||
break;
|
||||
|
||||
case kCGDisplayStreamFrameStatusStopped:
|
||||
break;
|
||||
|
||||
case kCGDisplayStreamFrameStatusFrameBlank:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (!subsystem->lastUpdate)
|
||||
{
|
||||
CFRetain(updateRef);
|
||||
subsystem->lastUpdate = updateRef;
|
||||
}
|
||||
else
|
||||
{
|
||||
CGDisplayStreamUpdateRef tmpRef = subsystem->lastUpdate;
|
||||
subsystem->lastUpdate = CGDisplayStreamUpdateCreateMergedUpdate(tmpRef, updateRef);
|
||||
CFRelease(tmpRef);
|
||||
}
|
||||
};
|
||||
|
||||
static int mac_shadow_capture_init(macShadowSubsystem* subsystem)
|
||||
{
|
||||
void* keys[2];
|
||||
void* values[2];
|
||||
CFDictionaryRef opts;
|
||||
CGDirectDisplayID displayId;
|
||||
displayId = CGMainDisplayID();
|
||||
subsystem->captureQueue = dispatch_queue_create("mac.shadow.capture", nullptr);
|
||||
keys[0] = (void*)kCGDisplayStreamShowCursor;
|
||||
values[0] = (void*)kCFBooleanFalse;
|
||||
opts = CFDictionaryCreate(kCFAllocatorDefault, (const void**)keys, (const void**)values, 1,
|
||||
nullptr, nullptr);
|
||||
subsystem->stream = CGDisplayStreamCreateWithDispatchQueue(
|
||||
displayId, subsystem->pixelWidth, subsystem->pixelHeight, 'BGRA', opts,
|
||||
subsystem->captureQueue, mac_capture_stream_handler);
|
||||
CFRelease(opts);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int mac_shadow_screen_grab(macShadowSubsystem* subsystem)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int mac_shadow_subsystem_process_message(macShadowSubsystem* subsystem, wMessage* message)
|
||||
{
|
||||
rdpShadowServer* server = subsystem->common.server;
|
||||
rdpShadowSurface* surface = server->surface;
|
||||
|
||||
switch (message->id)
|
||||
{
|
||||
case SHADOW_MSG_IN_REFRESH_REQUEST_ID:
|
||||
EnterCriticalSection(&(surface->lock));
|
||||
shadow_subsystem_frame_update((rdpShadowSubsystem*)subsystem);
|
||||
LeaveCriticalSection(&(surface->lock));
|
||||
break;
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "Unknown message id: %" PRIu32 "", message->id);
|
||||
break;
|
||||
}
|
||||
|
||||
if (message->Free)
|
||||
message->Free(message);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static DWORD WINAPI mac_shadow_subsystem_thread(LPVOID arg)
|
||||
{
|
||||
macShadowSubsystem* subsystem = (macShadowSubsystem*)arg;
|
||||
DWORD status;
|
||||
DWORD nCount;
|
||||
UINT64 cTime;
|
||||
DWORD dwTimeout;
|
||||
DWORD dwInterval;
|
||||
UINT64 frameTime;
|
||||
HANDLE events[32];
|
||||
wMessage message;
|
||||
wMessagePipe* MsgPipe;
|
||||
MsgPipe = subsystem->common.MsgPipe;
|
||||
nCount = 0;
|
||||
events[nCount++] = MessageQueue_Event(MsgPipe->In);
|
||||
subsystem->common.captureFrameRate = 16;
|
||||
dwInterval = 1000 / subsystem->common.captureFrameRate;
|
||||
frameTime = GetTickCount64() + dwInterval;
|
||||
|
||||
while (1)
|
||||
{
|
||||
cTime = GetTickCount64();
|
||||
dwTimeout = (cTime > frameTime) ? 0 : frameTime - cTime;
|
||||
status = WaitForMultipleObjects(nCount, events, FALSE, dwTimeout);
|
||||
|
||||
if (WaitForSingleObject(MessageQueue_Event(MsgPipe->In), 0) == WAIT_OBJECT_0)
|
||||
{
|
||||
if (MessageQueue_Peek(MsgPipe->In, &message, TRUE))
|
||||
{
|
||||
if (message.id == WMQ_QUIT)
|
||||
break;
|
||||
|
||||
mac_shadow_subsystem_process_message(subsystem, &message);
|
||||
}
|
||||
}
|
||||
|
||||
if ((status == WAIT_TIMEOUT) || (GetTickCount64() > frameTime))
|
||||
{
|
||||
mac_shadow_screen_grab(subsystem);
|
||||
dwInterval = 1000 / subsystem->common.captureFrameRate;
|
||||
frameTime += dwInterval;
|
||||
}
|
||||
}
|
||||
|
||||
ExitThread(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static UINT32 mac_shadow_enum_monitors(MONITOR_DEF* monitors, UINT32 maxMonitors)
|
||||
{
|
||||
int index;
|
||||
size_t wide, high;
|
||||
UINT32 numMonitors = 0;
|
||||
MONITOR_DEF* monitor;
|
||||
CGDirectDisplayID displayId;
|
||||
displayId = CGMainDisplayID();
|
||||
CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displayId);
|
||||
wide = CGDisplayPixelsWide(displayId);
|
||||
high = CGDisplayPixelsHigh(displayId);
|
||||
CGDisplayModeRelease(mode);
|
||||
index = 0;
|
||||
numMonitors = 1;
|
||||
monitor = &monitors[index];
|
||||
monitor->left = 0;
|
||||
monitor->top = 0;
|
||||
monitor->right = (int)wide;
|
||||
monitor->bottom = (int)high;
|
||||
monitor->flags = 1;
|
||||
return numMonitors;
|
||||
}
|
||||
|
||||
static int mac_shadow_subsystem_init(rdpShadowSubsystem* rdpsubsystem)
|
||||
{
|
||||
macShadowSubsystem* subsystem = (macShadowSubsystem*)rdpsubsystem;
|
||||
g_Subsystem = subsystem;
|
||||
|
||||
mac_shadow_detect_monitors(subsystem);
|
||||
mac_shadow_capture_init(subsystem);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int mac_shadow_subsystem_uninit(rdpShadowSubsystem* rdpsubsystem)
|
||||
{
|
||||
macShadowSubsystem* subsystem = (macShadowSubsystem*)rdpsubsystem;
|
||||
if (!subsystem)
|
||||
return -1;
|
||||
|
||||
if (subsystem->lastUpdate)
|
||||
{
|
||||
CFRelease(subsystem->lastUpdate);
|
||||
subsystem->lastUpdate = nullptr;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int mac_shadow_subsystem_start(rdpShadowSubsystem* rdpsubsystem)
|
||||
{
|
||||
macShadowSubsystem* subsystem = (macShadowSubsystem*)rdpsubsystem;
|
||||
HANDLE thread;
|
||||
|
||||
if (!subsystem)
|
||||
return -1;
|
||||
|
||||
mac_shadow_capture_start(subsystem);
|
||||
|
||||
if (!(thread =
|
||||
CreateThread(nullptr, 0, mac_shadow_subsystem_thread, (void*)subsystem, 0, nullptr)))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to create thread");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int mac_shadow_subsystem_stop(rdpShadowSubsystem* subsystem)
|
||||
{
|
||||
if (!subsystem)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void mac_shadow_subsystem_free(rdpShadowSubsystem* subsystem)
|
||||
{
|
||||
if (!subsystem)
|
||||
return;
|
||||
|
||||
mac_shadow_subsystem_uninit(subsystem);
|
||||
free(subsystem);
|
||||
}
|
||||
|
||||
static rdpShadowSubsystem* mac_shadow_subsystem_new(void)
|
||||
{
|
||||
macShadowSubsystem* subsystem = calloc(1, sizeof(macShadowSubsystem));
|
||||
|
||||
if (!subsystem)
|
||||
return nullptr;
|
||||
|
||||
subsystem->common.SynchronizeEvent = mac_shadow_input_synchronize_event;
|
||||
subsystem->common.KeyboardEvent = mac_shadow_input_keyboard_event;
|
||||
subsystem->common.UnicodeKeyboardEvent = mac_shadow_input_unicode_keyboard_event;
|
||||
subsystem->common.MouseEvent = mac_shadow_input_mouse_event;
|
||||
subsystem->common.ExtendedMouseEvent = mac_shadow_input_extended_mouse_event;
|
||||
return &subsystem->common;
|
||||
}
|
||||
|
||||
FREERDP_API const char* ShadowSubsystemName(void)
|
||||
{
|
||||
return "Mac";
|
||||
}
|
||||
|
||||
FREERDP_API int ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints)
|
||||
{
|
||||
char name[] = "mac shadow subsystem";
|
||||
char* arg[] = { name };
|
||||
|
||||
freerdp_server_warn_unmaintained(ARRAYSIZE(arg), arg);
|
||||
pEntryPoints->New = mac_shadow_subsystem_new;
|
||||
pEntryPoints->Free = mac_shadow_subsystem_free;
|
||||
pEntryPoints->Init = mac_shadow_subsystem_init;
|
||||
pEntryPoints->Uninit = mac_shadow_subsystem_uninit;
|
||||
pEntryPoints->Start = mac_shadow_subsystem_start;
|
||||
pEntryPoints->Stop = mac_shadow_subsystem_stop;
|
||||
pEntryPoints->EnumMonitors = mac_shadow_enum_monitors;
|
||||
return 1;
|
||||
}
|
||||
64
third_party/FreeRDP/server/shadow/Mac/mac_shadow.h
vendored
Normal file
64
third_party/FreeRDP/server/shadow/Mac/mac_shadow.h
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_SHADOW_MAC_SHADOW_H
|
||||
#define FREERDP_SERVER_SHADOW_MAC_SHADOW_H
|
||||
|
||||
#include <freerdp/server/shadow.h>
|
||||
|
||||
typedef struct mac_shadow_subsystem macShadowSubsystem;
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
#include <winpr/stream.h>
|
||||
#include <winpr/collections.h>
|
||||
|
||||
#include <dispatch/dispatch.h>
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOSurface/IOSurface.h>
|
||||
#include <CoreVideo/CoreVideo.h>
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
|
||||
struct mac_shadow_subsystem
|
||||
{
|
||||
rdpShadowSubsystem common;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
BOOL retina;
|
||||
int pixelWidth;
|
||||
int pixelHeight;
|
||||
BOOL mouseDownLeft;
|
||||
BOOL mouseDownRight;
|
||||
BOOL mouseDownOther;
|
||||
CGDisplayStreamRef stream;
|
||||
dispatch_queue_t captureQueue;
|
||||
CGDisplayStreamUpdateRef lastUpdate;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_SERVER_SHADOW_MAC_SHADOW_H */
|
||||
1
third_party/FreeRDP/server/shadow/Sample/CMakeLists.txt
vendored
Normal file
1
third_party/FreeRDP/server/shadow/Sample/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
add_library(freerdp-shadow-subsystem-impl STATIC sample_shadow.c sample_shadow.h)
|
||||
189
third_party/FreeRDP/server/shadow/Sample/sample_shadow.c
vendored
Normal file
189
third_party/FreeRDP/server/shadow/Sample/sample_shadow.c
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2025 Armin Novak <anovak@thincast.com>
|
||||
* Copyright 2025 Thincast Technologies GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/sysinfo.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#include <freerdp/codec/color.h>
|
||||
#include <freerdp/codec/region.h>
|
||||
#include <freerdp/server/server-common.h>
|
||||
|
||||
#include "sample_shadow.h"
|
||||
|
||||
#define TAG SERVER_TAG("shadow.sample")
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static BOOL sample_shadow_input_synchronize_event(WINPR_ATTR_UNUSED rdpShadowSubsystem* subsystem,
|
||||
WINPR_ATTR_UNUSED rdpShadowClient* client,
|
||||
WINPR_ATTR_UNUSED UINT32 flags)
|
||||
{
|
||||
WLog_WARN(TAG, "TODO: Implement!");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static BOOL sample_shadow_input_keyboard_event(WINPR_ATTR_UNUSED rdpShadowSubsystem* subsystem,
|
||||
WINPR_ATTR_UNUSED rdpShadowClient* client,
|
||||
WINPR_ATTR_UNUSED UINT16 flags,
|
||||
WINPR_ATTR_UNUSED UINT8 code)
|
||||
{
|
||||
WLog_WARN(TAG, "TODO: Implement!");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static BOOL sample_shadow_input_unicode_keyboard_event(
|
||||
WINPR_ATTR_UNUSED rdpShadowSubsystem* subsystem, WINPR_ATTR_UNUSED rdpShadowClient* client,
|
||||
WINPR_ATTR_UNUSED UINT16 flags, WINPR_ATTR_UNUSED UINT16 code)
|
||||
{
|
||||
WLog_WARN(TAG, "TODO: Implement!");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static BOOL sample_shadow_input_mouse_event(WINPR_ATTR_UNUSED rdpShadowSubsystem* subsystem,
|
||||
WINPR_ATTR_UNUSED rdpShadowClient* client,
|
||||
WINPR_ATTR_UNUSED UINT16 flags,
|
||||
WINPR_ATTR_UNUSED UINT16 x, WINPR_ATTR_UNUSED UINT16 y)
|
||||
{
|
||||
WLog_WARN(TAG, "TODO: Implement!");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static BOOL sample_shadow_input_extended_mouse_event(
|
||||
WINPR_ATTR_UNUSED rdpShadowSubsystem* subsystem, WINPR_ATTR_UNUSED rdpShadowClient* client,
|
||||
WINPR_ATTR_UNUSED UINT16 flags, WINPR_ATTR_UNUSED UINT16 x, WINPR_ATTR_UNUSED UINT16 y)
|
||||
{
|
||||
WLog_WARN(TAG, "TODO: Implement!");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static UINT32 sample_shadow_enum_monitors(WINPR_ATTR_UNUSED MONITOR_DEF* monitors,
|
||||
WINPR_ATTR_UNUSED UINT32 maxMonitors)
|
||||
{
|
||||
WLog_WARN(TAG, "TODO: Implement!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static int sample_shadow_subsystem_init(rdpShadowSubsystem* arg)
|
||||
{
|
||||
sampleShadowSubsystem* subsystem = (sampleShadowSubsystem*)arg;
|
||||
WINPR_ASSERT(subsystem);
|
||||
|
||||
subsystem->base.numMonitors = sample_shadow_enum_monitors(subsystem->base.monitors, 16);
|
||||
|
||||
WLog_WARN(TAG, "TODO: Implement!");
|
||||
|
||||
MONITOR_DEF* virtualScreen = &(subsystem->base.virtualScreen);
|
||||
virtualScreen->left = 0;
|
||||
virtualScreen->top = 0;
|
||||
virtualScreen->right = 0;
|
||||
virtualScreen->bottom = 0;
|
||||
virtualScreen->flags = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static int sample_shadow_subsystem_uninit(rdpShadowSubsystem* arg)
|
||||
{
|
||||
sampleShadowSubsystem* subsystem = (sampleShadowSubsystem*)arg;
|
||||
|
||||
if (!subsystem)
|
||||
return -1;
|
||||
|
||||
WLog_WARN(TAG, "TODO: Implement!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static int sample_shadow_subsystem_start(rdpShadowSubsystem* arg)
|
||||
{
|
||||
sampleShadowSubsystem* subsystem = (sampleShadowSubsystem*)arg;
|
||||
|
||||
if (!subsystem)
|
||||
return -1;
|
||||
|
||||
WLog_WARN(TAG, "TODO: Implement!");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static int sample_shadow_subsystem_stop(rdpShadowSubsystem* arg)
|
||||
{
|
||||
sampleShadowSubsystem* subsystem = (sampleShadowSubsystem*)arg;
|
||||
|
||||
if (!subsystem)
|
||||
return -1;
|
||||
|
||||
WLog_WARN(TAG, "TODO: Implement!");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void sample_shadow_subsystem_free(rdpShadowSubsystem* arg)
|
||||
{
|
||||
sampleShadowSubsystem* subsystem = (sampleShadowSubsystem*)arg;
|
||||
|
||||
if (!subsystem)
|
||||
return;
|
||||
|
||||
sample_shadow_subsystem_uninit(arg);
|
||||
free(subsystem);
|
||||
}
|
||||
|
||||
WINPR_ATTR_MALLOC(sample_shadow_subsystem_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
static rdpShadowSubsystem* sample_shadow_subsystem_new(void)
|
||||
{
|
||||
sampleShadowSubsystem* subsystem =
|
||||
(sampleShadowSubsystem*)calloc(1, sizeof(sampleShadowSubsystem));
|
||||
|
||||
if (!subsystem)
|
||||
return nullptr;
|
||||
|
||||
subsystem->base.SynchronizeEvent = sample_shadow_input_synchronize_event;
|
||||
subsystem->base.KeyboardEvent = sample_shadow_input_keyboard_event;
|
||||
subsystem->base.UnicodeKeyboardEvent = sample_shadow_input_unicode_keyboard_event;
|
||||
subsystem->base.MouseEvent = sample_shadow_input_mouse_event;
|
||||
subsystem->base.ExtendedMouseEvent = sample_shadow_input_extended_mouse_event;
|
||||
return &subsystem->base;
|
||||
}
|
||||
|
||||
const char* ShadowSubsystemName(void)
|
||||
{
|
||||
return "Sample";
|
||||
}
|
||||
|
||||
int ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints)
|
||||
{
|
||||
pEntryPoints->New = sample_shadow_subsystem_new;
|
||||
pEntryPoints->Free = sample_shadow_subsystem_free;
|
||||
pEntryPoints->Init = sample_shadow_subsystem_init;
|
||||
pEntryPoints->Uninit = sample_shadow_subsystem_uninit;
|
||||
pEntryPoints->Start = sample_shadow_subsystem_start;
|
||||
pEntryPoints->Stop = sample_shadow_subsystem_stop;
|
||||
pEntryPoints->EnumMonitors = sample_shadow_enum_monitors;
|
||||
return 1;
|
||||
}
|
||||
44
third_party/FreeRDP/server/shadow/Sample/sample_shadow.h
vendored
Normal file
44
third_party/FreeRDP/server/shadow/Sample/sample_shadow.h
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2025 Armin Novak <anovak@thincast.com>
|
||||
* Copyright 2025 Thincast Technologies GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <freerdp/server/shadow.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef struct sample_shadow_subsystem sampleShadowSubsystem;
|
||||
|
||||
struct sample_shadow_subsystem
|
||||
{
|
||||
rdpShadowSubsystem base;
|
||||
|
||||
/* Additional platform specific stuff goes here */
|
||||
};
|
||||
|
||||
FREERDP_API WINPR_ATTR_NODISCARD const char* ShadowSubsystemName(void);
|
||||
FREERDP_API WINPR_ATTR_NODISCARD int
|
||||
ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
16
third_party/FreeRDP/server/shadow/Win/CMakeLists.txt
vendored
Normal file
16
third_party/FreeRDP/server/shadow/Win/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
include(WarnUnmaintained)
|
||||
warn_unmaintained("windows shadow server subsystem" "-DWITH_SHADOW_SUBSYSTEM=OFF")
|
||||
|
||||
add_compile_definitions(WITH_SHADOW_WIN)
|
||||
add_library(
|
||||
freerdp-shadow-subsystem-impl STATIC
|
||||
win_dxgi.c
|
||||
win_dxgi.h
|
||||
win_rdp.c
|
||||
win_rdp.h
|
||||
win_shadow.c
|
||||
win_shadow.h
|
||||
win_wds.c
|
||||
win_wds.h
|
||||
)
|
||||
target_link_libraries(freerdp-shadow-subsystem-impl PRIVATE freerdp-client freerdp winpr)
|
||||
795
third_party/FreeRDP/server/shadow/Win/win_dxgi.c
vendored
Normal file
795
third_party/FreeRDP/server/shadow/Win/win_dxgi.c
vendored
Normal file
@@ -0,0 +1,795 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/library.h>
|
||||
#include <freerdp/log.h>
|
||||
|
||||
#include "win_dxgi.h"
|
||||
|
||||
#define TAG SERVER_TAG("shadow.win")
|
||||
|
||||
#ifdef WITH_DXGI_1_2
|
||||
|
||||
static D3D_DRIVER_TYPE DriverTypes[] = {
|
||||
D3D_DRIVER_TYPE_HARDWARE,
|
||||
D3D_DRIVER_TYPE_WARP,
|
||||
D3D_DRIVER_TYPE_REFERENCE,
|
||||
};
|
||||
|
||||
static UINT NumDriverTypes = ARRAYSIZE(DriverTypes);
|
||||
|
||||
static D3D_FEATURE_LEVEL FeatureLevels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1,
|
||||
D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_1 };
|
||||
|
||||
static UINT NumFeatureLevels = ARRAYSIZE(FeatureLevels);
|
||||
|
||||
static HMODULE d3d11_module = nullptr;
|
||||
|
||||
typedef HRESULT(WINAPI* fnD3D11CreateDevice)(IDXGIAdapter* pAdapter, D3D_DRIVER_TYPE DriverType,
|
||||
HMODULE Software, UINT Flags,
|
||||
CONST D3D_FEATURE_LEVEL* pFeatureLevels,
|
||||
UINT FeatureLevels, UINT SDKVersion,
|
||||
ID3D11Device** ppDevice,
|
||||
D3D_FEATURE_LEVEL* pFeatureLevel,
|
||||
ID3D11DeviceContext** ppImmediateContext);
|
||||
|
||||
static fnD3D11CreateDevice pfnD3D11CreateDevice = nullptr;
|
||||
|
||||
#undef DEFINE_GUID
|
||||
#define INITGUID
|
||||
|
||||
#include <initguid.h>
|
||||
|
||||
/* d3d11.h GUIDs */
|
||||
|
||||
DEFINE_GUID(IID_ID3D11DeviceChild, 0x1841e5c8, 0x16b0, 0x489b, 0xbc, 0xc8, 0x44, 0xcf, 0xb0, 0xd5,
|
||||
0xde, 0xae);
|
||||
DEFINE_GUID(IID_ID3D11DepthStencilState, 0x03823efb, 0x8d8f, 0x4e1c, 0x9a, 0xa2, 0xf6, 0x4b, 0xb2,
|
||||
0xcb, 0xfd, 0xf1);
|
||||
DEFINE_GUID(IID_ID3D11BlendState, 0x75b68faa, 0x347d, 0x4159, 0x8f, 0x45, 0xa0, 0x64, 0x0f, 0x01,
|
||||
0xcd, 0x9a);
|
||||
DEFINE_GUID(IID_ID3D11RasterizerState, 0x9bb4ab81, 0xab1a, 0x4d8f, 0xb5, 0x06, 0xfc, 0x04, 0x20,
|
||||
0x0b, 0x6e, 0xe7);
|
||||
DEFINE_GUID(IID_ID3D11Resource, 0xdc8e63f3, 0xd12b, 0x4952, 0xb4, 0x7b, 0x5e, 0x45, 0x02, 0x6a,
|
||||
0x86, 0x2d);
|
||||
DEFINE_GUID(IID_ID3D11Buffer, 0x48570b85, 0xd1ee, 0x4fcd, 0xa2, 0x50, 0xeb, 0x35, 0x07, 0x22, 0xb0,
|
||||
0x37);
|
||||
DEFINE_GUID(IID_ID3D11Texture1D, 0xf8fb5c27, 0xc6b3, 0x4f75, 0xa4, 0xc8, 0x43, 0x9a, 0xf2, 0xef,
|
||||
0x56, 0x4c);
|
||||
DEFINE_GUID(IID_ID3D11Texture2D, 0x6f15aaf2, 0xd208, 0x4e89, 0x9a, 0xb4, 0x48, 0x95, 0x35, 0xd3,
|
||||
0x4f, 0x9c);
|
||||
DEFINE_GUID(IID_ID3D11Texture3D, 0x037e866e, 0xf56d, 0x4357, 0xa8, 0xaf, 0x9d, 0xab, 0xbe, 0x6e,
|
||||
0x25, 0x0e);
|
||||
DEFINE_GUID(IID_ID3D11View, 0x839d1216, 0xbb2e, 0x412b, 0xb7, 0xf4, 0xa9, 0xdb, 0xeb, 0xe0, 0x8e,
|
||||
0xd1);
|
||||
DEFINE_GUID(IID_ID3D11ShaderResourceView, 0xb0e06fe0, 0x8192, 0x4e1a, 0xb1, 0xca, 0x36, 0xd7, 0x41,
|
||||
0x47, 0x10, 0xb2);
|
||||
DEFINE_GUID(IID_ID3D11RenderTargetView, 0xdfdba067, 0x0b8d, 0x4865, 0x87, 0x5b, 0xd7, 0xb4, 0x51,
|
||||
0x6c, 0xc1, 0x64);
|
||||
DEFINE_GUID(IID_ID3D11DepthStencilView, 0x9fdac92a, 0x1876, 0x48c3, 0xaf, 0xad, 0x25, 0xb9, 0x4f,
|
||||
0x84, 0xa9, 0xb6);
|
||||
DEFINE_GUID(IID_ID3D11UnorderedAccessView, 0x28acf509, 0x7f5c, 0x48f6, 0x86, 0x11, 0xf3, 0x16, 0x01,
|
||||
0x0a, 0x63, 0x80);
|
||||
DEFINE_GUID(IID_ID3D11VertexShader, 0x3b301d64, 0xd678, 0x4289, 0x88, 0x97, 0x22, 0xf8, 0x92, 0x8b,
|
||||
0x72, 0xf3);
|
||||
DEFINE_GUID(IID_ID3D11HullShader, 0x8e5c6061, 0x628a, 0x4c8e, 0x82, 0x64, 0xbb, 0xe4, 0x5c, 0xb3,
|
||||
0xd5, 0xdd);
|
||||
DEFINE_GUID(IID_ID3D11DomainShader, 0xf582c508, 0x0f36, 0x490c, 0x99, 0x77, 0x31, 0xee, 0xce, 0x26,
|
||||
0x8c, 0xfa);
|
||||
DEFINE_GUID(IID_ID3D11GeometryShader, 0x38325b96, 0xeffb, 0x4022, 0xba, 0x02, 0x2e, 0x79, 0x5b,
|
||||
0x70, 0x27, 0x5c);
|
||||
DEFINE_GUID(IID_ID3D11PixelShader, 0xea82e40d, 0x51dc, 0x4f33, 0x93, 0xd4, 0xdb, 0x7c, 0x91, 0x25,
|
||||
0xae, 0x8c);
|
||||
DEFINE_GUID(IID_ID3D11ComputeShader, 0x4f5b196e, 0xc2bd, 0x495e, 0xbd, 0x01, 0x1f, 0xde, 0xd3, 0x8e,
|
||||
0x49, 0x69);
|
||||
DEFINE_GUID(IID_ID3D11InputLayout, 0xe4819ddc, 0x4cf0, 0x4025, 0xbd, 0x26, 0x5d, 0xe8, 0x2a, 0x3e,
|
||||
0x07, 0xb7);
|
||||
DEFINE_GUID(IID_ID3D11SamplerState, 0xda6fea51, 0x564c, 0x4487, 0x98, 0x10, 0xf0, 0xd0, 0xf9, 0xb4,
|
||||
0xe3, 0xa5);
|
||||
DEFINE_GUID(IID_ID3D11Asynchronous, 0x4b35d0cd, 0x1e15, 0x4258, 0x9c, 0x98, 0x1b, 0x13, 0x33, 0xf6,
|
||||
0xdd, 0x3b);
|
||||
DEFINE_GUID(IID_ID3D11Query, 0xd6c00747, 0x87b7, 0x425e, 0xb8, 0x4d, 0x44, 0xd1, 0x08, 0x56, 0x0a,
|
||||
0xfd);
|
||||
DEFINE_GUID(IID_ID3D11Predicate, 0x9eb576dd, 0x9f77, 0x4d86, 0x81, 0xaa, 0x8b, 0xab, 0x5f, 0xe4,
|
||||
0x90, 0xe2);
|
||||
DEFINE_GUID(IID_ID3D11Counter, 0x6e8c49fb, 0xa371, 0x4770, 0xb4, 0x40, 0x29, 0x08, 0x60, 0x22, 0xb7,
|
||||
0x41);
|
||||
DEFINE_GUID(IID_ID3D11ClassInstance, 0xa6cd7faa, 0xb0b7, 0x4a2f, 0x94, 0x36, 0x86, 0x62, 0xa6, 0x57,
|
||||
0x97, 0xcb);
|
||||
DEFINE_GUID(IID_ID3D11ClassLinkage, 0xddf57cba, 0x9543, 0x46e4, 0xa1, 0x2b, 0xf2, 0x07, 0xa0, 0xfe,
|
||||
0x7f, 0xed);
|
||||
DEFINE_GUID(IID_ID3D11CommandList, 0xa24bc4d1, 0x769e, 0x43f7, 0x80, 0x13, 0x98, 0xff, 0x56, 0x6c,
|
||||
0x18, 0xe2);
|
||||
DEFINE_GUID(IID_ID3D11DeviceContext, 0xc0bfa96c, 0xe089, 0x44fb, 0x8e, 0xaf, 0x26, 0xf8, 0x79, 0x61,
|
||||
0x90, 0xda);
|
||||
DEFINE_GUID(IID_ID3D11VideoDecoder, 0x3C9C5B51, 0x995D, 0x48d1, 0x9B, 0x8D, 0xFA, 0x5C, 0xAE, 0xDE,
|
||||
0xD6, 0x5C);
|
||||
DEFINE_GUID(IID_ID3D11VideoProcessorEnumerator, 0x31627037, 0x53AB, 0x4200, 0x90, 0x61, 0x05, 0xFA,
|
||||
0xA9, 0xAB, 0x45, 0xF9);
|
||||
DEFINE_GUID(IID_ID3D11VideoProcessor, 0x1D7B0652, 0x185F, 0x41c6, 0x85, 0xCE, 0x0C, 0x5B, 0xE3,
|
||||
0xD4, 0xAE, 0x6C);
|
||||
DEFINE_GUID(IID_ID3D11AuthenticatedChannel, 0x3015A308, 0xDCBD, 0x47aa, 0xA7, 0x47, 0x19, 0x24,
|
||||
0x86, 0xD1, 0x4D, 0x4A);
|
||||
DEFINE_GUID(IID_ID3D11CryptoSession, 0x9B32F9AD, 0xBDCC, 0x40a6, 0xA3, 0x9D, 0xD5, 0xC8, 0x65, 0x84,
|
||||
0x57, 0x20);
|
||||
DEFINE_GUID(IID_ID3D11VideoDecoderOutputView, 0xC2931AEA, 0x2A85, 0x4f20, 0x86, 0x0F, 0xFB, 0xA1,
|
||||
0xFD, 0x25, 0x6E, 0x18);
|
||||
DEFINE_GUID(IID_ID3D11VideoProcessorInputView, 0x11EC5A5F, 0x51DC, 0x4945, 0xAB, 0x34, 0x6E, 0x8C,
|
||||
0x21, 0x30, 0x0E, 0xA5);
|
||||
DEFINE_GUID(IID_ID3D11VideoProcessorOutputView, 0xA048285E, 0x25A9, 0x4527, 0xBD, 0x93, 0xD6, 0x8B,
|
||||
0x68, 0xC4, 0x42, 0x54);
|
||||
DEFINE_GUID(IID_ID3D11VideoContext, 0x61F21C45, 0x3C0E, 0x4a74, 0x9C, 0xEA, 0x67, 0x10, 0x0D, 0x9A,
|
||||
0xD5, 0xE4);
|
||||
DEFINE_GUID(IID_ID3D11VideoDevice, 0x10EC4D5B, 0x975A, 0x4689, 0xB9, 0xE4, 0xD0, 0xAA, 0xC3, 0x0F,
|
||||
0xE3, 0x33);
|
||||
DEFINE_GUID(IID_ID3D11Device, 0xdb6f6ddb, 0xac77, 0x4e88, 0x82, 0x53, 0x81, 0x9d, 0xf9, 0xbb, 0xf1,
|
||||
0x40);
|
||||
|
||||
/* dxgi.h GUIDs */
|
||||
|
||||
DEFINE_GUID(IID_IDXGIObject, 0xaec22fb8, 0x76f3, 0x4639, 0x9b, 0xe0, 0x28, 0xeb, 0x43, 0xa6, 0x7a,
|
||||
0x2e);
|
||||
DEFINE_GUID(IID_IDXGIDeviceSubObject, 0x3d3e0379, 0xf9de, 0x4d58, 0xbb, 0x6c, 0x18, 0xd6, 0x29,
|
||||
0x92, 0xf1, 0xa6);
|
||||
DEFINE_GUID(IID_IDXGIResource, 0x035f3ab4, 0x482e, 0x4e50, 0xb4, 0x1f, 0x8a, 0x7f, 0x8b, 0xd8, 0x96,
|
||||
0x0b);
|
||||
DEFINE_GUID(IID_IDXGIKeyedMutex, 0x9d8e1289, 0xd7b3, 0x465f, 0x81, 0x26, 0x25, 0x0e, 0x34, 0x9a,
|
||||
0xf8, 0x5d);
|
||||
DEFINE_GUID(IID_IDXGISurface, 0xcafcb56c, 0x6ac3, 0x4889, 0xbf, 0x47, 0x9e, 0x23, 0xbb, 0xd2, 0x60,
|
||||
0xec);
|
||||
DEFINE_GUID(IID_IDXGISurface1, 0x4AE63092, 0x6327, 0x4c1b, 0x80, 0xAE, 0xBF, 0xE1, 0x2E, 0xA3, 0x2B,
|
||||
0x86);
|
||||
DEFINE_GUID(IID_IDXGIAdapter, 0x2411e7e1, 0x12ac, 0x4ccf, 0xbd, 0x14, 0x97, 0x98, 0xe8, 0x53, 0x4d,
|
||||
0xc0);
|
||||
DEFINE_GUID(IID_IDXGIOutput, 0xae02eedb, 0xc735, 0x4690, 0x8d, 0x52, 0x5a, 0x8d, 0xc2, 0x02, 0x13,
|
||||
0xaa);
|
||||
DEFINE_GUID(IID_IDXGISwapChain, 0x310d36a0, 0xd2e7, 0x4c0a, 0xaa, 0x04, 0x6a, 0x9d, 0x23, 0xb8,
|
||||
0x88, 0x6a);
|
||||
DEFINE_GUID(IID_IDXGIFactory, 0x7b7166ec, 0x21c7, 0x44ae, 0xb2, 0x1a, 0xc9, 0xae, 0x32, 0x1a, 0xe3,
|
||||
0x69);
|
||||
DEFINE_GUID(IID_IDXGIDevice, 0x54ec77fa, 0x1377, 0x44e6, 0x8c, 0x32, 0x88, 0xfd, 0x5f, 0x44, 0xc8,
|
||||
0x4c);
|
||||
DEFINE_GUID(IID_IDXGIFactory1, 0x770aae78, 0xf26f, 0x4dba, 0xa8, 0x29, 0x25, 0x3c, 0x83, 0xd1, 0xb3,
|
||||
0x87);
|
||||
DEFINE_GUID(IID_IDXGIAdapter1, 0x29038f61, 0x3839, 0x4626, 0x91, 0xfd, 0x08, 0x68, 0x79, 0x01, 0x1a,
|
||||
0x05);
|
||||
DEFINE_GUID(IID_IDXGIDevice1, 0x77db970f, 0x6276, 0x48ba, 0xba, 0x28, 0x07, 0x01, 0x43, 0xb4, 0x39,
|
||||
0x2c);
|
||||
|
||||
/* dxgi1_2.h GUIDs */
|
||||
|
||||
DEFINE_GUID(IID_IDXGIDisplayControl, 0xea9dbf1a, 0xc88e, 0x4486, 0x85, 0x4a, 0x98, 0xaa, 0x01, 0x38,
|
||||
0xf3, 0x0c);
|
||||
DEFINE_GUID(IID_IDXGIOutputDuplication, 0x191cfac3, 0xa341, 0x470d, 0xb2, 0x6e, 0xa8, 0x64, 0xf4,
|
||||
0x28, 0x31, 0x9c);
|
||||
DEFINE_GUID(IID_IDXGISurface2, 0xaba496dd, 0xb617, 0x4cb8, 0xa8, 0x66, 0xbc, 0x44, 0xd7, 0xeb, 0x1f,
|
||||
0xa2);
|
||||
DEFINE_GUID(IID_IDXGIResource1, 0x30961379, 0x4609, 0x4a41, 0x99, 0x8e, 0x54, 0xfe, 0x56, 0x7e,
|
||||
0xe0, 0xc1);
|
||||
DEFINE_GUID(IID_IDXGIDevice2, 0x05008617, 0xfbfd, 0x4051, 0xa7, 0x90, 0x14, 0x48, 0x84, 0xb4, 0xf6,
|
||||
0xa9);
|
||||
DEFINE_GUID(IID_IDXGISwapChain1, 0x790a45f7, 0x0d42, 0x4876, 0x98, 0x3a, 0x0a, 0x55, 0xcf, 0xe6,
|
||||
0xf4, 0xaa);
|
||||
DEFINE_GUID(IID_IDXGIFactory2, 0x50c83a1c, 0xe072, 0x4c48, 0x87, 0xb0, 0x36, 0x30, 0xfa, 0x36, 0xa6,
|
||||
0xd0);
|
||||
DEFINE_GUID(IID_IDXGIAdapter2, 0x0AA1AE0A, 0xFA0E, 0x4B84, 0x86, 0x44, 0xE0, 0x5F, 0xF8, 0xE5, 0xAC,
|
||||
0xB5);
|
||||
DEFINE_GUID(IID_IDXGIOutput1, 0x00cddea8, 0x939b, 0x4b83, 0xa3, 0x40, 0xa6, 0x85, 0x22, 0x66, 0x66,
|
||||
0xcc);
|
||||
|
||||
const char* GetDxgiErrorString(HRESULT hr)
|
||||
{
|
||||
switch (hr)
|
||||
{
|
||||
case DXGI_STATUS_OCCLUDED:
|
||||
return "DXGI_STATUS_OCCLUDED";
|
||||
case DXGI_STATUS_CLIPPED:
|
||||
return "DXGI_STATUS_CLIPPED";
|
||||
case DXGI_STATUS_NO_REDIRECTION:
|
||||
return "DXGI_STATUS_NO_REDIRECTION";
|
||||
case DXGI_STATUS_NO_DESKTOP_ACCESS:
|
||||
return "DXGI_STATUS_NO_DESKTOP_ACCESS";
|
||||
case DXGI_STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE:
|
||||
return "DXGI_STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE";
|
||||
case DXGI_STATUS_MODE_CHANGED:
|
||||
return "DXGI_STATUS_MODE_CHANGED";
|
||||
case DXGI_STATUS_MODE_CHANGE_IN_PROGRESS:
|
||||
return "DXGI_STATUS_MODE_CHANGE_IN_PROGRESS";
|
||||
case DXGI_ERROR_INVALID_CALL:
|
||||
return "DXGI_ERROR_INVALID_CALL";
|
||||
case DXGI_ERROR_NOT_FOUND:
|
||||
return "DXGI_ERROR_NOT_FOUND";
|
||||
case DXGI_ERROR_MORE_DATA:
|
||||
return "DXGI_ERROR_MORE_DATA";
|
||||
case DXGI_ERROR_UNSUPPORTED:
|
||||
return "DXGI_ERROR_UNSUPPORTED";
|
||||
case DXGI_ERROR_DEVICE_REMOVED:
|
||||
return "DXGI_ERROR_DEVICE_REMOVED";
|
||||
case DXGI_ERROR_DEVICE_HUNG:
|
||||
return "DXGI_ERROR_DEVICE_HUNG";
|
||||
case DXGI_ERROR_DEVICE_RESET:
|
||||
return "DXGI_ERROR_DEVICE_RESET";
|
||||
case DXGI_ERROR_WAS_STILL_DRAWING:
|
||||
return "DXGI_ERROR_WAS_STILL_DRAWING";
|
||||
case DXGI_ERROR_FRAME_STATISTICS_DISJOINT:
|
||||
return "DXGI_ERROR_FRAME_STATISTICS_DISJOINT";
|
||||
case DXGI_ERROR_GRAPHICS_VIDPN_SOURCE_IN_USE:
|
||||
return "DXGI_ERROR_GRAPHICS_VIDPN_SOURCE_IN_USE";
|
||||
case DXGI_ERROR_DRIVER_INTERNAL_ERROR:
|
||||
return "DXGI_ERROR_DRIVER_INTERNAL_ERROR";
|
||||
case DXGI_ERROR_NONEXCLUSIVE:
|
||||
return "DXGI_ERROR_NONEXCLUSIVE";
|
||||
case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE:
|
||||
return "DXGI_ERROR_NOT_CURRENTLY_AVAILABLE";
|
||||
case DXGI_ERROR_REMOTE_CLIENT_DISCONNECTED:
|
||||
return "DXGI_ERROR_REMOTE_CLIENT_DISCONNECTED";
|
||||
case DXGI_ERROR_REMOTE_OUTOFMEMORY:
|
||||
return "DXGI_ERROR_REMOTE_OUTOFMEMORY";
|
||||
case DXGI_ERROR_ACCESS_LOST:
|
||||
return "DXGI_ERROR_ACCESS_LOST";
|
||||
case DXGI_ERROR_WAIT_TIMEOUT:
|
||||
return "DXGI_ERROR_WAIT_TIMEOUT";
|
||||
case DXGI_ERROR_SESSION_DISCONNECTED:
|
||||
return "DXGI_ERROR_SESSION_DISCONNECTED";
|
||||
case DXGI_ERROR_RESTRICT_TO_OUTPUT_STALE:
|
||||
return "DXGI_ERROR_RESTRICT_TO_OUTPUT_STALE";
|
||||
case DXGI_ERROR_CANNOT_PROTECT_CONTENT:
|
||||
return "DXGI_ERROR_CANNOT_PROTECT_CONTENT";
|
||||
case DXGI_ERROR_ACCESS_DENIED:
|
||||
return "DXGI_ERROR_ACCESS_DENIED";
|
||||
case DXGI_ERROR_NAME_ALREADY_EXISTS:
|
||||
return "DXGI_ERROR_NAME_ALREADY_EXISTS";
|
||||
case DXGI_ERROR_SDK_COMPONENT_MISSING:
|
||||
return "DXGI_ERROR_SDK_COMPONENT_MISSING";
|
||||
case DXGI_STATUS_UNOCCLUDED:
|
||||
return "DXGI_STATUS_UNOCCLUDED";
|
||||
case DXGI_STATUS_DDA_WAS_STILL_DRAWING:
|
||||
return "DXGI_STATUS_DDA_WAS_STILL_DRAWING";
|
||||
case DXGI_ERROR_MODE_CHANGE_IN_PROGRESS:
|
||||
return "DXGI_ERROR_MODE_CHANGE_IN_PROGRESS";
|
||||
case DXGI_DDI_ERR_WASSTILLDRAWING:
|
||||
return "DXGI_DDI_ERR_WASSTILLDRAWING";
|
||||
case DXGI_DDI_ERR_UNSUPPORTED:
|
||||
return "DXGI_DDI_ERR_UNSUPPORTED";
|
||||
case DXGI_DDI_ERR_NONEXCLUSIVE:
|
||||
return "DXGI_DDI_ERR_NONEXCLUSIVE";
|
||||
case 0x80070005:
|
||||
return "DXGI_ERROR_ACCESS_DENIED";
|
||||
}
|
||||
|
||||
return "DXGI_ERROR_UNKNOWN";
|
||||
}
|
||||
|
||||
static void win_shadow_d3d11_module_init()
|
||||
{
|
||||
if (d3d11_module)
|
||||
return;
|
||||
|
||||
d3d11_module = LoadLibraryA("d3d11.dll");
|
||||
|
||||
if (!d3d11_module)
|
||||
return;
|
||||
|
||||
pfnD3D11CreateDevice = GetProcAddressAs(d3d11_module, "D3D11CreateDevice", fnD3D11CreateDevice);
|
||||
}
|
||||
|
||||
int win_shadow_dxgi_init_duplication(winShadowSubsystem* subsystem)
|
||||
{
|
||||
HRESULT hr;
|
||||
UINT dTop, i = 0;
|
||||
IDXGIOutput* pOutput;
|
||||
DXGI_OUTPUT_DESC outputDesc = WINPR_C_ARRAY_INIT;
|
||||
DXGI_OUTPUT_DESC* pOutputDesc;
|
||||
D3D11_TEXTURE2D_DESC textureDesc;
|
||||
IDXGIDevice* dxgiDevice = nullptr;
|
||||
IDXGIAdapter* dxgiAdapter = nullptr;
|
||||
IDXGIOutput* dxgiOutput = nullptr;
|
||||
IDXGIOutput1* dxgiOutput1 = nullptr;
|
||||
|
||||
hr = subsystem->dxgiDevice->lpVtbl->QueryInterface(subsystem->dxgiDevice, &IID_IDXGIDevice,
|
||||
(void**)&dxgiDevice);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "ID3D11Device::QueryInterface(IDXGIDevice) failure: %s (0x%08lX)",
|
||||
GetDxgiErrorString(hr), hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hr = dxgiDevice->lpVtbl->GetParent(dxgiDevice, &IID_IDXGIAdapter, (void**)&dxgiAdapter);
|
||||
|
||||
if (dxgiDevice)
|
||||
{
|
||||
dxgiDevice->lpVtbl->Release(dxgiDevice);
|
||||
dxgiDevice = nullptr;
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "IDXGIDevice::GetParent(IDXGIAdapter) failure: %s (0x%08lX)",
|
||||
GetDxgiErrorString(hr), hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pOutput = nullptr;
|
||||
|
||||
while (dxgiAdapter->lpVtbl->EnumOutputs(dxgiAdapter, i, &pOutput) != DXGI_ERROR_NOT_FOUND)
|
||||
{
|
||||
pOutputDesc = &outputDesc;
|
||||
|
||||
hr = pOutput->lpVtbl->GetDesc(pOutput, pOutputDesc);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "IDXGIOutput::GetDesc failure: %s (0x%08lX)", GetDxgiErrorString(hr), hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pOutputDesc->AttachedToDesktop)
|
||||
dTop = i;
|
||||
|
||||
pOutput->lpVtbl->Release(pOutput);
|
||||
i++;
|
||||
}
|
||||
|
||||
dTop = 0; /* screen id */
|
||||
|
||||
hr = dxgiAdapter->lpVtbl->EnumOutputs(dxgiAdapter, dTop, &dxgiOutput);
|
||||
|
||||
if (dxgiAdapter)
|
||||
{
|
||||
dxgiAdapter->lpVtbl->Release(dxgiAdapter);
|
||||
dxgiAdapter = nullptr;
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "IDXGIAdapter::EnumOutputs failure: %s (0x%08lX)", GetDxgiErrorString(hr),
|
||||
hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hr = dxgiOutput->lpVtbl->QueryInterface(dxgiOutput, &IID_IDXGIOutput1, (void**)&dxgiOutput1);
|
||||
|
||||
if (dxgiOutput)
|
||||
{
|
||||
dxgiOutput->lpVtbl->Release(dxgiOutput);
|
||||
dxgiOutput = nullptr;
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "IDXGIOutput::QueryInterface(IDXGIOutput1) failure: %s (0x%08lX)",
|
||||
GetDxgiErrorString(hr), hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hr = dxgiOutput1->lpVtbl->DuplicateOutput(dxgiOutput1, (IUnknown*)subsystem->dxgiDevice,
|
||||
&(subsystem->dxgiOutputDuplication));
|
||||
|
||||
if (dxgiOutput1)
|
||||
{
|
||||
dxgiOutput1->lpVtbl->Release(dxgiOutput1);
|
||||
dxgiOutput1 = nullptr;
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "IDXGIOutput1::DuplicateOutput failure: %s (0x%08lX)", GetDxgiErrorString(hr),
|
||||
hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
textureDesc.Width = subsystem->width;
|
||||
textureDesc.Height = subsystem->height;
|
||||
textureDesc.MipLevels = 1;
|
||||
textureDesc.ArraySize = 1;
|
||||
textureDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
textureDesc.SampleDesc.Count = 1;
|
||||
textureDesc.SampleDesc.Quality = 0;
|
||||
textureDesc.Usage = D3D11_USAGE_STAGING;
|
||||
textureDesc.BindFlags = 0;
|
||||
textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
textureDesc.MiscFlags = 0;
|
||||
|
||||
hr = subsystem->dxgiDevice->lpVtbl->CreateTexture2D(subsystem->dxgiDevice, &textureDesc,
|
||||
nullptr, &(subsystem->dxgiStage));
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "ID3D11Device::CreateTexture2D failure: %s (0x%08lX)", GetDxgiErrorString(hr),
|
||||
hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int win_shadow_dxgi_init(winShadowSubsystem* subsystem)
|
||||
{
|
||||
UINT i = 0;
|
||||
HRESULT hr;
|
||||
int status;
|
||||
UINT DriverTypeIndex;
|
||||
IDXGIDevice* DxgiDevice = nullptr;
|
||||
IDXGIAdapter* DxgiAdapter = nullptr;
|
||||
IDXGIOutput* DxgiOutput = nullptr;
|
||||
IDXGIOutput1* DxgiOutput1 = nullptr;
|
||||
|
||||
win_shadow_d3d11_module_init();
|
||||
|
||||
if (!pfnD3D11CreateDevice)
|
||||
return -1;
|
||||
|
||||
for (DriverTypeIndex = 0; DriverTypeIndex < NumDriverTypes; ++DriverTypeIndex)
|
||||
{
|
||||
hr = pfnD3D11CreateDevice(nullptr, DriverTypes[DriverTypeIndex], nullptr, 0, FeatureLevels,
|
||||
NumFeatureLevels, D3D11_SDK_VERSION, &(subsystem->dxgiDevice),
|
||||
&(subsystem->featureLevel), &(subsystem->dxgiDeviceContext));
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
break;
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "D3D11CreateDevice failure: 0x%08lX", hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = win_shadow_dxgi_init_duplication(subsystem);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int win_shadow_dxgi_uninit(winShadowSubsystem* subsystem)
|
||||
{
|
||||
if (subsystem->dxgiStage)
|
||||
{
|
||||
subsystem->dxgiStage->lpVtbl->Release(subsystem->dxgiStage);
|
||||
subsystem->dxgiStage = nullptr;
|
||||
}
|
||||
|
||||
if (subsystem->dxgiDesktopImage)
|
||||
{
|
||||
subsystem->dxgiDesktopImage->lpVtbl->Release(subsystem->dxgiDesktopImage);
|
||||
subsystem->dxgiDesktopImage = nullptr;
|
||||
}
|
||||
|
||||
if (subsystem->dxgiOutputDuplication)
|
||||
{
|
||||
subsystem->dxgiOutputDuplication->lpVtbl->Release(subsystem->dxgiOutputDuplication);
|
||||
subsystem->dxgiOutputDuplication = nullptr;
|
||||
}
|
||||
|
||||
if (subsystem->dxgiDeviceContext)
|
||||
{
|
||||
subsystem->dxgiDeviceContext->lpVtbl->Release(subsystem->dxgiDeviceContext);
|
||||
subsystem->dxgiDeviceContext = nullptr;
|
||||
}
|
||||
|
||||
if (subsystem->dxgiDevice)
|
||||
{
|
||||
subsystem->dxgiDevice->lpVtbl->Release(subsystem->dxgiDevice);
|
||||
subsystem->dxgiDevice = nullptr;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int win_shadow_dxgi_fetch_frame_data(winShadowSubsystem* subsystem, BYTE** ppDstData,
|
||||
int* pnDstStep, int x, int y, int width, int height)
|
||||
{
|
||||
int status;
|
||||
HRESULT hr;
|
||||
D3D11_BOX Box;
|
||||
DXGI_MAPPED_RECT mappedRect;
|
||||
|
||||
if ((width * height) < 1)
|
||||
return 0;
|
||||
|
||||
Box.top = x;
|
||||
Box.left = y;
|
||||
Box.right = x + width;
|
||||
Box.bottom = y + height;
|
||||
Box.front = 0;
|
||||
Box.back = 1;
|
||||
|
||||
subsystem->dxgiDeviceContext->lpVtbl->CopySubresourceRegion(
|
||||
subsystem->dxgiDeviceContext, (ID3D11Resource*)subsystem->dxgiStage, 0, 0, 0, 0,
|
||||
(ID3D11Resource*)subsystem->dxgiDesktopImage, 0, &Box);
|
||||
|
||||
hr = subsystem->dxgiStage->lpVtbl->QueryInterface(subsystem->dxgiStage, &IID_IDXGISurface,
|
||||
(void**)&(subsystem->dxgiSurface));
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "ID3D11Texture2D::QueryInterface(IDXGISurface) failure: %s 0x%08lX",
|
||||
GetDxgiErrorString(hr), hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hr = subsystem->dxgiSurface->lpVtbl->Map(subsystem->dxgiSurface, &mappedRect, DXGI_MAP_READ);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "IDXGISurface::Map failure: %s 0x%08lX", GetDxgiErrorString(hr), hr);
|
||||
|
||||
if (hr == DXGI_ERROR_DEVICE_REMOVED)
|
||||
{
|
||||
win_shadow_dxgi_uninit(subsystem);
|
||||
|
||||
status = win_shadow_dxgi_init(subsystem);
|
||||
|
||||
if (status < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
subsystem->dxgiSurfaceMapped = TRUE;
|
||||
|
||||
*ppDstData = mappedRect.pBits;
|
||||
*pnDstStep = mappedRect.Pitch;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int win_shadow_dxgi_release_frame_data(winShadowSubsystem* subsystem)
|
||||
{
|
||||
if (subsystem->dxgiSurface)
|
||||
{
|
||||
if (subsystem->dxgiSurfaceMapped)
|
||||
{
|
||||
subsystem->dxgiSurface->lpVtbl->Unmap(subsystem->dxgiSurface);
|
||||
subsystem->dxgiSurfaceMapped = FALSE;
|
||||
}
|
||||
|
||||
subsystem->dxgiSurface->lpVtbl->Release(subsystem->dxgiSurface);
|
||||
subsystem->dxgiSurface = nullptr;
|
||||
}
|
||||
|
||||
if (subsystem->dxgiOutputDuplication)
|
||||
{
|
||||
if (subsystem->dxgiFrameAcquired)
|
||||
{
|
||||
subsystem->dxgiOutputDuplication->lpVtbl->ReleaseFrame(
|
||||
subsystem->dxgiOutputDuplication);
|
||||
subsystem->dxgiFrameAcquired = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
subsystem->pendingFrames = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int win_shadow_dxgi_get_next_frame(winShadowSubsystem* subsystem)
|
||||
{
|
||||
UINT i = 0;
|
||||
int status;
|
||||
HRESULT hr = 0;
|
||||
UINT timeout = 15;
|
||||
UINT DataBufferSize = 0;
|
||||
BYTE* DataBuffer = nullptr;
|
||||
|
||||
if (subsystem->dxgiFrameAcquired)
|
||||
{
|
||||
win_shadow_dxgi_release_frame_data(subsystem);
|
||||
}
|
||||
|
||||
if (subsystem->dxgiDesktopImage)
|
||||
{
|
||||
subsystem->dxgiDesktopImage->lpVtbl->Release(subsystem->dxgiDesktopImage);
|
||||
subsystem->dxgiDesktopImage = nullptr;
|
||||
}
|
||||
|
||||
hr = subsystem->dxgiOutputDuplication->lpVtbl->AcquireNextFrame(
|
||||
subsystem->dxgiOutputDuplication, timeout, &(subsystem->dxgiFrameInfo),
|
||||
&(subsystem->dxgiResource));
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
subsystem->dxgiFrameAcquired = TRUE;
|
||||
subsystem->pendingFrames = subsystem->dxgiFrameInfo.AccumulatedFrames;
|
||||
}
|
||||
|
||||
if (hr == DXGI_ERROR_WAIT_TIMEOUT)
|
||||
return 0;
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "IDXGIOutputDuplication::AcquireNextFrame failure: %s (0x%08lX)",
|
||||
GetDxgiErrorString(hr), hr);
|
||||
|
||||
if (hr == DXGI_ERROR_ACCESS_LOST)
|
||||
{
|
||||
win_shadow_dxgi_release_frame_data(subsystem);
|
||||
|
||||
if (subsystem->dxgiDesktopImage)
|
||||
{
|
||||
subsystem->dxgiDesktopImage->lpVtbl->Release(subsystem->dxgiDesktopImage);
|
||||
subsystem->dxgiDesktopImage = nullptr;
|
||||
}
|
||||
|
||||
if (subsystem->dxgiOutputDuplication)
|
||||
{
|
||||
subsystem->dxgiOutputDuplication->lpVtbl->Release(subsystem->dxgiOutputDuplication);
|
||||
subsystem->dxgiOutputDuplication = nullptr;
|
||||
}
|
||||
|
||||
status = win_shadow_dxgi_init_duplication(subsystem);
|
||||
|
||||
if (status < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
else if (hr == DXGI_ERROR_INVALID_CALL)
|
||||
{
|
||||
win_shadow_dxgi_uninit(subsystem);
|
||||
|
||||
status = win_shadow_dxgi_init(subsystem);
|
||||
|
||||
if (status < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
hr = subsystem->dxgiResource->lpVtbl->QueryInterface(
|
||||
subsystem->dxgiResource, &IID_ID3D11Texture2D, (void**)&(subsystem->dxgiDesktopImage));
|
||||
|
||||
if (subsystem->dxgiResource)
|
||||
{
|
||||
subsystem->dxgiResource->lpVtbl->Release(subsystem->dxgiResource);
|
||||
subsystem->dxgiResource = nullptr;
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "IDXGIResource::QueryInterface(ID3D11Texture2D) failure: %s (0x%08lX)",
|
||||
GetDxgiErrorString(hr), hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int win_shadow_dxgi_get_invalid_region(winShadowSubsystem* subsystem)
|
||||
{
|
||||
HRESULT hr;
|
||||
POINT* pSrcPt;
|
||||
RECT* pDstRect;
|
||||
RECT* pDirtyRect;
|
||||
UINT numMoveRects;
|
||||
UINT numDirtyRects;
|
||||
UINT UsedBufferSize;
|
||||
RECTANGLE_16 invalidRect;
|
||||
UINT MetadataBufferSize;
|
||||
UINT MoveRectsBufferSize;
|
||||
UINT DirtyRectsBufferSize;
|
||||
RECT* pDirtyRectsBuffer;
|
||||
DXGI_OUTDUPL_MOVE_RECT* pMoveRect;
|
||||
DXGI_OUTDUPL_MOVE_RECT* pMoveRectBuffer;
|
||||
rdpShadowSurface* surface = subsystem->server->surface;
|
||||
|
||||
if (subsystem->dxgiFrameInfo.AccumulatedFrames == 0)
|
||||
return 0;
|
||||
|
||||
if (subsystem->dxgiFrameInfo.TotalMetadataBufferSize == 0)
|
||||
return 0;
|
||||
|
||||
MetadataBufferSize = subsystem->dxgiFrameInfo.TotalMetadataBufferSize;
|
||||
|
||||
if (MetadataBufferSize > subsystem->MetadataBufferSize)
|
||||
{
|
||||
subsystem->MetadataBuffer = (BYTE*)realloc(subsystem->MetadataBuffer, MetadataBufferSize);
|
||||
|
||||
if (!subsystem->MetadataBuffer)
|
||||
return -1;
|
||||
|
||||
subsystem->MetadataBufferSize = MetadataBufferSize;
|
||||
}
|
||||
|
||||
/* GetFrameMoveRects */
|
||||
|
||||
UsedBufferSize = 0;
|
||||
|
||||
MoveRectsBufferSize = MetadataBufferSize - UsedBufferSize;
|
||||
pMoveRectBuffer = (DXGI_OUTDUPL_MOVE_RECT*)&(subsystem->MetadataBuffer[UsedBufferSize]);
|
||||
|
||||
hr = subsystem->dxgiOutputDuplication->lpVtbl->GetFrameMoveRects(
|
||||
subsystem->dxgiOutputDuplication, MoveRectsBufferSize, pMoveRectBuffer,
|
||||
&MoveRectsBufferSize);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG,
|
||||
"IDXGIOutputDuplication::GetFrameMoveRects failure: %s (0x%08lX) Size: %u Total "
|
||||
"%u Used: %u",
|
||||
GetDxgiErrorString(hr), hr, MoveRectsBufferSize, MetadataBufferSize,
|
||||
UsedBufferSize);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* GetFrameDirtyRects */
|
||||
|
||||
UsedBufferSize += MoveRectsBufferSize;
|
||||
|
||||
DirtyRectsBufferSize = MetadataBufferSize - UsedBufferSize;
|
||||
pDirtyRectsBuffer = (RECT*)&(subsystem->MetadataBuffer[UsedBufferSize]);
|
||||
|
||||
hr = subsystem->dxgiOutputDuplication->lpVtbl->GetFrameDirtyRects(
|
||||
subsystem->dxgiOutputDuplication, DirtyRectsBufferSize, pDirtyRectsBuffer,
|
||||
&DirtyRectsBufferSize);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG,
|
||||
"IDXGIOutputDuplication::GetFrameDirtyRects failure: %s (0x%08lX) Size: %u Total "
|
||||
"%u Used: %u",
|
||||
GetDxgiErrorString(hr), hr, DirtyRectsBufferSize, MetadataBufferSize,
|
||||
UsedBufferSize);
|
||||
return -1;
|
||||
}
|
||||
|
||||
numMoveRects = MoveRectsBufferSize / sizeof(DXGI_OUTDUPL_MOVE_RECT);
|
||||
|
||||
for (UINT i = 0; i < numMoveRects; i++)
|
||||
{
|
||||
pMoveRect = &pMoveRectBuffer[i];
|
||||
pSrcPt = &(pMoveRect->SourcePoint);
|
||||
pDstRect = &(pMoveRect->DestinationRect);
|
||||
|
||||
invalidRect.left = (UINT16)pDstRect->left;
|
||||
invalidRect.top = (UINT16)pDstRect->top;
|
||||
invalidRect.right = (UINT16)pDstRect->right;
|
||||
invalidRect.bottom = (UINT16)pDstRect->bottom;
|
||||
|
||||
region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect);
|
||||
}
|
||||
|
||||
numDirtyRects = DirtyRectsBufferSize / sizeof(RECT);
|
||||
|
||||
for (UINT i = 0; i < numDirtyRects; i++)
|
||||
{
|
||||
pDirtyRect = &pDirtyRectsBuffer[i];
|
||||
|
||||
invalidRect.left = (UINT16)pDirtyRect->left;
|
||||
invalidRect.top = (UINT16)pDirtyRect->top;
|
||||
invalidRect.right = (UINT16)pDirtyRect->right;
|
||||
invalidRect.bottom = (UINT16)pDirtyRect->bottom;
|
||||
|
||||
region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
62
third_party/FreeRDP/server/shadow/Win/win_dxgi.h
vendored
Normal file
62
third_party/FreeRDP/server/shadow/Win/win_dxgi.h
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_SHADOW_WIN_DXGI_H
|
||||
#define FREERDP_SERVER_SHADOW_WIN_DXGI_H
|
||||
|
||||
#if _WIN32_WINNT >= 0x0602
|
||||
//#define WITH_DXGI_1_2 1
|
||||
#endif
|
||||
|
||||
#ifdef WITH_DXGI_1_2
|
||||
|
||||
#ifndef CINTERFACE
|
||||
#define CINTERFACE
|
||||
#endif
|
||||
|
||||
#include <D3D11.h>
|
||||
#include <dxgi1_2.h>
|
||||
|
||||
#endif
|
||||
|
||||
#include "win_shadow.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#ifdef WITH_DXGI_1_2
|
||||
|
||||
WINPR_ATTR_NODISCARD int win_shadow_dxgi_init(winShadowSubsystem* subsystem);
|
||||
WINPR_ATTR_NODISCARD int win_shadow_dxgi_uninit(winShadowSubsystem* subsystem);
|
||||
|
||||
WINPR_ATTR_NODISCARD int win_shadow_dxgi_fetch_frame_data(winShadowSubsystem* subsystem,
|
||||
BYTE** ppDstData, int* pnDstStep,
|
||||
int x, int y, int width, int height);
|
||||
|
||||
WINPR_ATTR_NODISCARD int win_shadow_dxgi_get_next_frame(winShadowSubsystem* subsystem);
|
||||
WINPR_ATTR_NODISCARD int win_shadow_dxgi_get_invalid_region(winShadowSubsystem* subsystem);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_SERVER_SHADOW_WIN_DXGI_H */
|
||||
440
third_party/FreeRDP/server/shadow/Win/win_rdp.c
vendored
Normal file
440
third_party/FreeRDP/server/shadow/Win/win_rdp.c
vendored
Normal file
@@ -0,0 +1,440 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
|
||||
#include "win_rdp.h"
|
||||
|
||||
#define TAG SERVER_TAG("shadow.win")
|
||||
|
||||
static void shw_OnChannelConnectedEventHandler(void* context, const ChannelConnectedEventArgs* e)
|
||||
{
|
||||
shwContext* shw = (shwContext*)context;
|
||||
WINPR_ASSERT(e);
|
||||
WLog_INFO(TAG, "OnChannelConnected: %s", e->name);
|
||||
}
|
||||
|
||||
static void shw_OnChannelDisconnectedEventHandler(void* context,
|
||||
const ChannelDisconnectedEventArgs* e)
|
||||
{
|
||||
shwContext* shw = (shwContext*)context;
|
||||
WINPR_ASSERT(e);
|
||||
WLog_INFO(TAG, "OnChannelDisconnected: %s", e->name);
|
||||
}
|
||||
|
||||
static BOOL shw_begin_paint(rdpContext* context)
|
||||
{
|
||||
shwContext* shw;
|
||||
rdpGdi* gdi;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
gdi = context->gdi;
|
||||
WINPR_ASSERT(gdi);
|
||||
shw = (shwContext*)context;
|
||||
gdi->primary->hdc->hwnd->invalid->null = TRUE;
|
||||
gdi->primary->hdc->hwnd->ninvalid = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL shw_end_paint(rdpContext* context)
|
||||
{
|
||||
int ninvalid;
|
||||
HGDI_RGN cinvalid;
|
||||
RECTANGLE_16 invalidRect;
|
||||
rdpGdi* gdi = context->gdi;
|
||||
shwContext* shw = (shwContext*)context;
|
||||
winShadowSubsystem* subsystem = shw->subsystem;
|
||||
rdpShadowSurface* surface = subsystem->base.server->surface;
|
||||
ninvalid = gdi->primary->hdc->hwnd->ninvalid;
|
||||
cinvalid = gdi->primary->hdc->hwnd->cinvalid;
|
||||
|
||||
for (int index = 0; index < ninvalid; index++)
|
||||
{
|
||||
invalidRect.left = cinvalid[index].x;
|
||||
invalidRect.top = cinvalid[index].y;
|
||||
invalidRect.right = cinvalid[index].x + cinvalid[index].w;
|
||||
invalidRect.bottom = cinvalid[index].y + cinvalid[index].h;
|
||||
region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect);
|
||||
}
|
||||
|
||||
(void)SetEvent(subsystem->RdpUpdateEnterEvent);
|
||||
(void)WaitForSingleObject(subsystem->RdpUpdateLeaveEvent, INFINITE);
|
||||
(void)ResetEvent(subsystem->RdpUpdateLeaveEvent);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL shw_desktop_resize(rdpContext* context)
|
||||
{
|
||||
WLog_WARN(TAG, "Desktop resizing not implemented!");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL shw_surface_frame_marker(rdpContext* context,
|
||||
const SURFACE_FRAME_MARKER* surfaceFrameMarker)
|
||||
{
|
||||
shwContext* shw = (shwContext*)context;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL shw_authenticate(freerdp* instance, char** username, char** password, char** domain)
|
||||
{
|
||||
WLog_WARN(TAG, "Authentication not implemented, access granted to everyone!");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int shw_verify_x509_certificate(freerdp* instance, const BYTE* data, size_t length,
|
||||
const char* hostname, UINT16 port, DWORD flags)
|
||||
{
|
||||
WLog_WARN(TAG, "Certificate checks not implemented, access granted to everyone!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void shw_OnConnectionResultEventHandler(void* context, const ConnectionResultEventArgs* e)
|
||||
{
|
||||
shwContext* shw = (shwContext*)context;
|
||||
WINPR_ASSERT(e);
|
||||
WLog_INFO(TAG, "OnConnectionResult: %d", e->result);
|
||||
}
|
||||
|
||||
static BOOL shw_pre_connect(freerdp* instance)
|
||||
{
|
||||
shwContext* shw;
|
||||
rdpContext* context = instance->context;
|
||||
shw = (shwContext*)context;
|
||||
PubSub_SubscribeConnectionResult(context->pubSub, shw_OnConnectionResultEventHandler);
|
||||
PubSub_SubscribeChannelConnected(context->pubSub, shw_OnChannelConnectedEventHandler);
|
||||
PubSub_SubscribeChannelDisconnected(context->pubSub, shw_OnChannelDisconnectedEventHandler);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL shw_post_connect(freerdp* instance)
|
||||
{
|
||||
rdpGdi* gdi;
|
||||
shwContext* shw;
|
||||
rdpUpdate* update;
|
||||
rdpSettings* settings;
|
||||
|
||||
WINPR_ASSERT(instance);
|
||||
|
||||
shw = (shwContext*)instance->context;
|
||||
WINPR_ASSERT(shw);
|
||||
|
||||
update = instance->context->update;
|
||||
WINPR_ASSERT(update);
|
||||
|
||||
settings = instance->context->settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
if (!gdi_init(instance, PIXEL_FORMAT_BGRX32))
|
||||
return FALSE;
|
||||
|
||||
gdi = instance->context->gdi;
|
||||
update->BeginPaint = shw_begin_paint;
|
||||
update->EndPaint = shw_end_paint;
|
||||
update->DesktopResize = shw_desktop_resize;
|
||||
update->SurfaceFrameMarker = shw_surface_frame_marker;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static DWORD WINAPI shw_client_thread(LPVOID arg)
|
||||
{
|
||||
int index;
|
||||
BOOL bSuccess;
|
||||
shwContext* shw;
|
||||
rdpContext* context;
|
||||
rdpChannels* channels;
|
||||
|
||||
freerdp* instance = (freerdp*)arg;
|
||||
WINPR_ASSERT(instance);
|
||||
|
||||
context = (rdpContext*)instance->context;
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
shw = (shwContext*)context;
|
||||
|
||||
bSuccess = freerdp_connect(instance);
|
||||
WLog_INFO(TAG, "freerdp_connect: %d", bSuccess);
|
||||
|
||||
if (!bSuccess)
|
||||
{
|
||||
ExitThread(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
channels = context->channels;
|
||||
WINPR_ASSERT(channels);
|
||||
|
||||
while (1)
|
||||
{
|
||||
DWORD status;
|
||||
HANDLE handles[MAXIMUM_WAIT_OBJECTS] = WINPR_C_ARRAY_INIT;
|
||||
DWORD count = freerdp_get_event_handles(instance->context, handles, ARRAYSIZE(handles));
|
||||
|
||||
if ((count == 0) || (count == MAXIMUM_WAIT_OBJECTS))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get FreeRDP event handles");
|
||||
break;
|
||||
}
|
||||
|
||||
handles[count++] = freerdp_channels_get_event_handle(instance);
|
||||
|
||||
if (MsgWaitForMultipleObjects(count, handles, FALSE, 1000, QS_ALLINPUT) == WAIT_FAILED)
|
||||
{
|
||||
WLog_ERR(TAG, "MsgWaitForMultipleObjects failure: 0x%08lX", GetLastError());
|
||||
break;
|
||||
}
|
||||
|
||||
if (!freerdp_check_fds(instance))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
|
||||
break;
|
||||
}
|
||||
|
||||
if (freerdp_shall_disconnect_context(instance->context))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (!freerdp_channels_check_fds(channels, instance))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to check channels file descriptor");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
freerdp_free(instance);
|
||||
ExitThread(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Client Interface
|
||||
*/
|
||||
|
||||
static BOOL shw_freerdp_client_global_init(void)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void shw_freerdp_client_global_uninit(void)
|
||||
{
|
||||
}
|
||||
|
||||
static int shw_freerdp_client_start(rdpContext* context)
|
||||
{
|
||||
shwContext* shw;
|
||||
freerdp* instance = context->instance;
|
||||
shw = (shwContext*)context;
|
||||
|
||||
if (!(shw->common.thread = CreateThread(nullptr, 0, shw_client_thread, instance, 0, nullptr)))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to create thread");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int shw_freerdp_client_stop(rdpContext* context)
|
||||
{
|
||||
shwContext* shw = (shwContext*)context;
|
||||
(void)SetEvent(shw->StopEvent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static BOOL shw_freerdp_client_new(freerdp* instance, rdpContext* context)
|
||||
{
|
||||
shwContext* shw;
|
||||
rdpSettings* settings;
|
||||
|
||||
WINPR_ASSERT(instance);
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
shw = (shwContext*)instance->context;
|
||||
WINPR_ASSERT(shw);
|
||||
|
||||
if (!(shw->StopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
|
||||
return FALSE;
|
||||
|
||||
instance->LoadChannels = freerdp_client_load_channels;
|
||||
instance->PreConnect = shw_pre_connect;
|
||||
instance->PostConnect = shw_post_connect;
|
||||
instance->Authenticate = shw_authenticate;
|
||||
instance->VerifyX509Certificate = shw_verify_x509_certificate;
|
||||
|
||||
settings = context->settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
shw->settings = settings;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_AsyncChannels, FALSE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_AsyncUpdate, FALSE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_IgnoreCertificate, TRUE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_ExternalCertificateManagement, TRUE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_RdpSecurity, TRUE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_TlsSecurity, TRUE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, FALSE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCacheEnabled, FALSE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCacheV3Enabled, FALSE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_OffscreenSupportLevel, FALSE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_uint32(settings, FreeRDP_GlyphSupportLevel, GLYPH_SUPPORT_NONE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_BrushSupportLevel, FALSE))
|
||||
return FALSE;
|
||||
ZeroMemory(freerdp_settings_get_pointer_writable(settings, FreeRDP_OrderSupport), 32);
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_FrameMarkerCommandEnabled, TRUE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_SurfaceFrameMarkerEnabled, TRUE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_AltSecFrameMarkerSupport, TRUE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, 32))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, TRUE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, TRUE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_FastPathInput, TRUE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_FastPathOutput, TRUE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_LargePointerFlag, TRUE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_CompressionEnabled, FALSE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_AutoReconnectionEnabled, FALSE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_NetworkAutoDetect, FALSE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_SupportHeartbeatPdu, FALSE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_SupportMultitransport, FALSE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_uint32(settings, FreeRDP_ConnectionType, CONNECTION_TYPE_LAN))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, TRUE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, TRUE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, FALSE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, TRUE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, TRUE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, FALSE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_DeviceRedirection, TRUE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectClipboard, TRUE))
|
||||
return FALSE;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_SupportDynamicChannels, TRUE))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void shw_freerdp_client_free(freerdp* instance, rdpContext* context)
|
||||
{
|
||||
shwContext* shw = (shwContext*)instance->context;
|
||||
}
|
||||
|
||||
int shw_RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
|
||||
{
|
||||
pEntryPoints->Version = 1;
|
||||
pEntryPoints->Size = sizeof(RDP_CLIENT_ENTRY_POINTS_V1);
|
||||
pEntryPoints->settings = nullptr;
|
||||
pEntryPoints->ContextSize = sizeof(shwContext);
|
||||
pEntryPoints->GlobalInit = shw_freerdp_client_global_init;
|
||||
pEntryPoints->GlobalUninit = shw_freerdp_client_global_uninit;
|
||||
pEntryPoints->ClientNew = shw_freerdp_client_new;
|
||||
pEntryPoints->ClientFree = shw_freerdp_client_free;
|
||||
pEntryPoints->ClientStart = shw_freerdp_client_start;
|
||||
pEntryPoints->ClientStop = shw_freerdp_client_stop;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int win_shadow_rdp_init(winShadowSubsystem* subsystem)
|
||||
{
|
||||
rdpContext* context;
|
||||
RDP_CLIENT_ENTRY_POINTS clientEntryPoints = WINPR_C_ARRAY_INIT;
|
||||
|
||||
clientEntryPoints.Size = sizeof(RDP_CLIENT_ENTRY_POINTS);
|
||||
clientEntryPoints.Version = RDP_CLIENT_INTERFACE_VERSION;
|
||||
shw_RdpClientEntry(&clientEntryPoints);
|
||||
|
||||
if (!(subsystem->RdpUpdateEnterEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
|
||||
goto fail_enter_event;
|
||||
|
||||
if (!(subsystem->RdpUpdateLeaveEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
|
||||
goto fail_leave_event;
|
||||
|
||||
if (!(context = freerdp_client_context_new(&clientEntryPoints)))
|
||||
goto fail_context;
|
||||
|
||||
subsystem->shw = (shwContext*)context;
|
||||
subsystem->shw->settings = context->settings;
|
||||
subsystem->shw->subsystem = subsystem;
|
||||
return 1;
|
||||
fail_context:
|
||||
(void)CloseHandle(subsystem->RdpUpdateLeaveEvent);
|
||||
fail_leave_event:
|
||||
(void)CloseHandle(subsystem->RdpUpdateEnterEvent);
|
||||
fail_enter_event:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int win_shadow_rdp_start(winShadowSubsystem* subsystem)
|
||||
{
|
||||
int status;
|
||||
shwContext* shw = subsystem->shw;
|
||||
rdpContext* context = (rdpContext*)shw;
|
||||
status = freerdp_client_start(context);
|
||||
return status;
|
||||
}
|
||||
|
||||
int win_shadow_rdp_stop(winShadowSubsystem* subsystem)
|
||||
{
|
||||
int status;
|
||||
shwContext* shw = subsystem->shw;
|
||||
rdpContext* context = (rdpContext*)shw;
|
||||
status = freerdp_client_stop(context);
|
||||
return status;
|
||||
}
|
||||
|
||||
int win_shadow_rdp_uninit(winShadowSubsystem* subsystem)
|
||||
{
|
||||
win_shadow_rdp_stop(subsystem);
|
||||
return 1;
|
||||
}
|
||||
56
third_party/FreeRDP/server/shadow/Win/win_rdp.h
vendored
Normal file
56
third_party/FreeRDP/server/shadow/Win/win_rdp.h
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_SHADOW_WIN_RDP_H
|
||||
#define FREERDP_SERVER_SHADOW_WIN_RDP_H
|
||||
|
||||
#include <freerdp/addin.h>
|
||||
#include <freerdp/gdi/gdi.h>
|
||||
#include <freerdp/client/cmdline.h>
|
||||
#include <freerdp/channels/channels.h>
|
||||
|
||||
typedef struct shw_context shwContext;
|
||||
|
||||
#include "win_shadow.h"
|
||||
|
||||
struct shw_context
|
||||
{
|
||||
rdpClientContext common;
|
||||
|
||||
HANDLE StopEvent;
|
||||
freerdp* instance;
|
||||
rdpSettings* settings;
|
||||
winShadowSubsystem* subsystem;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
WINPR_ATTR_NODISCARD int win_shadow_rdp_init(winShadowSubsystem* subsystem);
|
||||
WINPR_ATTR_NODISCARD int win_shadow_rdp_uninit(winShadowSubsystem* subsystem);
|
||||
|
||||
WINPR_ATTR_NODISCARD int win_shadow_rdp_start(winShadowSubsystem* subsystem);
|
||||
WINPR_ATTR_NODISCARD int win_shadow_rdp_stop(winShadowSubsystem* subsystem);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_SERVER_SHADOW_WIN_RDP_H */
|
||||
562
third_party/FreeRDP/server/shadow/Win/win_shadow.c
vendored
Normal file
562
third_party/FreeRDP/server/shadow/Win/win_shadow.c
vendored
Normal file
@@ -0,0 +1,562 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/sysinfo.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#include <freerdp/codec/color.h>
|
||||
#include <freerdp/codec/region.h>
|
||||
#include <freerdp/server/server-common.h>
|
||||
|
||||
#include "win_shadow.h"
|
||||
|
||||
#define TAG SERVER_TAG("shadow.win")
|
||||
|
||||
/* https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mouse_event
|
||||
* does not mention this flag is only supported if building for _WIN32_WINNT >= 0x0600
|
||||
*/
|
||||
#ifndef MOUSEEVENTF_HWHEEL
|
||||
#define MOUSEEVENTF_HWHEEL 0x1000
|
||||
#endif
|
||||
|
||||
static BOOL win_shadow_input_synchronize_event(rdpShadowSubsystem* subsystem,
|
||||
rdpShadowClient* client, UINT32 flags)
|
||||
{
|
||||
WLog_WARN(TAG, "TODO: Implement!");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL win_shadow_input_keyboard_event(rdpShadowSubsystem* subsystem, rdpShadowClient* client,
|
||||
UINT16 flags, UINT8 code)
|
||||
{
|
||||
UINT rc;
|
||||
INPUT event;
|
||||
event.type = INPUT_KEYBOARD;
|
||||
event.ki.wVk = 0;
|
||||
event.ki.wScan = code;
|
||||
event.ki.dwFlags = KEYEVENTF_SCANCODE;
|
||||
event.ki.dwExtraInfo = 0;
|
||||
event.ki.time = 0;
|
||||
|
||||
if (flags & KBD_FLAGS_RELEASE)
|
||||
event.ki.dwFlags |= KEYEVENTF_KEYUP;
|
||||
|
||||
if (flags & KBD_FLAGS_EXTENDED)
|
||||
event.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
|
||||
|
||||
rc = SendInput(1, &event, sizeof(INPUT));
|
||||
if (rc == 0)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL win_shadow_input_unicode_keyboard_event(rdpShadowSubsystem* subsystem,
|
||||
rdpShadowClient* client, UINT16 flags,
|
||||
UINT16 code)
|
||||
{
|
||||
UINT rc;
|
||||
INPUT event;
|
||||
event.type = INPUT_KEYBOARD;
|
||||
event.ki.wVk = 0;
|
||||
event.ki.wScan = code;
|
||||
event.ki.dwFlags = KEYEVENTF_UNICODE;
|
||||
event.ki.dwExtraInfo = 0;
|
||||
event.ki.time = 0;
|
||||
|
||||
if (flags & KBD_FLAGS_RELEASE)
|
||||
event.ki.dwFlags |= KEYEVENTF_KEYUP;
|
||||
|
||||
rc = SendInput(1, &event, sizeof(INPUT));
|
||||
if (rc == 0)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL win_shadow_input_mouse_event(rdpShadowSubsystem* subsystem, rdpShadowClient* client,
|
||||
UINT16 flags, UINT16 x, UINT16 y)
|
||||
{
|
||||
UINT rc = 1;
|
||||
INPUT event = WINPR_C_ARRAY_INIT;
|
||||
float width;
|
||||
float height;
|
||||
|
||||
event.type = INPUT_MOUSE;
|
||||
|
||||
if (flags & (PTR_FLAGS_WHEEL | PTR_FLAGS_HWHEEL))
|
||||
{
|
||||
if (flags & PTR_FLAGS_WHEEL)
|
||||
event.mi.dwFlags = MOUSEEVENTF_WHEEL;
|
||||
else
|
||||
event.mi.dwFlags = MOUSEEVENTF_HWHEEL;
|
||||
event.mi.mouseData = flags & WheelRotationMask;
|
||||
|
||||
if (flags & PTR_FLAGS_WHEEL_NEGATIVE)
|
||||
event.mi.mouseData *= -1;
|
||||
|
||||
rc = SendInput(1, &event, sizeof(INPUT));
|
||||
|
||||
/* The build target is a system that did not support MOUSEEVENTF_HWHEEL
|
||||
* but it may run on newer systems supporting it.
|
||||
* Ignore the return value in these cases.
|
||||
*/
|
||||
#if (_WIN32_WINNT < 0x0600)
|
||||
if (flags & PTR_FLAGS_HWHEEL)
|
||||
rc = 1;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
width = (float)GetSystemMetrics(SM_CXSCREEN);
|
||||
height = (float)GetSystemMetrics(SM_CYSCREEN);
|
||||
event.mi.dx = (LONG)((float)x * (65535.0f / width));
|
||||
event.mi.dy = (LONG)((float)y * (65535.0f / height));
|
||||
event.mi.dwFlags = MOUSEEVENTF_ABSOLUTE;
|
||||
|
||||
if (flags & PTR_FLAGS_MOVE)
|
||||
{
|
||||
event.mi.dwFlags |= MOUSEEVENTF_MOVE;
|
||||
rc = SendInput(1, &event, sizeof(INPUT));
|
||||
if (rc == 0)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
event.mi.dwFlags = MOUSEEVENTF_ABSOLUTE;
|
||||
|
||||
if (flags & PTR_FLAGS_BUTTON1)
|
||||
{
|
||||
if (flags & PTR_FLAGS_DOWN)
|
||||
event.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
|
||||
else
|
||||
event.mi.dwFlags |= MOUSEEVENTF_LEFTUP;
|
||||
|
||||
rc = SendInput(1, &event, sizeof(INPUT));
|
||||
}
|
||||
else if (flags & PTR_FLAGS_BUTTON2)
|
||||
{
|
||||
if (flags & PTR_FLAGS_DOWN)
|
||||
event.mi.dwFlags |= MOUSEEVENTF_RIGHTDOWN;
|
||||
else
|
||||
event.mi.dwFlags |= MOUSEEVENTF_RIGHTUP;
|
||||
|
||||
rc = SendInput(1, &event, sizeof(INPUT));
|
||||
}
|
||||
else if (flags & PTR_FLAGS_BUTTON3)
|
||||
{
|
||||
if (flags & PTR_FLAGS_DOWN)
|
||||
event.mi.dwFlags |= MOUSEEVENTF_MIDDLEDOWN;
|
||||
else
|
||||
event.mi.dwFlags |= MOUSEEVENTF_MIDDLEUP;
|
||||
|
||||
rc = SendInput(1, &event, sizeof(INPUT));
|
||||
}
|
||||
}
|
||||
|
||||
if (rc == 0)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL win_shadow_input_extended_mouse_event(rdpShadowSubsystem* subsystem,
|
||||
rdpShadowClient* client, UINT16 flags, UINT16 x,
|
||||
UINT16 y)
|
||||
{
|
||||
UINT rc = 1;
|
||||
INPUT event = WINPR_C_ARRAY_INIT;
|
||||
float width;
|
||||
float height;
|
||||
|
||||
if ((flags & PTR_XFLAGS_BUTTON1) || (flags & PTR_XFLAGS_BUTTON2))
|
||||
{
|
||||
event.type = INPUT_MOUSE;
|
||||
|
||||
if (flags & PTR_FLAGS_MOVE)
|
||||
{
|
||||
width = (float)GetSystemMetrics(SM_CXSCREEN);
|
||||
height = (float)GetSystemMetrics(SM_CYSCREEN);
|
||||
event.mi.dx = (LONG)((float)x * (65535.0f / width));
|
||||
event.mi.dy = (LONG)((float)y * (65535.0f / height));
|
||||
event.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
|
||||
rc = SendInput(1, &event, sizeof(INPUT));
|
||||
if (rc == 0)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
event.mi.dx = event.mi.dy = event.mi.dwFlags = 0;
|
||||
|
||||
if (flags & PTR_XFLAGS_DOWN)
|
||||
event.mi.dwFlags |= MOUSEEVENTF_XDOWN;
|
||||
else
|
||||
event.mi.dwFlags |= MOUSEEVENTF_XUP;
|
||||
|
||||
if (flags & PTR_XFLAGS_BUTTON1)
|
||||
event.mi.mouseData = XBUTTON1;
|
||||
else if (flags & PTR_XFLAGS_BUTTON2)
|
||||
event.mi.mouseData = XBUTTON2;
|
||||
|
||||
rc = SendInput(1, &event, sizeof(INPUT));
|
||||
}
|
||||
|
||||
if (rc == 0)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int win_shadow_invalidate_region(winShadowSubsystem* subsystem, int x, int y, int width,
|
||||
int height)
|
||||
{
|
||||
rdpShadowServer* server;
|
||||
rdpShadowSurface* surface;
|
||||
RECTANGLE_16 invalidRect;
|
||||
server = subsystem->base.server;
|
||||
surface = server->surface;
|
||||
invalidRect.left = x;
|
||||
invalidRect.top = y;
|
||||
invalidRect.right = x + width;
|
||||
invalidRect.bottom = y + height;
|
||||
EnterCriticalSection(&(surface->lock));
|
||||
region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect);
|
||||
LeaveCriticalSection(&(surface->lock));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int win_shadow_surface_copy(winShadowSubsystem* subsystem)
|
||||
{
|
||||
int x, y;
|
||||
int width;
|
||||
int height;
|
||||
int count;
|
||||
int status = 1;
|
||||
int nDstStep = 0;
|
||||
DWORD DstFormat;
|
||||
BYTE* pDstData = nullptr;
|
||||
rdpShadowServer* server;
|
||||
rdpShadowSurface* surface;
|
||||
RECTANGLE_16 surfaceRect;
|
||||
RECTANGLE_16 invalidRect;
|
||||
const RECTANGLE_16* extents;
|
||||
server = subsystem->base.server;
|
||||
surface = server->surface;
|
||||
|
||||
if (ArrayList_Count(server->clients) < 1)
|
||||
return 1;
|
||||
|
||||
surfaceRect.left = surface->x;
|
||||
surfaceRect.top = surface->y;
|
||||
surfaceRect.right = surface->x + surface->width;
|
||||
surfaceRect.bottom = surface->y + surface->height;
|
||||
region16_intersect_rect(&(surface->invalidRegion), &(surface->invalidRegion), &surfaceRect);
|
||||
|
||||
if (region16_is_empty(&(surface->invalidRegion)))
|
||||
return 1;
|
||||
|
||||
extents = region16_extents(&(surface->invalidRegion));
|
||||
CopyMemory(&invalidRect, extents, sizeof(RECTANGLE_16));
|
||||
shadow_capture_align_clip_rect(&invalidRect, &surfaceRect);
|
||||
x = invalidRect.left;
|
||||
y = invalidRect.top;
|
||||
width = invalidRect.right - invalidRect.left;
|
||||
height = invalidRect.bottom - invalidRect.top;
|
||||
|
||||
if (0)
|
||||
{
|
||||
x = 0;
|
||||
y = 0;
|
||||
width = surface->width;
|
||||
height = surface->height;
|
||||
}
|
||||
|
||||
WLog_INFO(TAG, "SurfaceCopy x: %d y: %d width: %d height: %d right: %d bottom: %d", x, y, width,
|
||||
height, x + width, y + height);
|
||||
#if defined(WITH_WDS_API)
|
||||
{
|
||||
rdpGdi* gdi;
|
||||
shwContext* shw;
|
||||
rdpContext* context;
|
||||
|
||||
WINPR_ASSERT(subsystem);
|
||||
shw = subsystem->shw;
|
||||
WINPR_ASSERT(shw);
|
||||
|
||||
context = &shw->common.context;
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
gdi = context->gdi;
|
||||
WINPR_ASSERT(gdi);
|
||||
|
||||
pDstData = gdi->primary_buffer;
|
||||
nDstStep = gdi->width * 4;
|
||||
DstFormat = gdi->dstFormat;
|
||||
}
|
||||
#elif defined(WITH_DXGI_1_2)
|
||||
DstFormat = PIXEL_FORMAT_BGRX32;
|
||||
status = win_shadow_dxgi_fetch_frame_data(subsystem, &pDstData, &nDstStep, x, y, width, height);
|
||||
#endif
|
||||
|
||||
if (status <= 0)
|
||||
return status;
|
||||
|
||||
if (!freerdp_image_copy_no_overlap(surface->data, surface->format, surface->scanline, x, y,
|
||||
width, height, pDstData, DstFormat, nDstStep, x, y, nullptr,
|
||||
FREERDP_FLIP_NONE))
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
||||
ArrayList_Lock(server->clients);
|
||||
count = ArrayList_Count(server->clients);
|
||||
shadow_subsystem_frame_update(&subsystem->base);
|
||||
ArrayList_Unlock(server->clients);
|
||||
region16_clear(&(surface->invalidRegion));
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if defined(WITH_WDS_API)
|
||||
|
||||
static DWORD WINAPI win_shadow_subsystem_thread(LPVOID arg)
|
||||
{
|
||||
winShadowSubsystem* subsystem = (winShadowSubsystem*)arg;
|
||||
DWORD status;
|
||||
DWORD nCount;
|
||||
HANDLE events[32];
|
||||
HANDLE StopEvent;
|
||||
StopEvent = subsystem->base.server->StopEvent;
|
||||
nCount = 0;
|
||||
events[nCount++] = StopEvent;
|
||||
events[nCount++] = subsystem->RdpUpdateEnterEvent;
|
||||
|
||||
while (1)
|
||||
{
|
||||
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
|
||||
|
||||
if (WaitForSingleObject(StopEvent, 0) == WAIT_OBJECT_0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (WaitForSingleObject(subsystem->RdpUpdateEnterEvent, 0) == WAIT_OBJECT_0)
|
||||
{
|
||||
win_shadow_surface_copy(subsystem);
|
||||
(void)ResetEvent(subsystem->RdpUpdateEnterEvent);
|
||||
(void)SetEvent(subsystem->RdpUpdateLeaveEvent);
|
||||
}
|
||||
}
|
||||
|
||||
ExitThread(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(WITH_DXGI_1_2)
|
||||
|
||||
static DWORD WINAPI win_shadow_subsystem_thread(LPVOID arg)
|
||||
{
|
||||
winShadowSubsystem* subsystem = (winShadowSubsystem*)arg;
|
||||
int fps;
|
||||
DWORD status;
|
||||
DWORD nCount;
|
||||
UINT64 cTime;
|
||||
DWORD dwTimeout;
|
||||
DWORD dwInterval;
|
||||
UINT64 frameTime;
|
||||
HANDLE events[32];
|
||||
HANDLE StopEvent;
|
||||
StopEvent = subsystem->server->StopEvent;
|
||||
nCount = 0;
|
||||
events[nCount++] = StopEvent;
|
||||
fps = 16;
|
||||
dwInterval = 1000 / fps;
|
||||
frameTime = GetTickCount64() + dwInterval;
|
||||
|
||||
while (1)
|
||||
{
|
||||
dwTimeout = INFINITE;
|
||||
cTime = GetTickCount64();
|
||||
dwTimeout = (DWORD)((cTime > frameTime) ? 0 : frameTime - cTime);
|
||||
status = WaitForMultipleObjects(nCount, events, FALSE, dwTimeout);
|
||||
|
||||
if (WaitForSingleObject(StopEvent, 0) == WAIT_OBJECT_0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if ((status == WAIT_TIMEOUT) || (GetTickCount64() > frameTime))
|
||||
{
|
||||
int dxgi_status;
|
||||
dxgi_status = win_shadow_dxgi_get_next_frame(subsystem);
|
||||
|
||||
if (dxgi_status > 0)
|
||||
dxgi_status = win_shadow_dxgi_get_invalid_region(subsystem);
|
||||
|
||||
if (dxgi_status > 0)
|
||||
win_shadow_surface_copy(subsystem);
|
||||
|
||||
dwInterval = 1000 / fps;
|
||||
frameTime += dwInterval;
|
||||
}
|
||||
}
|
||||
|
||||
ExitThread(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static UINT32 win_shadow_enum_monitors(MONITOR_DEF* monitors, UINT32 maxMonitors)
|
||||
{
|
||||
HDC hdc;
|
||||
int index;
|
||||
int desktopWidth;
|
||||
int desktopHeight;
|
||||
DWORD iDevNum = 0;
|
||||
int numMonitors = 0;
|
||||
MONITOR_DEF* monitor;
|
||||
DISPLAY_DEVICE displayDevice = WINPR_C_ARRAY_INIT;
|
||||
|
||||
displayDevice.cb = sizeof(DISPLAY_DEVICE);
|
||||
|
||||
if (EnumDisplayDevices(nullptr, iDevNum, &displayDevice, 0))
|
||||
{
|
||||
hdc = CreateDC(displayDevice.DeviceName, nullptr, nullptr, nullptr);
|
||||
desktopWidth = GetDeviceCaps(hdc, HORZRES);
|
||||
desktopHeight = GetDeviceCaps(hdc, VERTRES);
|
||||
index = 0;
|
||||
numMonitors = 1;
|
||||
monitor = &monitors[index];
|
||||
monitor->left = 0;
|
||||
monitor->top = 0;
|
||||
monitor->right = desktopWidth;
|
||||
monitor->bottom = desktopHeight;
|
||||
monitor->flags = 1;
|
||||
DeleteDC(hdc);
|
||||
}
|
||||
|
||||
return numMonitors;
|
||||
}
|
||||
|
||||
static int win_shadow_subsystem_init(rdpShadowSubsystem* arg)
|
||||
{
|
||||
winShadowSubsystem* subsystem = (winShadowSubsystem*)arg;
|
||||
int status;
|
||||
MONITOR_DEF* virtualScreen;
|
||||
subsystem->base.numMonitors = win_shadow_enum_monitors(subsystem->base.monitors, 16);
|
||||
#if defined(WITH_WDS_API)
|
||||
status = win_shadow_wds_init(subsystem);
|
||||
#elif defined(WITH_DXGI_1_2)
|
||||
status = win_shadow_dxgi_init(subsystem);
|
||||
#endif
|
||||
virtualScreen = &(subsystem->base.virtualScreen);
|
||||
virtualScreen->left = 0;
|
||||
virtualScreen->top = 0;
|
||||
virtualScreen->right = subsystem->width;
|
||||
virtualScreen->bottom = subsystem->height;
|
||||
virtualScreen->flags = 1;
|
||||
WLog_INFO(TAG, "width: %d height: %d", subsystem->width, subsystem->height);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int win_shadow_subsystem_uninit(rdpShadowSubsystem* arg)
|
||||
{
|
||||
winShadowSubsystem* subsystem = (winShadowSubsystem*)arg;
|
||||
|
||||
if (!subsystem)
|
||||
return -1;
|
||||
|
||||
#if defined(WITH_WDS_API)
|
||||
win_shadow_wds_uninit(subsystem);
|
||||
#elif defined(WITH_DXGI_1_2)
|
||||
win_shadow_dxgi_uninit(subsystem);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int win_shadow_subsystem_start(rdpShadowSubsystem* arg)
|
||||
{
|
||||
winShadowSubsystem* subsystem = (winShadowSubsystem*)arg;
|
||||
HANDLE thread;
|
||||
|
||||
if (!subsystem)
|
||||
return -1;
|
||||
|
||||
if (!(thread =
|
||||
CreateThread(nullptr, 0, win_shadow_subsystem_thread, (void*)subsystem, 0, nullptr)))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to create thread");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int win_shadow_subsystem_stop(rdpShadowSubsystem* arg)
|
||||
{
|
||||
winShadowSubsystem* subsystem = (winShadowSubsystem*)arg;
|
||||
|
||||
if (!subsystem)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void win_shadow_subsystem_free(rdpShadowSubsystem* arg)
|
||||
{
|
||||
winShadowSubsystem* subsystem = (winShadowSubsystem*)arg;
|
||||
|
||||
if (!subsystem)
|
||||
return;
|
||||
|
||||
win_shadow_subsystem_uninit(arg);
|
||||
free(subsystem);
|
||||
}
|
||||
|
||||
static rdpShadowSubsystem* win_shadow_subsystem_new(void)
|
||||
{
|
||||
winShadowSubsystem* subsystem;
|
||||
subsystem = (winShadowSubsystem*)calloc(1, sizeof(winShadowSubsystem));
|
||||
|
||||
if (!subsystem)
|
||||
return nullptr;
|
||||
|
||||
subsystem->base.SynchronizeEvent = win_shadow_input_synchronize_event;
|
||||
subsystem->base.KeyboardEvent = win_shadow_input_keyboard_event;
|
||||
subsystem->base.UnicodeKeyboardEvent = win_shadow_input_unicode_keyboard_event;
|
||||
subsystem->base.MouseEvent = win_shadow_input_mouse_event;
|
||||
subsystem->base.ExtendedMouseEvent = win_shadow_input_extended_mouse_event;
|
||||
return &subsystem->base;
|
||||
}
|
||||
|
||||
FREERDP_API const char* ShadowSubsystemName(void)
|
||||
{
|
||||
return "Win";
|
||||
}
|
||||
|
||||
FREERDP_API int ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints)
|
||||
{
|
||||
const char name[] = "windows shadow subsystem";
|
||||
const char* arg[] = { name };
|
||||
|
||||
freerdp_server_warn_unmaintained(ARRAYSIZE(arg), arg);
|
||||
pEntryPoints->New = win_shadow_subsystem_new;
|
||||
pEntryPoints->Free = win_shadow_subsystem_free;
|
||||
pEntryPoints->Init = win_shadow_subsystem_init;
|
||||
pEntryPoints->Uninit = win_shadow_subsystem_uninit;
|
||||
pEntryPoints->Start = win_shadow_subsystem_start;
|
||||
pEntryPoints->Stop = win_shadow_subsystem_stop;
|
||||
pEntryPoints->EnumMonitors = win_shadow_enum_monitors;
|
||||
return 1;
|
||||
}
|
||||
89
third_party/FreeRDP/server/shadow/Win/win_shadow.h
vendored
Normal file
89
third_party/FreeRDP/server/shadow/Win/win_shadow.h
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_SHADOW_WIN_H
|
||||
#define FREERDP_SERVER_SHADOW_WIN_H
|
||||
|
||||
#include <freerdp/assistance.h>
|
||||
|
||||
#include <freerdp/server/shadow.h>
|
||||
|
||||
typedef struct win_shadow_subsystem winShadowSubsystem;
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
#include <winpr/stream.h>
|
||||
#include <winpr/collections.h>
|
||||
|
||||
#include "win_rdp.h"
|
||||
#include "win_wds.h"
|
||||
#include "win_dxgi.h"
|
||||
|
||||
struct win_shadow_subsystem
|
||||
{
|
||||
rdpShadowSubsystem base;
|
||||
|
||||
int bpp;
|
||||
int width;
|
||||
int height;
|
||||
|
||||
#ifdef WITH_WDS_API
|
||||
HWND hWnd;
|
||||
shwContext* shw;
|
||||
HANDLE RdpUpdateEnterEvent;
|
||||
HANDLE RdpUpdateLeaveEvent;
|
||||
rdpAssistanceFile* pAssistanceFile;
|
||||
_IRDPSessionEvents* pSessionEvents;
|
||||
IRDPSRAPISharingSession* pSharingSession;
|
||||
IRDPSRAPIInvitation* pInvitation;
|
||||
IRDPSRAPIInvitationManager* pInvitationMgr;
|
||||
IRDPSRAPISessionProperties* pSessionProperties;
|
||||
IRDPSRAPIVirtualChannelManager* pVirtualChannelMgr;
|
||||
IRDPSRAPIApplicationFilter* pApplicationFilter;
|
||||
IRDPSRAPIAttendeeManager* pAttendeeMgr;
|
||||
#endif
|
||||
|
||||
#ifdef WITH_DXGI_1_2
|
||||
UINT pendingFrames;
|
||||
BYTE* MetadataBuffer;
|
||||
UINT MetadataBufferSize;
|
||||
BOOL dxgiSurfaceMapped;
|
||||
BOOL dxgiFrameAcquired;
|
||||
ID3D11Device* dxgiDevice;
|
||||
IDXGISurface* dxgiSurface;
|
||||
ID3D11Texture2D* dxgiStage;
|
||||
IDXGIResource* dxgiResource;
|
||||
D3D_FEATURE_LEVEL featureLevel;
|
||||
ID3D11Texture2D* dxgiDesktopImage;
|
||||
DXGI_OUTDUPL_FRAME_INFO dxgiFrameInfo;
|
||||
ID3D11DeviceContext* dxgiDeviceContext;
|
||||
IDXGIOutputDuplication* dxgiOutputDuplication;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_SERVER_SHADOW_WIN_H */
|
||||
855
third_party/FreeRDP/server/shadow/Win/win_wds.c
vendored
Normal file
855
third_party/FreeRDP/server/shadow/Win/win_wds.c
vendored
Normal file
@@ -0,0 +1,855 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/print.h>
|
||||
#include <freerdp/log.h>
|
||||
|
||||
#include "win_rdp.h"
|
||||
|
||||
#include "win_wds.h"
|
||||
|
||||
/**
|
||||
* Windows Desktop Sharing API:
|
||||
* http://blogs.msdn.com/b/rds/archive/2007/03/08/windows-desktop-sharing-api.aspx
|
||||
*
|
||||
* Windows Desktop Sharing Interfaces:
|
||||
* http://msdn.microsoft.com/en-us/library/aa373871%28v=vs.85%29.aspx
|
||||
*
|
||||
* Offer Remote Assistance Sample C:
|
||||
* http://msdn.microsoft.com/en-us/library/ms811079.aspx#remoteassistanceapi_topic2b
|
||||
*
|
||||
* Remote Assistance in XP: Programmatically establish an RDP session:
|
||||
* http://www.codeproject.com/Articles/29939/Remote-Assistance-in-XP-Programmatically-establish
|
||||
*/
|
||||
|
||||
#undef DEFINE_GUID
|
||||
#define INITGUID
|
||||
|
||||
#include <initguid.h>
|
||||
|
||||
#include <freerdp/assistance.h>
|
||||
|
||||
#define TAG SERVER_TAG("shadow.win")
|
||||
|
||||
DEFINE_GUID(CLSID_RDPSession, 0x9B78F0E6, 0x3E05, 0x4A5B, 0xB2, 0xE8, 0xE7, 0x43, 0xA8, 0x95, 0x6B,
|
||||
0x65);
|
||||
DEFINE_GUID(DIID__IRDPSessionEvents, 0x98a97042, 0x6698, 0x40e9, 0x8e, 0xfd, 0xb3, 0x20, 0x09, 0x90,
|
||||
0x00, 0x4b);
|
||||
DEFINE_GUID(IID_IRDPSRAPISharingSession, 0xeeb20886, 0xe470, 0x4cf6, 0x84, 0x2b, 0x27, 0x39, 0xc0,
|
||||
0xec, 0x5c, 0xfb);
|
||||
DEFINE_GUID(IID_IRDPSRAPIAttendee, 0xec0671b3, 0x1b78, 0x4b80, 0xa4, 0x64, 0x91, 0x32, 0x24, 0x75,
|
||||
0x43, 0xe3);
|
||||
DEFINE_GUID(IID_IRDPSRAPIAttendeeManager, 0xba3a37e8, 0x33da, 0x4749, 0x8d, 0xa0, 0x07, 0xfa, 0x34,
|
||||
0xda, 0x79, 0x44);
|
||||
DEFINE_GUID(IID_IRDPSRAPISessionProperties, 0x339b24f2, 0x9bc0, 0x4f16, 0x9a, 0xac, 0xf1, 0x65,
|
||||
0x43, 0x3d, 0x13, 0xd4);
|
||||
DEFINE_GUID(CLSID_RDPSRAPIApplicationFilter, 0xe35ace89, 0xc7e8, 0x427e, 0xa4, 0xf9, 0xb9, 0xda,
|
||||
0x07, 0x28, 0x26, 0xbd);
|
||||
DEFINE_GUID(CLSID_RDPSRAPIInvitationManager, 0x53d9c9db, 0x75ab, 0x4271, 0x94, 0x8a, 0x4c, 0x4e,
|
||||
0xb3, 0x6a, 0x8f, 0x2b);
|
||||
|
||||
static ULONG Shadow_IRDPSessionEvents_RefCount = 0;
|
||||
|
||||
const char* GetRDPSessionEventString(DISPID id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case DISPID_RDPSRAPI_EVENT_ON_ATTENDEE_CONNECTED:
|
||||
return "OnAttendeeConnected";
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_ATTENDEE_DISCONNECTED:
|
||||
return "OnAttendeeDisconnected";
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_ATTENDEE_UPDATE:
|
||||
return "OnAttendeeUpdate";
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_ERROR:
|
||||
return "OnError";
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_VIEWER_CONNECTED:
|
||||
return "OnConnectionEstablished";
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_VIEWER_DISCONNECTED:
|
||||
return "OnConnectionTerminated";
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_VIEWER_AUTHENTICATED:
|
||||
return "OnConnectionAuthenticated";
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_VIEWER_CONNECTFAILED:
|
||||
return "OnConnectionFailed";
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_CTRLLEVEL_CHANGE_REQUEST:
|
||||
return "OnControlLevelChangeRequest";
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_GRAPHICS_STREAM_PAUSED:
|
||||
return "OnGraphicsStreamPaused";
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_GRAPHICS_STREAM_RESUMED:
|
||||
return "OnGraphicsStreamResumed";
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_JOIN:
|
||||
return "OnChannelJoin";
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_LEAVE:
|
||||
return "OnChannelLeave";
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_DATARECEIVED:
|
||||
return "OnChannelDataReceived";
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_SENDCOMPLETED:
|
||||
return "OnChannelDataSent";
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_APPLICATION_OPEN:
|
||||
return "OnApplicationOpen";
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_APPLICATION_CLOSE:
|
||||
return "OnApplicationClose";
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_APPLICATION_UPDATE:
|
||||
return "OnApplicationUpdate";
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_WINDOW_OPEN:
|
||||
return "OnWindowOpen";
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_WINDOW_CLOSE:
|
||||
return "OnWindowClose";
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_WINDOW_UPDATE:
|
||||
return "OnWindowUpdate";
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_APPFILTER_UPDATE:
|
||||
return "OnAppFilterUpdate";
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_SHARED_RECT_CHANGED:
|
||||
return "OnSharedRectChanged";
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_FOCUSRELEASED:
|
||||
return "OnFocusReleased";
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_SHARED_DESKTOP_SETTINGS_CHANGED:
|
||||
return "OnSharedDesktopSettingsChanged";
|
||||
break;
|
||||
|
||||
case DISPID_RDPAPI_EVENT_ON_BOUNDING_RECT_CHANGED:
|
||||
return "OnViewingSizeChanged";
|
||||
break;
|
||||
}
|
||||
|
||||
return "OnUnknown";
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE
|
||||
Shadow_IRDPSessionEvents_QueryInterface(__RPC__in _IRDPSessionEvents* This,
|
||||
/* [in] */ __RPC__in REFIID riid,
|
||||
/* [annotation][iid_is][out] */
|
||||
_COM_Outptr_ void** ppvObject)
|
||||
{
|
||||
*ppvObject = nullptr;
|
||||
|
||||
if (IsEqualIID(riid, &DIID__IRDPSessionEvents) || IsEqualIID(riid, &IID_IDispatch) ||
|
||||
IsEqualIID(riid, &IID_IUnknown))
|
||||
{
|
||||
*ppvObject = This;
|
||||
}
|
||||
|
||||
if (!(*ppvObject))
|
||||
return E_NOINTERFACE;
|
||||
|
||||
This->lpVtbl->AddRef(This);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static ULONG STDMETHODCALLTYPE Shadow_IRDPSessionEvents_AddRef(__RPC__in _IRDPSessionEvents* This)
|
||||
{
|
||||
Shadow_IRDPSessionEvents_RefCount++;
|
||||
return Shadow_IRDPSessionEvents_RefCount;
|
||||
}
|
||||
|
||||
static ULONG STDMETHODCALLTYPE Shadow_IRDPSessionEvents_Release(__RPC__in _IRDPSessionEvents* This)
|
||||
{
|
||||
if (!Shadow_IRDPSessionEvents_RefCount)
|
||||
return 0;
|
||||
|
||||
Shadow_IRDPSessionEvents_RefCount--;
|
||||
return Shadow_IRDPSessionEvents_RefCount;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE
|
||||
Shadow_IRDPSessionEvents_GetTypeInfoCount(__RPC__in _IRDPSessionEvents* This,
|
||||
/* [out] */ __RPC__out UINT* pctinfo)
|
||||
{
|
||||
WLog_INFO(TAG, "Shadow_IRDPSessionEvents_GetTypeInfoCount");
|
||||
*pctinfo = 1;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE
|
||||
Shadow_IRDPSessionEvents_GetTypeInfo(__RPC__in _IRDPSessionEvents* This,
|
||||
/* [in] */ UINT iTInfo,
|
||||
/* [in] */ LCID lcid,
|
||||
/* [out] */ __RPC__deref_out_opt ITypeInfo** ppTInfo)
|
||||
{
|
||||
WLog_INFO(TAG, "Shadow_IRDPSessionEvents_GetTypeInfo");
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE Shadow_IRDPSessionEvents_GetIDsOfNames(
|
||||
__RPC__in _IRDPSessionEvents* This,
|
||||
/* [in] */ __RPC__in REFIID riid,
|
||||
/* [size_is][in] */ __RPC__in_ecount_full(cNames) LPOLESTR* rgszNames,
|
||||
/* [range][in] */ __RPC__in_range(0, 16384) UINT cNames,
|
||||
/* [in] */ LCID lcid,
|
||||
/* [size_is][out] */ __RPC__out_ecount_full(cNames) DISPID* rgDispId)
|
||||
{
|
||||
WLog_INFO(TAG, "Shadow_IRDPSessionEvents_GetIDsOfNames");
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE Shadow_IRDPSessionEvents_Invoke(_IRDPSessionEvents* This,
|
||||
/* [annotation][in] */
|
||||
_In_ DISPID dispIdMember,
|
||||
/* [annotation][in] */
|
||||
_In_ REFIID riid,
|
||||
/* [annotation][in] */
|
||||
_In_ LCID lcid,
|
||||
/* [annotation][in] */
|
||||
_In_ WORD wFlags,
|
||||
/* [annotation][out][in] */
|
||||
_In_ DISPPARAMS* pDispParams,
|
||||
/* [annotation][out] */
|
||||
_Out_opt_ VARIANT* pVarResult,
|
||||
/* [annotation][out] */
|
||||
_Out_opt_ EXCEPINFO* pExcepInfo,
|
||||
/* [annotation][out] */
|
||||
_Out_opt_ UINT* puArgErr)
|
||||
{
|
||||
HRESULT hr;
|
||||
VARIANT vr;
|
||||
UINT uArgErr;
|
||||
WLog_INFO(TAG, "%s (%ld)", GetRDPSessionEventString(dispIdMember), dispIdMember);
|
||||
|
||||
switch (dispIdMember)
|
||||
{
|
||||
case DISPID_RDPSRAPI_EVENT_ON_ATTENDEE_CONNECTED:
|
||||
{
|
||||
int level;
|
||||
IDispatch* pDispatch;
|
||||
IRDPSRAPIAttendee* pAttendee;
|
||||
vr.vt = VT_DISPATCH;
|
||||
vr.pdispVal = nullptr;
|
||||
hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &vr, &uArgErr);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "%s DispGetParam(0, VT_DISPATCH) failure: 0x%08lX",
|
||||
GetRDPSessionEventString(dispIdMember), hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
pDispatch = vr.pdispVal;
|
||||
hr = pDispatch->lpVtbl->QueryInterface(pDispatch, &IID_IRDPSRAPIAttendee,
|
||||
(void**)&pAttendee);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_INFO(TAG, "%s IDispatch::QueryInterface(IRDPSRAPIAttendee) failure: 0x%08lX",
|
||||
GetRDPSessionEventString(dispIdMember), hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
level = CTRL_LEVEL_VIEW;
|
||||
// level = CTRL_LEVEL_INTERACTIVE;
|
||||
hr = pAttendee->lpVtbl->put_ControlLevel(pAttendee, level);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_INFO(TAG, "%s IRDPSRAPIAttendee::put_ControlLevel() failure: 0x%08lX",
|
||||
GetRDPSessionEventString(dispIdMember), hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
pAttendee->lpVtbl->Release(pAttendee);
|
||||
}
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_ATTENDEE_DISCONNECTED:
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_ATTENDEE_UPDATE:
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_ERROR:
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_VIEWER_CONNECTED:
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_VIEWER_DISCONNECTED:
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_VIEWER_AUTHENTICATED:
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_VIEWER_CONNECTFAILED:
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_CTRLLEVEL_CHANGE_REQUEST:
|
||||
{
|
||||
int level;
|
||||
IDispatch* pDispatch;
|
||||
IRDPSRAPIAttendee* pAttendee;
|
||||
vr.vt = VT_INT;
|
||||
vr.pdispVal = nullptr;
|
||||
hr = DispGetParam(pDispParams, 1, VT_INT, &vr, &uArgErr);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_INFO(TAG, "%s DispGetParam(1, VT_INT) failure: 0x%08lX",
|
||||
GetRDPSessionEventString(dispIdMember), hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
level = vr.intVal;
|
||||
vr.vt = VT_DISPATCH;
|
||||
vr.pdispVal = nullptr;
|
||||
hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &vr, &uArgErr);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "%s DispGetParam(0, VT_DISPATCH) failure: 0x%08lX",
|
||||
GetRDPSessionEventString(dispIdMember), hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
pDispatch = vr.pdispVal;
|
||||
hr = pDispatch->lpVtbl->QueryInterface(pDispatch, &IID_IRDPSRAPIAttendee,
|
||||
(void**)&pAttendee);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_INFO(TAG, "%s IDispatch::QueryInterface(IRDPSRAPIAttendee) failure: 0x%08lX",
|
||||
GetRDPSessionEventString(dispIdMember), hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = pAttendee->lpVtbl->put_ControlLevel(pAttendee, level);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_INFO(TAG, "%s IRDPSRAPIAttendee::put_ControlLevel() failure: 0x%08lX",
|
||||
GetRDPSessionEventString(dispIdMember), hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
pAttendee->lpVtbl->Release(pAttendee);
|
||||
}
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_GRAPHICS_STREAM_PAUSED:
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_GRAPHICS_STREAM_RESUMED:
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_JOIN:
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_LEAVE:
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_DATARECEIVED:
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_SENDCOMPLETED:
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_APPLICATION_OPEN:
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_APPLICATION_CLOSE:
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_APPLICATION_UPDATE:
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_WINDOW_OPEN:
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_WINDOW_CLOSE:
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_WINDOW_UPDATE:
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_APPFILTER_UPDATE:
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_SHARED_RECT_CHANGED:
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_FOCUSRELEASED:
|
||||
break;
|
||||
|
||||
case DISPID_RDPSRAPI_EVENT_ON_SHARED_DESKTOP_SETTINGS_CHANGED:
|
||||
break;
|
||||
|
||||
case DISPID_RDPAPI_EVENT_ON_BOUNDING_RECT_CHANGED:
|
||||
break;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static _IRDPSessionEventsVtbl Shadow_IRDPSessionEventsVtbl = {
|
||||
/* IUnknown */
|
||||
Shadow_IRDPSessionEvents_QueryInterface, Shadow_IRDPSessionEvents_AddRef,
|
||||
Shadow_IRDPSessionEvents_Release,
|
||||
|
||||
/* IDispatch */
|
||||
Shadow_IRDPSessionEvents_GetTypeInfoCount, Shadow_IRDPSessionEvents_GetTypeInfo,
|
||||
Shadow_IRDPSessionEvents_GetIDsOfNames, Shadow_IRDPSessionEvents_Invoke
|
||||
};
|
||||
|
||||
static _IRDPSessionEvents Shadow_IRDPSessionEvents = { &Shadow_IRDPSessionEventsVtbl };
|
||||
|
||||
static LRESULT CALLBACK ShadowWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_CLOSE:
|
||||
DestroyWindow(hwnd);
|
||||
break;
|
||||
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
|
||||
default:
|
||||
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int win_shadow_wds_wnd_init(winShadowSubsystem* subsystem)
|
||||
{
|
||||
HMODULE hModule;
|
||||
HINSTANCE hInstance;
|
||||
WNDCLASSEX wndClassEx = WINPR_C_ARRAY_INIT;
|
||||
hModule = GetModuleHandle(nullptr);
|
||||
|
||||
wndClassEx.cbSize = sizeof(WNDCLASSEX);
|
||||
wndClassEx.style = 0;
|
||||
wndClassEx.lpfnWndProc = ShadowWndProc;
|
||||
wndClassEx.cbClsExtra = 0;
|
||||
wndClassEx.cbWndExtra = 0;
|
||||
wndClassEx.hInstance = hModule;
|
||||
wndClassEx.hIcon = nullptr;
|
||||
wndClassEx.hCursor = nullptr;
|
||||
wndClassEx.hbrBackground = nullptr;
|
||||
wndClassEx.lpszMenuName = _T("ShadowWndMenu");
|
||||
wndClassEx.lpszClassName = _T("ShadowWndClass");
|
||||
wndClassEx.hIconSm = nullptr;
|
||||
|
||||
if (!RegisterClassEx(&wndClassEx))
|
||||
{
|
||||
WLog_ERR(TAG, "RegisterClassEx failure");
|
||||
return -1;
|
||||
}
|
||||
|
||||
hInstance = wndClassEx.hInstance;
|
||||
subsystem->hWnd = CreateWindowEx(0, wndClassEx.lpszClassName, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0,
|
||||
hInstance, nullptr);
|
||||
|
||||
if (!subsystem->hWnd)
|
||||
{
|
||||
WLog_INFO(TAG, "CreateWindowEx failure");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int win_shadow_wds_init(winShadowSubsystem* subsystem)
|
||||
{
|
||||
int status = -1;
|
||||
|
||||
long left = 0;
|
||||
long top = 0;
|
||||
long right = 0;
|
||||
long bottom = 0;
|
||||
BSTR bstrAuthString = nullptr;
|
||||
BSTR bstrGroupName = nullptr;
|
||||
BSTR bstrPassword = nullptr;
|
||||
BSTR bstrPropertyName = nullptr;
|
||||
VARIANT varPropertyValue;
|
||||
rdpAssistanceFile* file = nullptr;
|
||||
IConnectionPoint* pCP = nullptr;
|
||||
IConnectionPointContainer* pCPC = nullptr;
|
||||
|
||||
win_shadow_wds_wnd_init(subsystem);
|
||||
HRESULT hr = OleInitialize(nullptr);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "OleInitialize() failure");
|
||||
return -1;
|
||||
}
|
||||
|
||||
hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "CoInitialize() failure");
|
||||
return -1;
|
||||
}
|
||||
|
||||
hr = CoCreateInstance(&CLSID_RDPSession, nullptr, CLSCTX_ALL, &IID_IRDPSRAPISharingSession,
|
||||
(void**)&(subsystem->pSharingSession));
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "CoCreateInstance(IRDPSRAPISharingSession) failure: 0x%08lX", hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
IUnknown* pUnknown = (IUnknown*)subsystem->pSharingSession;
|
||||
hr = pUnknown->lpVtbl->QueryInterface(pUnknown, &IID_IConnectionPointContainer, (void**)&pCPC);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "QueryInterface(IID_IConnectionPointContainer) failure: 0x%08lX", hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pCPC->lpVtbl->FindConnectionPoint(pCPC, &DIID__IRDPSessionEvents, &pCP);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(
|
||||
TAG,
|
||||
"IConnectionPointContainer::FindConnectionPoint(_IRDPSessionEvents) failure: 0x%08lX",
|
||||
hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DWORD dwCookie = 0;
|
||||
subsystem->pSessionEvents = &Shadow_IRDPSessionEvents;
|
||||
subsystem->pSessionEvents->lpVtbl->AddRef(subsystem->pSessionEvents);
|
||||
hr = pCP->lpVtbl->Advise(pCP, (IUnknown*)subsystem->pSessionEvents, &dwCookie);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "IConnectionPoint::Advise(Shadow_IRDPSessionEvents) failure: 0x%08lX", hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hr = subsystem->pSharingSession->lpVtbl->put_ColorDepth(subsystem->pSharingSession, 32);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "IRDPSRAPISharingSession::put_ColorDepth() failure: 0x%08lX", hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hr = subsystem->pSharingSession->lpVtbl->GetDesktopSharedRect(subsystem->pSharingSession, &left,
|
||||
&top, &right, &bottom);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "IRDPSRAPISharingSession::GetDesktopSharedRect() failure: 0x%08lX", hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
long width = right - left;
|
||||
long height = bottom - top;
|
||||
WLog_INFO(
|
||||
TAG,
|
||||
"GetDesktopSharedRect(): left: %ld top: %ld right: %ld bottom: %ld width: %ld height: %ld",
|
||||
left, top, right, bottom, width, height);
|
||||
hr = subsystem->pSharingSession->lpVtbl->get_VirtualChannelManager(
|
||||
subsystem->pSharingSession, &(subsystem->pVirtualChannelMgr));
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "IRDPSRAPISharingSession::get_VirtualChannelManager() failure: 0x%08lX", hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hr = subsystem->pSharingSession->lpVtbl->get_ApplicationFilter(
|
||||
subsystem->pSharingSession, &(subsystem->pApplicationFilter));
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "IRDPSRAPISharingSession::get_ApplicationFilter() failure: 0x%08lX", hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hr = subsystem->pSharingSession->lpVtbl->get_Attendees(subsystem->pSharingSession,
|
||||
&(subsystem->pAttendeeMgr));
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "IRDPSRAPISharingSession::get_Attendees() failure: 0x%08lX", hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hr = subsystem->pSharingSession->lpVtbl->get_Properties(subsystem->pSharingSession,
|
||||
&(subsystem->pSessionProperties));
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "IRDPSRAPISharingSession::get_Properties() failure: 0x%08lX", hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bstrPropertyName = SysAllocString(L"PortId");
|
||||
varPropertyValue.vt = VT_I4;
|
||||
varPropertyValue.intVal = 40000;
|
||||
hr = subsystem->pSessionProperties->lpVtbl->put_Property(subsystem->pSessionProperties,
|
||||
bstrPropertyName, varPropertyValue);
|
||||
SysFreeString(bstrPropertyName);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "IRDPSRAPISessionProperties::put_Property(PortId) failure: 0x%08lX", hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bstrPropertyName = SysAllocString(L"DrvConAttach");
|
||||
varPropertyValue.vt = VT_BOOL;
|
||||
varPropertyValue.boolVal = VARIANT_TRUE;
|
||||
hr = subsystem->pSessionProperties->lpVtbl->put_Property(subsystem->pSessionProperties,
|
||||
bstrPropertyName, varPropertyValue);
|
||||
SysFreeString(bstrPropertyName);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "IRDPSRAPISessionProperties::put_Property(DrvConAttach) failure: 0x%08lX",
|
||||
hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bstrPropertyName = SysAllocString(L"PortProtocol");
|
||||
varPropertyValue.vt = VT_I4;
|
||||
// varPropertyValue.intVal = 0; // AF_UNSPEC
|
||||
varPropertyValue.intVal = 2; // AF_INET
|
||||
// varPropertyValue.intVal = 23; // AF_INET6
|
||||
hr = subsystem->pSessionProperties->lpVtbl->put_Property(subsystem->pSessionProperties,
|
||||
bstrPropertyName, varPropertyValue);
|
||||
SysFreeString(bstrPropertyName);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "IRDPSRAPISessionProperties::put_Property(PortProtocol) failure: 0x%08lX",
|
||||
hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hr = subsystem->pSharingSession->lpVtbl->Open(subsystem->pSharingSession);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "IRDPSRAPISharingSession::Open() failure: 0x%08lX", hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hr = subsystem->pSharingSession->lpVtbl->get_Invitations(subsystem->pSharingSession,
|
||||
&(subsystem->pInvitationMgr));
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "IRDPSRAPISharingSession::get_Invitations() failure");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bstrAuthString = SysAllocString(L"Shadow");
|
||||
bstrGroupName = SysAllocString(L"ShadowGroup");
|
||||
bstrPassword = SysAllocString(L"Shadow123!");
|
||||
hr = subsystem->pInvitationMgr->lpVtbl->CreateInvitation(
|
||||
subsystem->pInvitationMgr, bstrAuthString, bstrGroupName, bstrPassword, 5,
|
||||
&(subsystem->pInvitation));
|
||||
SysFreeString(bstrAuthString);
|
||||
SysFreeString(bstrGroupName);
|
||||
SysFreeString(bstrPassword);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "IRDPSRAPIInvitationManager::CreateInvitation() failure: 0x%08lX", hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
file = subsystem->pAssistanceFile = freerdp_assistance_file_new();
|
||||
|
||||
if (!file)
|
||||
{
|
||||
WLog_ERR(TAG, "freerdp_assistance_file_new() failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
{
|
||||
int status2 = -1;
|
||||
char* ConnectionString2;
|
||||
BSTR bstrConnectionString;
|
||||
hr = subsystem->pInvitation->lpVtbl->get_ConnectionString(subsystem->pInvitation,
|
||||
&bstrConnectionString);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WLog_ERR(TAG, "IRDPSRAPIInvitation::get_ConnectionString() failure: 0x%08lX", hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ConnectionString2 = ConvertWCharToUtf8Alloc(bstrConnectionString, nullptr);
|
||||
SysFreeString(bstrConnectionString);
|
||||
status2 = freerdp_assistance_set_connection_string2(file, ConnectionString2, "Shadow123!");
|
||||
free(ConnectionString2);
|
||||
|
||||
if ((!ConnectionString2) || (status2 < 1))
|
||||
{
|
||||
WLog_ERR(TAG, "failed to convert connection string");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
freerdp_assistance_print_file(file, WLog_Get(TAG), WLOG_INFO);
|
||||
status = win_shadow_rdp_init(subsystem);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
WLog_ERR(TAG, "win_shadow_rdp_init() failure: %d", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
rdpSettings* settings = subsystem->shw->settings;
|
||||
if (!freerdp_assistance_populate_settings_from_assistance_file(file, settings))
|
||||
return -1;
|
||||
if (!freerdp_settings_set_string(settings, FreeRDP_Domain, "RDP"))
|
||||
return -1;
|
||||
if (!freerdp_settings_set_string(settings, FreeRDP_Username, "Shadow"))
|
||||
return -1;
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_AutoLogonEnabled, TRUE))
|
||||
return -1;
|
||||
if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth, width))
|
||||
return -1;
|
||||
if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight, height))
|
||||
return -1;
|
||||
status = win_shadow_rdp_start(subsystem);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
WLog_ERR(TAG, "win_shadow_rdp_start() failure: %d", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int win_shadow_wds_uninit(winShadowSubsystem* subsystem)
|
||||
{
|
||||
if (subsystem->pSharingSession)
|
||||
{
|
||||
subsystem->pSharingSession->lpVtbl->Close(subsystem->pSharingSession);
|
||||
subsystem->pSharingSession->lpVtbl->Release(subsystem->pSharingSession);
|
||||
subsystem->pSharingSession = nullptr;
|
||||
}
|
||||
|
||||
if (subsystem->pVirtualChannelMgr)
|
||||
{
|
||||
subsystem->pVirtualChannelMgr->lpVtbl->Release(subsystem->pVirtualChannelMgr);
|
||||
subsystem->pVirtualChannelMgr = nullptr;
|
||||
}
|
||||
|
||||
if (subsystem->pApplicationFilter)
|
||||
{
|
||||
subsystem->pApplicationFilter->lpVtbl->Release(subsystem->pApplicationFilter);
|
||||
subsystem->pApplicationFilter = nullptr;
|
||||
}
|
||||
|
||||
if (subsystem->pAttendeeMgr)
|
||||
{
|
||||
subsystem->pAttendeeMgr->lpVtbl->Release(subsystem->pAttendeeMgr);
|
||||
subsystem->pAttendeeMgr = nullptr;
|
||||
}
|
||||
|
||||
if (subsystem->pSessionProperties)
|
||||
{
|
||||
subsystem->pSessionProperties->lpVtbl->Release(subsystem->pSessionProperties);
|
||||
subsystem->pSessionProperties = nullptr;
|
||||
}
|
||||
|
||||
if (subsystem->pInvitationMgr)
|
||||
{
|
||||
subsystem->pInvitationMgr->lpVtbl->Release(subsystem->pInvitationMgr);
|
||||
subsystem->pInvitationMgr = nullptr;
|
||||
}
|
||||
|
||||
if (subsystem->pInvitation)
|
||||
{
|
||||
subsystem->pInvitation->lpVtbl->Release(subsystem->pInvitation);
|
||||
subsystem->pInvitation = nullptr;
|
||||
}
|
||||
|
||||
if (subsystem->pAssistanceFile)
|
||||
{
|
||||
freerdp_assistance_file_free(subsystem->pAssistanceFile);
|
||||
subsystem->pAssistanceFile = nullptr;
|
||||
}
|
||||
|
||||
if (subsystem->hWnd)
|
||||
{
|
||||
DestroyWindow(subsystem->hWnd);
|
||||
subsystem->hWnd = nullptr;
|
||||
}
|
||||
|
||||
if (subsystem->shw)
|
||||
{
|
||||
win_shadow_rdp_uninit(subsystem);
|
||||
subsystem->shw = nullptr;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
48
third_party/FreeRDP/server/shadow/Win/win_wds.h
vendored
Normal file
48
third_party/FreeRDP/server/shadow/Win/win_wds.h
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_SHADOW_WIN_WDS_H
|
||||
#define FREERDP_SERVER_SHADOW_WIN_WDS_H
|
||||
|
||||
#define WITH_WDS_API 1
|
||||
|
||||
#ifndef CINTERFACE
|
||||
#define CINTERFACE
|
||||
#endif
|
||||
|
||||
#include <rdpencomapi.h>
|
||||
|
||||
#ifndef DISPID_RDPAPI_EVENT_ON_BOUNDING_RECT_CHANGED
|
||||
#define DISPID_RDPAPI_EVENT_ON_BOUNDING_RECT_CHANGED 340
|
||||
#endif
|
||||
|
||||
#include "win_shadow.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
WINPR_ATTR_NODISCARD int win_shadow_wds_init(winShadowSubsystem* subsystem);
|
||||
WINPR_ATTR_NODISCARD int win_shadow_wds_uninit(winShadowSubsystem* subsystem);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_SERVER_SHADOW_WIN_WDS_H */
|
||||
67
third_party/FreeRDP/server/shadow/X11/CMakeLists.txt
vendored
Normal file
67
third_party/FreeRDP/server/shadow/X11/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
find_package(X11 REQUIRED)
|
||||
if(X11_FOUND)
|
||||
add_compile_definitions(WITH_X11)
|
||||
include_directories(SYSTEM ${X11_INCLUDE_DIR})
|
||||
list(APPEND LIBS ${X11_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(X11_XShm_FOUND)
|
||||
add_compile_definitions(WITH_XSHM)
|
||||
include_directories(SYSTEM ${X11_XShm_INCLUDE_PATH})
|
||||
list(APPEND LIBS ${X11_XShm_LIB})
|
||||
endif()
|
||||
|
||||
if(X11_Xext_FOUND)
|
||||
add_compile_definitions(WITH_XEXT)
|
||||
list(APPEND LIBS ${X11_Xext_LIB})
|
||||
endif()
|
||||
|
||||
if(X11_Xinerama_FOUND)
|
||||
add_compile_definitions(WITH_XINERAMA)
|
||||
include_directories(SYSTEM ${X11_Xinerama_INCLUDE_PATH})
|
||||
list(APPEND LIBS ${X11_Xinerama_LIB})
|
||||
endif()
|
||||
|
||||
if(X11_Xdamage_FOUND)
|
||||
add_compile_definitions(WITH_XDAMAGE)
|
||||
include_directories(SYSTEM ${X11_Xdamage_INCLUDE_PATH})
|
||||
list(APPEND LIBS ${X11_Xdamage_LIB})
|
||||
endif()
|
||||
|
||||
if(X11_Xfixes_FOUND)
|
||||
add_compile_definitions(WITH_XFIXES)
|
||||
include_directories(SYSTEM ${X11_Xfixes_INCLUDE_PATH})
|
||||
list(APPEND LIBS ${X11_Xfixes_LIB})
|
||||
endif()
|
||||
|
||||
if(X11_XTest_FOUND)
|
||||
add_compile_definitions(WITH_XTEST)
|
||||
include_directories(SYSTEM ${X11_XTest_INCLUDE_PATH})
|
||||
list(APPEND LIBS ${X11_XTest_LIB})
|
||||
endif()
|
||||
|
||||
# XCursor and XRandr are currently not used so don't link them
|
||||
#if(X11_Xcursor_FOUND)
|
||||
# add_compile_definitions(WITH_XCURSOR)
|
||||
# include_directories(SYSTEM ${X11_Xcursor_INCLUDE_PATH})
|
||||
# list(APPEND LIBS ${X11_Xcursor_LIB})
|
||||
#endif()
|
||||
|
||||
#if(X11_Xrandr_FOUND)
|
||||
# add_compile_definitions(WITH_XRANDR)
|
||||
# include_directories(SYSTEM ${X11_Xrandr_INCLUDE_PATH})
|
||||
# list(APPEND LIBS ${X11_Xrandr_LIB})
|
||||
#endif()
|
||||
|
||||
find_package(PAM)
|
||||
if(PAM_FOUND)
|
||||
add_compile_definitions(WITH_PAM)
|
||||
include_directories(SYSTEM ${PAM_INCLUDE_DIR})
|
||||
list(APPEND LIBS ${PAM_LIBRARY})
|
||||
else()
|
||||
message("building without PAM authentication support")
|
||||
endif()
|
||||
|
||||
add_compile_definitions(WITH_SHADOW_X11)
|
||||
add_library(freerdp-shadow-subsystem-impl STATIC x11_shadow.h x11_shadow.c)
|
||||
target_link_libraries(freerdp-shadow-subsystem-impl PRIVATE ${LIBS})
|
||||
1668
third_party/FreeRDP/server/shadow/X11/x11_shadow.c
vendored
Normal file
1668
third_party/FreeRDP/server/shadow/X11/x11_shadow.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
115
third_party/FreeRDP/server/shadow/X11/x11_shadow.h
vendored
Normal file
115
third_party/FreeRDP/server/shadow/X11/x11_shadow.h
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_SHADOW_X11_H
|
||||
#define FREERDP_SERVER_SHADOW_X11_H
|
||||
|
||||
#include <freerdp/server/shadow.h>
|
||||
|
||||
typedef struct x11_shadow_subsystem x11ShadowSubsystem;
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
#include <winpr/stream.h>
|
||||
#include <winpr/collections.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
#ifdef WITH_XSHM
|
||||
#include <X11/extensions/XShm.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_XFIXES
|
||||
#include <X11/extensions/Xfixes.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_XTEST
|
||||
#include <X11/extensions/XTest.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_XDAMAGE
|
||||
#include <X11/extensions/Xdamage.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_XINERAMA
|
||||
#include <X11/extensions/Xinerama.h>
|
||||
#endif
|
||||
|
||||
struct x11_shadow_subsystem
|
||||
{
|
||||
rdpShadowSubsystem common;
|
||||
|
||||
HANDLE thread;
|
||||
|
||||
UINT32 bpp;
|
||||
int xfds;
|
||||
UINT32 depth;
|
||||
UINT32 width;
|
||||
UINT32 height;
|
||||
int number;
|
||||
XImage* image;
|
||||
Screen* screen;
|
||||
Visual* visual;
|
||||
Display* display;
|
||||
UINT32 scanline_pad;
|
||||
BOOL composite;
|
||||
|
||||
BOOL use_xshm;
|
||||
BOOL use_xfixes;
|
||||
BOOL use_xdamage;
|
||||
BOOL use_xinerama;
|
||||
|
||||
XImage* fb_image;
|
||||
Pixmap fb_pixmap;
|
||||
Window root_window;
|
||||
XShmSegmentInfo fb_shm_info;
|
||||
|
||||
UINT32 cursorHotX;
|
||||
UINT32 cursorHotY;
|
||||
UINT32 cursorWidth;
|
||||
UINT32 cursorHeight;
|
||||
UINT64 cursorId;
|
||||
BYTE* cursorPixels;
|
||||
UINT32 cursorMaxWidth;
|
||||
UINT32 cursorMaxHeight;
|
||||
rdpShadowClient* lastMouseClient;
|
||||
|
||||
#ifdef WITH_XDAMAGE
|
||||
GC xshm_gc;
|
||||
Damage xdamage;
|
||||
int xdamage_notify_event;
|
||||
XserverRegion xdamage_region;
|
||||
#endif
|
||||
|
||||
#ifdef WITH_XFIXES
|
||||
int xfixes_cursor_notify_event;
|
||||
#endif
|
||||
UINT32 format;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_SERVER_SHADOW_X11_H */
|
||||
30
third_party/FreeRDP/server/shadow/cli/CMakeLists.txt
vendored
Normal file
30
third_party/FreeRDP/server/shadow/cli/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP Shadow Server cmake build script
|
||||
#
|
||||
# Copyright 2025 Armin Novak <anoavk@thincast.com>
|
||||
# Copyright Thincast Technologies GmbH
|
||||
#
|
||||
# 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.
|
||||
|
||||
set(MODULE_NAME "freerdp-shadow-cli")
|
||||
|
||||
set(SRCS shadow.c)
|
||||
|
||||
addtargetwithresourcefile(${MODULE_NAME} TRUE "${FREERDP_VERSION}" SRCS)
|
||||
|
||||
list(APPEND LIBS freerdp-shadow-subsystem freerdp-shadow freerdp winpr)
|
||||
|
||||
target_link_libraries(${MODULE_NAME} PRIVATE ${LIBS})
|
||||
|
||||
installwithrpath(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT server)
|
||||
generate_and_install_freerdp_man_from_template(${MODULE_NAME} "1" "${FREERDP_API_VERSION}")
|
||||
93
third_party/FreeRDP/server/shadow/cli/freerdp-shadow-cli.1.in
vendored
Normal file
93
third_party/FreeRDP/server/shadow/cli/freerdp-shadow-cli.1.in
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
.de URL
|
||||
\\$2 \(laURL: \\$1 \(ra\\$3
|
||||
..
|
||||
.if \n[.g] .mso www.tmac
|
||||
.TH @MANPAGE_NAME@ 1 2017-01-12 "@FREERDP_VERSION_FULL@" "FreeRDP"
|
||||
.SH NAME
|
||||
@MANPAGE_NAME@ \- A utility for sharing a X display via RDP.
|
||||
.SH SYNOPSIS
|
||||
.B @MANPAGE_NAME@
|
||||
[\fB/port:\fP\fI<port number>\fP]
|
||||
[\fB/ipc-socket:\fP\fI<ipc-socket>\fP]
|
||||
[\fB/monitors:\fP\fI<0,1,2,...>\fP]
|
||||
[\fB/rect:\fP\fI<x,y,w,h>\fP]
|
||||
[\fB+auth\fP]
|
||||
[\fB-may-view\fP]
|
||||
[\fB-may-interact\fP]
|
||||
[\fB/sec:\fP\fI<rdp|tls|nla|ext>\fP]
|
||||
[\fB-sec-rdp\fP]
|
||||
[\fB-sec-tls\fP]
|
||||
[\fB-sec-nla\fP]
|
||||
[\fB-sec-ext\fP]
|
||||
[\fB/sam-file:\fP\fI<file>\fP]
|
||||
[\fB/version\fP]
|
||||
[\fB/help\fP]
|
||||
.SH DESCRIPTION
|
||||
.B @MANPAGE_NAME@
|
||||
can be used to share a running X display like with VNC but by using the RDP
|
||||
instead. It is also possibly to share only parts (rect) of the display.
|
||||
.SH OPTIONS
|
||||
.IP /ipc-socket:<ipc-socket>
|
||||
If this option is set an ipc socket with the path \fIipc-socket\fP is used
|
||||
instead of a TCP socket.
|
||||
.IP /port:<port>
|
||||
Set the port to use. Default is 3389.
|
||||
This option is ignored if ipc-socket is used.
|
||||
.IP /monitors:<1,2,3,...>
|
||||
Select the monitor(s) to share.
|
||||
.IP /rect:<x,y,w,h>
|
||||
Select rectangle within monitor to share.
|
||||
.IP -auth
|
||||
Disable authentication. If authentication is enabled PAM is used with the
|
||||
X11 subsystem. Running as root is not necessary, however if run as user only
|
||||
the same user that started @MANPAGE_NAME@ can authenticate.
|
||||
.br
|
||||
\fBWarning\fP: If authentication is disabled \fIeveryone\fP can connect.
|
||||
.IP -may-view
|
||||
Clients may view without prompt.
|
||||
.IP -may-interact
|
||||
Clients may interact without prompt.
|
||||
.IP /sec:<rdp|tls|nla|ext>
|
||||
Force a specific protocol security
|
||||
.IP -sec-rdp
|
||||
Disable RDP security (default:on)
|
||||
.IP -sec-tls
|
||||
Disable TLS protocol security (default:on)
|
||||
.IP -sec-nla
|
||||
Disable NLA protocol security (default:on)
|
||||
.IP +sec-ext
|
||||
Use NLA extended protocol security (default:off)
|
||||
.IP /sam-file:<file>
|
||||
NTLM SAM file for NLA authentication
|
||||
.IP /version
|
||||
Print the version and exit.
|
||||
.IP /help
|
||||
Print the help and exit.
|
||||
|
||||
.SH USAGE
|
||||
|
||||
#MANPAGE_NAME@ - start the shadow server on port 3389 with NLA security, SAM database at /etc/winpr/SAM
|
||||
.br
|
||||
@MANPAGE_NAME@ /sam-file:SAM.db - same as above, but a custom SAM database provided as argument
|
||||
.br
|
||||
@MANPAGE_NAME@ -sec-nla - start the shadow server on port 3380 with TLS/NLA security. This allows authenticating against PAM with unix users. Be aware that the password is transmitted plain text like with basic HTTP auth
|
||||
|
||||
.SH EXAMPLES
|
||||
@MANPAGE_NAME@ /port:12345
|
||||
|
||||
When run as user within a X session (for example from an xterm) a socket on
|
||||
12345 is opened and the current display is shared via RDP.
|
||||
|
||||
.SH EXIT STATUS
|
||||
.TP
|
||||
.B 0
|
||||
Successful program execution.
|
||||
.TP
|
||||
.B 1
|
||||
Otherwise.
|
||||
|
||||
.SH SEE ALSO
|
||||
wlog(7)
|
||||
|
||||
.SH AUTHOR
|
||||
FreeRDP <team@freerdp.com>
|
||||
199
third_party/FreeRDP/server/shadow/cli/shadow.c
vendored
Normal file
199
third_party/FreeRDP/server/shadow/cli/shadow.c
vendored
Normal file
@@ -0,0 +1,199 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/ssl.h>
|
||||
#include <winpr/path.h>
|
||||
#include <winpr/cmdline.h>
|
||||
#include <winpr/winsock.h>
|
||||
|
||||
#include <winpr/tools/makecert.h>
|
||||
|
||||
#include <freerdp/server/shadow.h>
|
||||
#include <freerdp/settings.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#define TAG SERVER_TAG("shadow")
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int status = 0;
|
||||
DWORD dwExitCode = 0;
|
||||
COMMAND_LINE_ARGUMENT_A shadow_args[] = {
|
||||
{ "log-filters", COMMAND_LINE_VALUE_REQUIRED, "<tag>:<level>[,<tag>:<level>[,...]]",
|
||||
nullptr, nullptr, -1, nullptr, "Set logger filters, see wLog(7) for details" },
|
||||
{ "log-level", COMMAND_LINE_VALUE_REQUIRED, "[OFF|FATAL|ERROR|WARN|INFO|DEBUG|TRACE]",
|
||||
nullptr, nullptr, -1, nullptr, "Set the default log level, see wLog(7) for details" },
|
||||
{ "port", COMMAND_LINE_VALUE_REQUIRED, "<number>", nullptr, nullptr, -1, nullptr,
|
||||
"Server port" },
|
||||
{ "ipc-socket", COMMAND_LINE_VALUE_REQUIRED, "<ipc-socket>", nullptr, nullptr, -1, nullptr,
|
||||
"Server IPC socket" },
|
||||
{ "bind-address", COMMAND_LINE_VALUE_REQUIRED, "<bind-address>[,<another address>, ...]",
|
||||
nullptr, nullptr, -1, nullptr,
|
||||
"An address to bind to. Use '[<ipv6>]' for IPv6 addresses, e.g. '[::1]' for "
|
||||
"localhost" },
|
||||
{ "server-side-cursor", COMMAND_LINE_VALUE_BOOL, nullptr, nullptr, nullptr, -1, nullptr,
|
||||
"hide mouse cursor in RDP client." },
|
||||
{ "monitors", COMMAND_LINE_VALUE_OPTIONAL, "<0,1,2...>", nullptr, nullptr, -1, nullptr,
|
||||
"Select or list monitors" },
|
||||
{ "max-connections", COMMAND_LINE_VALUE_REQUIRED, "<number>", nullptr, nullptr, -1, nullptr,
|
||||
"maximum connections allowed to server, 0 to deactivate" },
|
||||
{ "mouse-relative", COMMAND_LINE_VALUE_BOOL, nullptr, nullptr, nullptr, -1, nullptr,
|
||||
"enable support for relative mouse events" },
|
||||
{ "rect", COMMAND_LINE_VALUE_REQUIRED, "<x,y,w,h>", nullptr, nullptr, -1, nullptr,
|
||||
"Select rectangle within monitor to share" },
|
||||
{ "auth", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
|
||||
"Clients must authenticate" },
|
||||
{ "remote-guard", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueFalse, nullptr, -1, nullptr,
|
||||
"Remote credential guard" },
|
||||
{ "restricted-admin", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
|
||||
"Restricted Admin" },
|
||||
{ "vmconnect", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueFalse,
|
||||
nullptr, -1, nullptr, "Hyper-V console server (bind on vsock://1)" },
|
||||
{ "may-view", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
|
||||
"Clients may view without prompt" },
|
||||
{ "may-interact", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
|
||||
"Clients may interact without prompt" },
|
||||
{ "sec", COMMAND_LINE_VALUE_REQUIRED, "<rdp|tls|nla|ext>", nullptr, nullptr, -1, nullptr,
|
||||
"force specific protocol security" },
|
||||
{ "sec-rdp", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
|
||||
"rdp protocol security" },
|
||||
{ "sec-tls", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
|
||||
"tls protocol security" },
|
||||
{ "sec-nla", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
|
||||
"nla protocol security" },
|
||||
{ "sec-ext", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueFalse, nullptr, -1, nullptr,
|
||||
"nla extended protocol security" },
|
||||
{ "sam-file", COMMAND_LINE_VALUE_REQUIRED, "<file>", nullptr, nullptr, -1, nullptr,
|
||||
"NTLM SAM file for NLA authentication" },
|
||||
{ "keytab", COMMAND_LINE_VALUE_REQUIRED, "<file>", nullptr, nullptr, -1, nullptr,
|
||||
"Kerberos keytab file for NLA authentication" },
|
||||
{ "ccache", COMMAND_LINE_VALUE_REQUIRED, "<file>", nullptr, nullptr, -1, nullptr,
|
||||
"Kerberos host ccache file for NLA authentication" },
|
||||
{ "tls-secrets-file", COMMAND_LINE_VALUE_REQUIRED, "<file>", nullptr, nullptr, -1, nullptr,
|
||||
"file where tls secrets shall be stored" },
|
||||
{ "nsc", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
|
||||
"Allow NSC codec" },
|
||||
{ "rfx", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
|
||||
"Allow RFX surface bits" },
|
||||
{ "gfx", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
|
||||
"Allow GFX pipeline" },
|
||||
{ "gfx-progressive", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
|
||||
"Allow GFX progressive codec" },
|
||||
{ "gfx-rfx", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
|
||||
"Allow GFX RFX codec" },
|
||||
{ "gfx-planar", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
|
||||
"Allow GFX planar codec" },
|
||||
{ "gfx-avc420", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
|
||||
"Allow GFX AVC420 codec" },
|
||||
{ "gfx-avc444", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueTrue, nullptr, -1, nullptr,
|
||||
"Allow GFX AVC444 codec" },
|
||||
{ "bitmap-compat", COMMAND_LINE_VALUE_BOOL, nullptr, BoolValueFalse, nullptr, -1, nullptr,
|
||||
"Limit BitmapUpdate to 1 rectangle (fixes broken windows 11 24H2 clients)" },
|
||||
{ "version", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_VERSION, nullptr, nullptr,
|
||||
nullptr, -1, nullptr, "Print version" },
|
||||
{ "buildconfig", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_BUILDCONFIG, nullptr, nullptr,
|
||||
nullptr, -1, nullptr, "Print the build configuration" },
|
||||
{ "help", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_HELP, nullptr, nullptr, nullptr, -1,
|
||||
"?", "Print help" },
|
||||
{ nullptr, 0, nullptr, nullptr, nullptr, -1, nullptr, nullptr }
|
||||
};
|
||||
|
||||
shadow_subsystem_set_entry_builtin(nullptr);
|
||||
|
||||
rdpShadowServer* server = shadow_server_new();
|
||||
|
||||
if (!server)
|
||||
{
|
||||
status = -1;
|
||||
WLog_ERR(TAG, "Server new failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
{
|
||||
rdpSettings* settings = server->settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, TRUE) ||
|
||||
!freerdp_settings_set_bool(settings, FreeRDP_TlsSecurity, TRUE) ||
|
||||
!freerdp_settings_set_bool(settings, FreeRDP_RdpSecurity, TRUE))
|
||||
goto fail;
|
||||
|
||||
/* By default allow all GFX modes.
|
||||
* This can be changed with command line flags [+|-]gfx-CODEC
|
||||
*/
|
||||
if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, 32) ||
|
||||
!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, TRUE) ||
|
||||
!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, TRUE) ||
|
||||
!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxImageCodec, TRUE) ||
|
||||
!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxRlgrMode, RLGR3) ||
|
||||
!freerdp_settings_set_bool(settings, FreeRDP_GfxH264, TRUE) ||
|
||||
!freerdp_settings_set_bool(settings, FreeRDP_GfxAVC444, TRUE) ||
|
||||
!freerdp_settings_set_bool(settings, FreeRDP_GfxAVC444v2, TRUE) ||
|
||||
!freerdp_settings_set_bool(settings, FreeRDP_GfxProgressive, TRUE) ||
|
||||
!freerdp_settings_set_bool(settings, FreeRDP_GfxProgressiveV2, TRUE))
|
||||
goto fail;
|
||||
|
||||
if (!freerdp_settings_set_bool(settings, FreeRDP_MouseUseRelativeMove, FALSE) ||
|
||||
!freerdp_settings_set_bool(settings, FreeRDP_HasRelativeMouseEvent, FALSE))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((status = shadow_server_parse_command_line(server, argc, argv, shadow_args)) < 0)
|
||||
{
|
||||
status = shadow_server_command_line_status_print(server, argc, argv, status, shadow_args);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((status = shadow_server_init(server)) < 0)
|
||||
{
|
||||
WLog_ERR(TAG, "Server initialization failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((status = shadow_server_start(server)) < 0)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to start server.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
{
|
||||
MSG msg = WINPR_C_ARRAY_INIT;
|
||||
while (GetMessage(&msg, 0, 0, 0))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
(void)WaitForSingleObject(server->thread, INFINITE);
|
||||
|
||||
if (!GetExitCodeThread(server->thread, &dwExitCode))
|
||||
status = -1;
|
||||
else
|
||||
status = (int)dwExitCode;
|
||||
|
||||
fail:
|
||||
shadow_server_uninit(server);
|
||||
shadow_server_free(server);
|
||||
return status;
|
||||
}
|
||||
15
third_party/FreeRDP/server/shadow/freerdp-shadow.pc.in
vendored
Normal file
15
third_party/FreeRDP/server/shadow/freerdp-shadow.pc.in
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
prefix=@PKG_CONFIG_INSTALL_PREFIX@
|
||||
exec_prefix=${prefix}
|
||||
libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
|
||||
includedir=${prefix}/@FREERDP_INCLUDE_DIR@
|
||||
libs=-lfreerdp-shadow@FREERDP_API_VERSION@ -lfreerdp-shadow-subsystem@FREERDP_API_VERSION@
|
||||
|
||||
Name: FreeRDP shadow
|
||||
Description: FreeRDP: A Remote Desktop Protocol Implementation
|
||||
URL: http://www.freerdp.com/
|
||||
Version: @FREERDP_VERSION@
|
||||
Requires: @FREERDP_SHADOW_PC_REQUIRES@
|
||||
Requires.private: @FREERDP_SHADOW_PC_REQUIRES_PRIVATE@
|
||||
Libs: -L${libdir} ${libs}
|
||||
Libs.private: @FREERDP_SHADOW_PC_LIBRARY_PRIVATE@
|
||||
Cflags: -I${includedir}
|
||||
44
third_party/FreeRDP/server/shadow/shadow.h
vendored
Normal file
44
third_party/FreeRDP/server/shadow/shadow.h
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_SHADOW_SHADOW_H
|
||||
#define FREERDP_SERVER_SHADOW_SHADOW_H
|
||||
|
||||
#include <freerdp/server/shadow.h>
|
||||
|
||||
#include "shadow_client.h"
|
||||
#include "shadow_input.h"
|
||||
#include "shadow_screen.h"
|
||||
#include "shadow_surface.h"
|
||||
#include "shadow_encoder.h"
|
||||
#include "shadow_capture.h"
|
||||
#include "shadow_channels.h"
|
||||
#include "shadow_subsystem.h"
|
||||
#include "shadow_lobby.h"
|
||||
#include "shadow_mcevent.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_SERVER_SHADOW_SHADOW_H */
|
||||
106
third_party/FreeRDP/server/shadow/shadow_audin.c
vendored
Normal file
106
third_party/FreeRDP/server/shadow/shadow_audin.c
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2015 Jiang Zihao <zihao.jiang@yahoo.com>
|
||||
* Copyright 2023 Pascal Nowack <Pascal.Nowack@gmx.de>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#include "shadow.h"
|
||||
|
||||
#include "shadow_audin.h"
|
||||
#include <freerdp/server/server-common.h>
|
||||
|
||||
#if defined(CHANNEL_AUDIN_SERVER)
|
||||
#include <freerdp/server/audin.h>
|
||||
#endif
|
||||
|
||||
#if defined(CHANNEL_AUDIN_SERVER)
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static UINT AudinServerData(audin_server_context* audin, const SNDIN_DATA* data)
|
||||
{
|
||||
rdpShadowClient* client = nullptr;
|
||||
rdpShadowSubsystem* subsystem = nullptr;
|
||||
|
||||
WINPR_ASSERT(audin);
|
||||
WINPR_ASSERT(data);
|
||||
|
||||
client = audin->userdata;
|
||||
WINPR_ASSERT(client);
|
||||
WINPR_ASSERT(client->server);
|
||||
subsystem = client->server->subsystem;
|
||||
WINPR_ASSERT(subsystem);
|
||||
|
||||
if (!client->mayInteract)
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
if (!IFCALLRESULT(TRUE, subsystem->AudinServerReceiveSamples, subsystem, client,
|
||||
audin_server_get_negotiated_format(client->audin), data->Data))
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
BOOL shadow_client_audin_init(rdpShadowClient* client)
|
||||
{
|
||||
WINPR_ASSERT(client);
|
||||
|
||||
#if defined(CHANNEL_AUDIN_SERVER)
|
||||
audin_server_context* audin = client->audin = audin_server_context_new(client->vcm);
|
||||
|
||||
if (!audin)
|
||||
return FALSE;
|
||||
|
||||
audin->userdata = client;
|
||||
|
||||
audin->Data = AudinServerData;
|
||||
|
||||
if (client->subsystem->audinFormats)
|
||||
{
|
||||
if (client->subsystem->nAudinFormats > SSIZE_MAX)
|
||||
goto fail;
|
||||
|
||||
if (!audin_server_set_formats(client->audin, (SSIZE_T)client->subsystem->nAudinFormats,
|
||||
client->subsystem->audinFormats))
|
||||
goto fail;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!audin_server_set_formats(client->audin, -1, nullptr))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
fail:
|
||||
audin_server_context_free(audin);
|
||||
client->audin = nullptr;
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void shadow_client_audin_uninit(rdpShadowClient* client)
|
||||
{
|
||||
WINPR_ASSERT(client);
|
||||
|
||||
#if defined(CHANNEL_AUDIN_SERVER)
|
||||
audin_server_context_free(client->audin);
|
||||
client->audin = nullptr;
|
||||
#endif
|
||||
}
|
||||
39
third_party/FreeRDP/server/shadow/shadow_audin.h
vendored
Normal file
39
third_party/FreeRDP/server/shadow/shadow_audin.h
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2015 Jiang Zihao <zihao.jiang@yahoo.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_SHADOW_AUDIN_H
|
||||
#define FREERDP_SERVER_SHADOW_AUDIN_H
|
||||
|
||||
#include <freerdp/server/shadow.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
WINPR_ATTR_NODISCARD BOOL shadow_client_audin_init(rdpShadowClient* client);
|
||||
void shadow_client_audin_uninit(rdpShadowClient* client);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_SERVER_SHADOW_AUDIN_H */
|
||||
349
third_party/FreeRDP/server/shadow/shadow_capture.c
vendored
Normal file
349
third_party/FreeRDP/server/shadow/shadow_capture.c
vendored
Normal file
@@ -0,0 +1,349 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/print.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
|
||||
#include "shadow_surface.h"
|
||||
|
||||
#include "shadow_capture.h"
|
||||
|
||||
int shadow_capture_align_clip_rect(RECTANGLE_16* rect, const RECTANGLE_16* clip)
|
||||
{
|
||||
int dx = 0;
|
||||
int dy = 0;
|
||||
dx = (rect->left % 16);
|
||||
|
||||
if (dx != 0)
|
||||
{
|
||||
rect->left -= dx;
|
||||
rect->right += dx;
|
||||
}
|
||||
|
||||
dx = (rect->right % 16);
|
||||
|
||||
if (dx != 0)
|
||||
{
|
||||
rect->right += (16 - dx);
|
||||
}
|
||||
|
||||
dy = (rect->top % 16);
|
||||
|
||||
if (dy != 0)
|
||||
{
|
||||
rect->top -= dy;
|
||||
rect->bottom += dy;
|
||||
}
|
||||
|
||||
dy = (rect->bottom % 16);
|
||||
|
||||
if (dy != 0)
|
||||
{
|
||||
rect->bottom += (16 - dy);
|
||||
}
|
||||
|
||||
if (rect->left < clip->left)
|
||||
rect->left = clip->left;
|
||||
|
||||
if (rect->top < clip->top)
|
||||
rect->top = clip->top;
|
||||
|
||||
if (rect->right > clip->right)
|
||||
rect->right = clip->right;
|
||||
|
||||
if (rect->bottom > clip->bottom)
|
||||
rect->bottom = clip->bottom;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
|
||||
int shadow_capture_compare(const BYTE* WINPR_RESTRICT pData1, UINT32 nStep1, UINT32 nWidth,
|
||||
UINT32 nHeight, const BYTE* WINPR_RESTRICT pData2, UINT32 nStep2,
|
||||
RECTANGLE_16* WINPR_RESTRICT rect)
|
||||
{
|
||||
return shadow_capture_compare_with_format(pData1, PIXEL_FORMAT_BGRX32, nStep1, nWidth, nHeight,
|
||||
pData2, PIXEL_FORMAT_BGRX32, nStep2, rect);
|
||||
}
|
||||
#endif
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static BOOL color_equal(UINT32 colorA, UINT32 formatA, UINT32 colorB, UINT32 formatB)
|
||||
{
|
||||
BYTE ar = 0;
|
||||
BYTE ag = 0;
|
||||
BYTE ab = 0;
|
||||
BYTE aa = 0;
|
||||
BYTE br = 0;
|
||||
BYTE bg = 0;
|
||||
BYTE bb = 0;
|
||||
BYTE ba = 0;
|
||||
FreeRDPSplitColor(colorA, formatA, &ar, &ag, &ab, &aa, nullptr);
|
||||
FreeRDPSplitColor(colorB, formatB, &br, &bg, &bb, &ba, nullptr);
|
||||
|
||||
if (ar != br)
|
||||
return FALSE;
|
||||
if (ag != bg)
|
||||
return FALSE;
|
||||
if (ab != bb)
|
||||
return FALSE;
|
||||
if (aa != ba)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static BOOL pixel_equal(const BYTE* WINPR_RESTRICT a, UINT32 formatA, const BYTE* WINPR_RESTRICT b,
|
||||
UINT32 formatB, size_t count)
|
||||
{
|
||||
const size_t bppA = FreeRDPGetBytesPerPixel(formatA);
|
||||
const size_t bppB = FreeRDPGetBytesPerPixel(formatB);
|
||||
|
||||
for (size_t x = 0; x < count; x++)
|
||||
{
|
||||
const UINT32 colorA = FreeRDPReadColor(&a[bppA * x], formatA);
|
||||
const UINT32 colorB = FreeRDPReadColor(&b[bppB * x], formatB);
|
||||
if (!color_equal(colorA, formatA, colorB, formatB))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static BOOL color_equal_no_alpha(UINT32 colorA, UINT32 formatA, UINT32 colorB, UINT32 formatB)
|
||||
{
|
||||
BYTE ar = 0;
|
||||
BYTE ag = 0;
|
||||
BYTE ab = 0;
|
||||
BYTE br = 0;
|
||||
BYTE bg = 0;
|
||||
BYTE bb = 0;
|
||||
FreeRDPSplitColor(colorA, formatA, &ar, &ag, &ab, nullptr, nullptr);
|
||||
FreeRDPSplitColor(colorB, formatB, &br, &bg, &bb, nullptr, nullptr);
|
||||
|
||||
if (ar != br)
|
||||
return FALSE;
|
||||
if (ag != bg)
|
||||
return FALSE;
|
||||
if (ab != bb)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static BOOL pixel_equal_no_alpha(const BYTE* WINPR_RESTRICT a, UINT32 formatA,
|
||||
const BYTE* WINPR_RESTRICT b, UINT32 formatB, size_t count)
|
||||
{
|
||||
const size_t bppA = FreeRDPGetBytesPerPixel(formatA);
|
||||
const size_t bppB = FreeRDPGetBytesPerPixel(formatB);
|
||||
|
||||
for (size_t x = 0; x < count; x++)
|
||||
{
|
||||
const UINT32 colorA = FreeRDPReadColor(&a[bppA * x], formatA);
|
||||
const UINT32 colorB = FreeRDPReadColor(&b[bppB * x], formatB);
|
||||
if (!color_equal_no_alpha(colorA, formatA, colorB, formatB))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static BOOL pixel_equal_same_format(const BYTE* WINPR_RESTRICT a, UINT32 formatA,
|
||||
const BYTE* WINPR_RESTRICT b, UINT32 formatB, size_t count)
|
||||
{
|
||||
if (formatA != formatB)
|
||||
return FALSE;
|
||||
const size_t bppA = FreeRDPGetBytesPerPixel(formatA);
|
||||
return memcmp(a, b, count * bppA) == 0;
|
||||
}
|
||||
|
||||
typedef BOOL (*pixel_equal_fn_t)(const BYTE* WINPR_RESTRICT a, UINT32 formatA,
|
||||
const BYTE* WINPR_RESTRICT b, UINT32 formatB, size_t count);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static pixel_equal_fn_t get_comparison_fn(DWORD format1, DWORD format2)
|
||||
{
|
||||
|
||||
if (format1 == format2)
|
||||
return pixel_equal_same_format;
|
||||
|
||||
const UINT32 bpp1 = FreeRDPGetBitsPerPixel(format1);
|
||||
|
||||
if (!FreeRDPColorHasAlpha(format1) || !FreeRDPColorHasAlpha(format2))
|
||||
{
|
||||
/* In case we have RGBA32 and RGBX32 or similar assume the alpha data is equal.
|
||||
* This allows us to use the fast memcmp comparison. */
|
||||
if ((bpp1 == 32) && FreeRDPAreColorFormatsEqualNoAlpha(format1, format2))
|
||||
{
|
||||
switch (format1)
|
||||
{
|
||||
case PIXEL_FORMAT_ARGB32:
|
||||
case PIXEL_FORMAT_XRGB32:
|
||||
case PIXEL_FORMAT_ABGR32:
|
||||
case PIXEL_FORMAT_XBGR32:
|
||||
return pixel_equal;
|
||||
case PIXEL_FORMAT_RGBA32:
|
||||
case PIXEL_FORMAT_RGBX32:
|
||||
case PIXEL_FORMAT_BGRA32:
|
||||
case PIXEL_FORMAT_BGRX32:
|
||||
return pixel_equal;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return pixel_equal_no_alpha;
|
||||
}
|
||||
else
|
||||
return pixel_equal_no_alpha;
|
||||
}
|
||||
|
||||
int shadow_capture_compare_with_format(const BYTE* WINPR_RESTRICT pData1, UINT32 format1,
|
||||
UINT32 nStep1, UINT32 nWidth, UINT32 nHeight,
|
||||
const BYTE* WINPR_RESTRICT pData2, UINT32 format2,
|
||||
UINT32 nStep2, RECTANGLE_16* WINPR_RESTRICT rect)
|
||||
{
|
||||
pixel_equal_fn_t pixel_equal_fn = get_comparison_fn(format1, format2);
|
||||
BOOL allEqual = TRUE;
|
||||
UINT32 tw = 0;
|
||||
const UINT32 nrow = (nHeight + 15) / 16;
|
||||
const UINT32 ncol = (nWidth + 15) / 16;
|
||||
UINT32 l = ncol + 1;
|
||||
UINT32 t = nrow + 1;
|
||||
UINT32 r = 0;
|
||||
UINT32 b = 0;
|
||||
const size_t bppA = FreeRDPGetBytesPerPixel(format1);
|
||||
const size_t bppB = FreeRDPGetBytesPerPixel(format2);
|
||||
const RECTANGLE_16 empty = WINPR_C_ARRAY_INIT;
|
||||
WINPR_ASSERT(rect);
|
||||
|
||||
*rect = empty;
|
||||
|
||||
for (size_t ty = 0; ty < nrow; ty++)
|
||||
{
|
||||
BOOL rowEqual = TRUE;
|
||||
size_t th = ((ty + 1) == nrow) ? (nHeight % 16) : 16;
|
||||
|
||||
if (!th)
|
||||
th = 16;
|
||||
|
||||
for (size_t tx = 0; tx < ncol; tx++)
|
||||
{
|
||||
BOOL equal = TRUE;
|
||||
tw = ((tx + 1) == ncol) ? (nWidth % 16) : 16;
|
||||
|
||||
if (!tw)
|
||||
tw = 16;
|
||||
|
||||
const BYTE* p1 = &pData1[(ty * 16ULL * nStep1) + (tx * 16ull * bppA)];
|
||||
const BYTE* p2 = &pData2[(ty * 16ULL * nStep2) + (tx * 16ull * bppB)];
|
||||
|
||||
for (size_t k = 0; k < th; k++)
|
||||
{
|
||||
if (!pixel_equal_fn(p1, format1, p2, format2, tw))
|
||||
{
|
||||
equal = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
p1 += nStep1;
|
||||
p2 += nStep2;
|
||||
}
|
||||
|
||||
if (!equal)
|
||||
{
|
||||
rowEqual = FALSE;
|
||||
if (l > tx)
|
||||
l = (UINT32)tx;
|
||||
|
||||
if (r < tx)
|
||||
r = (UINT32)tx;
|
||||
}
|
||||
}
|
||||
|
||||
if (!rowEqual)
|
||||
{
|
||||
allEqual = FALSE;
|
||||
|
||||
if (t > ty)
|
||||
t = (UINT32)ty;
|
||||
|
||||
if (b < ty)
|
||||
b = (UINT32)ty;
|
||||
}
|
||||
}
|
||||
|
||||
if (allEqual)
|
||||
return 0;
|
||||
|
||||
WINPR_ASSERT(l * 16 <= UINT16_MAX);
|
||||
WINPR_ASSERT(t * 16 <= UINT16_MAX);
|
||||
WINPR_ASSERT((r + 1) * 16 <= UINT16_MAX);
|
||||
WINPR_ASSERT((b + 1) * 16 <= UINT16_MAX);
|
||||
rect->left = (UINT16)l * 16;
|
||||
rect->top = (UINT16)t * 16;
|
||||
rect->right = (UINT16)(r + 1) * 16;
|
||||
rect->bottom = (UINT16)(b + 1) * 16;
|
||||
|
||||
WINPR_ASSERT(nWidth <= UINT16_MAX);
|
||||
if (rect->right > nWidth)
|
||||
rect->right = (UINT16)nWidth;
|
||||
|
||||
WINPR_ASSERT(nHeight <= UINT16_MAX);
|
||||
if (rect->bottom > nHeight)
|
||||
rect->bottom = (UINT16)nHeight;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
rdpShadowCapture* shadow_capture_new(rdpShadowServer* server)
|
||||
{
|
||||
WINPR_ASSERT(server);
|
||||
|
||||
rdpShadowCapture* capture = (rdpShadowCapture*)calloc(1, sizeof(rdpShadowCapture));
|
||||
|
||||
if (!capture)
|
||||
return nullptr;
|
||||
|
||||
capture->server = server;
|
||||
|
||||
if (!InitializeCriticalSectionAndSpinCount(&(capture->lock), 4000))
|
||||
{
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
shadow_capture_free(capture);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return capture;
|
||||
}
|
||||
|
||||
void shadow_capture_free(rdpShadowCapture* capture)
|
||||
{
|
||||
if (!capture)
|
||||
return;
|
||||
|
||||
DeleteCriticalSection(&(capture->lock));
|
||||
free(capture);
|
||||
}
|
||||
53
third_party/FreeRDP/server/shadow/shadow_capture.h
vendored
Normal file
53
third_party/FreeRDP/server/shadow/shadow_capture.h
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_SHADOW_CAPTURE_H
|
||||
#define FREERDP_SERVER_SHADOW_CAPTURE_H
|
||||
|
||||
#include <freerdp/server/shadow.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/synch.h>
|
||||
|
||||
struct rdp_shadow_capture
|
||||
{
|
||||
rdpShadowServer* server;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
|
||||
CRITICAL_SECTION lock;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void shadow_capture_free(rdpShadowCapture* capture);
|
||||
|
||||
WINPR_ATTR_MALLOC(shadow_capture_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
rdpShadowCapture* shadow_capture_new(rdpShadowServer* server);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_SERVER_SHADOW_CAPTURE_H */
|
||||
61
third_party/FreeRDP/server/shadow/shadow_channels.c
vendored
Normal file
61
third_party/FreeRDP/server/shadow/shadow_channels.c
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include "shadow.h"
|
||||
|
||||
#include "shadow_channels.h"
|
||||
|
||||
UINT shadow_client_channels_post_connect(rdpShadowClient* client)
|
||||
{
|
||||
if (WTSVirtualChannelManagerIsChannelJoined(client->vcm, ENCOMSP_SVC_CHANNEL_NAME))
|
||||
{
|
||||
if (shadow_client_encomsp_init(client) < 0)
|
||||
return ERROR_NOT_READY;
|
||||
}
|
||||
|
||||
if (WTSVirtualChannelManagerIsChannelJoined(client->vcm, REMDESK_SVC_CHANNEL_NAME))
|
||||
{
|
||||
if (shadow_client_remdesk_init(client) < 0)
|
||||
return ERROR_NOT_READY;
|
||||
}
|
||||
|
||||
if (WTSVirtualChannelManagerIsChannelJoined(client->vcm, RDPSND_CHANNEL_NAME))
|
||||
{
|
||||
if (shadow_client_rdpsnd_init(client) < 0)
|
||||
return ERROR_NOT_READY;
|
||||
}
|
||||
|
||||
if (!shadow_client_audin_init(client))
|
||||
return ERROR_NOT_READY;
|
||||
|
||||
if (shadow_client_rdpgfx_init(client) < 0)
|
||||
return ERROR_NOT_READY;
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
void shadow_client_channels_free(rdpShadowClient* client)
|
||||
{
|
||||
shadow_client_rdpgfx_uninit(client);
|
||||
shadow_client_audin_uninit(client);
|
||||
shadow_client_rdpsnd_uninit(client);
|
||||
shadow_client_remdesk_uninit(client);
|
||||
shadow_client_encomsp_uninit(client);
|
||||
}
|
||||
45
third_party/FreeRDP/server/shadow/shadow_channels.h
vendored
Normal file
45
third_party/FreeRDP/server/shadow/shadow_channels.h
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_SHADOW_CHANNELS_H
|
||||
#define FREERDP_SERVER_SHADOW_CHANNELS_H
|
||||
|
||||
#include <freerdp/server/shadow.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
|
||||
#include "shadow_encomsp.h"
|
||||
#include "shadow_remdesk.h"
|
||||
#include "shadow_rdpsnd.h"
|
||||
#include "shadow_audin.h"
|
||||
#include "shadow_rdpgfx.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
WINPR_ATTR_NODISCARD UINT shadow_client_channels_post_connect(rdpShadowClient* client);
|
||||
void shadow_client_channels_free(rdpShadowClient* client);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_SERVER_SHADOW_CHANNELS_H */
|
||||
2820
third_party/FreeRDP/server/shadow/shadow_client.c
vendored
Normal file
2820
third_party/FreeRDP/server/shadow/shadow_client.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
36
third_party/FreeRDP/server/shadow/shadow_client.h
vendored
Normal file
36
third_party/FreeRDP/server/shadow/shadow_client.h
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_SHADOW_CLIENT_H
|
||||
#define FREERDP_SERVER_SHADOW_CLIENT_H
|
||||
|
||||
#include <freerdp/server/shadow.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
WINPR_ATTR_NODISCARD BOOL shadow_client_accepted(freerdp_listener* listener,
|
||||
freerdp_peer* peer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_SERVER_SHADOW_CLIENT_H */
|
||||
534
third_party/FreeRDP/server/shadow/shadow_encoder.c
vendored
Normal file
534
third_party/FreeRDP/server/shadow/shadow_encoder.c
vendored
Normal file
@@ -0,0 +1,534 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#include "shadow.h"
|
||||
|
||||
#include "shadow_encoder.h"
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#define TAG CLIENT_TAG("shadow")
|
||||
|
||||
UINT32 shadow_encoder_preferred_fps(rdpShadowEncoder* encoder)
|
||||
{
|
||||
/* Return preferred fps calculated according to the last
|
||||
* sent frame id and last client-acknowledged frame id.
|
||||
*/
|
||||
return encoder->fps;
|
||||
}
|
||||
|
||||
UINT32 shadow_encoder_inflight_frames(rdpShadowEncoder* encoder)
|
||||
{
|
||||
/* Return in-flight frame count.
|
||||
* If queueDepth is SUSPEND_FRAME_ACKNOWLEDGEMENT, count = 0
|
||||
* Otherwise, calculate count =
|
||||
* <last sent frame id> - <last client-acknowledged frame id>
|
||||
* Note: This function is exported so that subsystem could
|
||||
* implement its own strategy to tune fps.
|
||||
*/
|
||||
return (encoder->queueDepth == SUSPEND_FRAME_ACKNOWLEDGEMENT)
|
||||
? 0
|
||||
: encoder->frameId - encoder->lastAckframeId;
|
||||
}
|
||||
|
||||
UINT32 shadow_encoder_create_frame_id(rdpShadowEncoder* encoder)
|
||||
{
|
||||
UINT32 frameId = 0;
|
||||
UINT32 inFlightFrames = shadow_encoder_inflight_frames(encoder);
|
||||
|
||||
/*
|
||||
* Calculate preferred fps according to how much frames are
|
||||
* in-progress. Note that it only works when subsystem implementation
|
||||
* calls shadow_encoder_preferred_fps and takes the suggestion.
|
||||
*/
|
||||
if (inFlightFrames > 1)
|
||||
{
|
||||
encoder->fps = (100 / (inFlightFrames + 1) * encoder->maxFps) / 100;
|
||||
}
|
||||
else
|
||||
{
|
||||
encoder->fps += 2;
|
||||
|
||||
if (encoder->fps > encoder->maxFps)
|
||||
encoder->fps = encoder->maxFps;
|
||||
}
|
||||
|
||||
if (encoder->fps < 1)
|
||||
encoder->fps = 1;
|
||||
|
||||
frameId = ++encoder->frameId;
|
||||
return frameId;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static int shadow_encoder_init_grid(rdpShadowEncoder* encoder)
|
||||
{
|
||||
UINT32 tileSize = 0;
|
||||
UINT32 tileCount = 0;
|
||||
encoder->gridWidth = ((encoder->width + (encoder->maxTileWidth - 1)) / encoder->maxTileWidth);
|
||||
encoder->gridHeight =
|
||||
((encoder->height + (encoder->maxTileHeight - 1)) / encoder->maxTileHeight);
|
||||
tileSize = encoder->maxTileWidth * encoder->maxTileHeight * 4;
|
||||
tileCount = encoder->gridWidth * encoder->gridHeight;
|
||||
encoder->gridBuffer = (BYTE*)calloc(tileSize, tileCount);
|
||||
|
||||
if (!encoder->gridBuffer)
|
||||
return -1;
|
||||
|
||||
encoder->grid = (BYTE**)calloc(tileCount, sizeof(BYTE*));
|
||||
|
||||
if (!encoder->grid)
|
||||
return -1;
|
||||
|
||||
for (UINT32 i = 0; i < encoder->gridHeight; i++)
|
||||
{
|
||||
for (UINT32 j = 0; j < encoder->gridWidth; j++)
|
||||
{
|
||||
const size_t k = (1ULL * i * encoder->gridWidth) + j;
|
||||
encoder->grid[k] = &(encoder->gridBuffer[k * tileSize]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int shadow_encoder_uninit_grid(rdpShadowEncoder* encoder)
|
||||
{
|
||||
if (encoder->gridBuffer)
|
||||
{
|
||||
free(encoder->gridBuffer);
|
||||
encoder->gridBuffer = nullptr;
|
||||
}
|
||||
|
||||
if (encoder->grid)
|
||||
{
|
||||
free((void*)encoder->grid);
|
||||
encoder->grid = nullptr;
|
||||
}
|
||||
|
||||
encoder->gridWidth = 0;
|
||||
encoder->gridHeight = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static int shadow_encoder_init_rfx(rdpShadowEncoder* encoder)
|
||||
{
|
||||
if (!encoder->rfx)
|
||||
encoder->rfx = rfx_context_new_ex(
|
||||
TRUE, freerdp_settings_get_uint32(encoder->server->settings, FreeRDP_ThreadingFlags));
|
||||
|
||||
if (!encoder->rfx)
|
||||
goto fail;
|
||||
|
||||
if (!rfx_context_reset(encoder->rfx, encoder->width, encoder->height))
|
||||
goto fail;
|
||||
|
||||
{
|
||||
const UINT32 mode =
|
||||
freerdp_settings_get_uint32(encoder->server->settings, FreeRDP_RemoteFxRlgrMode);
|
||||
if (!rfx_context_set_mode(encoder->rfx, WINPR_ASSERTING_INT_CAST(RLGR_MODE, mode)))
|
||||
goto fail;
|
||||
}
|
||||
rfx_context_set_pixel_format(encoder->rfx, PIXEL_FORMAT_BGRX32);
|
||||
encoder->codecs |= FREERDP_CODEC_REMOTEFX;
|
||||
return 1;
|
||||
fail:
|
||||
rfx_context_free(encoder->rfx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static int shadow_encoder_init_nsc(rdpShadowEncoder* encoder)
|
||||
{
|
||||
rdpContext* context = (rdpContext*)encoder->client;
|
||||
rdpSettings* settings = context->settings;
|
||||
|
||||
if (!encoder->nsc)
|
||||
encoder->nsc = nsc_context_new();
|
||||
|
||||
if (!encoder->nsc)
|
||||
goto fail;
|
||||
|
||||
if (!nsc_context_reset(encoder->nsc, encoder->width, encoder->height))
|
||||
goto fail;
|
||||
|
||||
if (!nsc_context_set_parameters(
|
||||
encoder->nsc, NSC_COLOR_LOSS_LEVEL,
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_NSCodecColorLossLevel)))
|
||||
goto fail;
|
||||
if (!nsc_context_set_parameters(
|
||||
encoder->nsc, NSC_ALLOW_SUBSAMPLING,
|
||||
freerdp_settings_get_bool(settings, FreeRDP_NSCodecAllowSubsampling) ? 1 : 0))
|
||||
goto fail;
|
||||
if (!nsc_context_set_parameters(
|
||||
encoder->nsc, NSC_DYNAMIC_COLOR_FIDELITY,
|
||||
!freerdp_settings_get_bool(settings, FreeRDP_NSCodecAllowDynamicColorFidelity)))
|
||||
goto fail;
|
||||
if (!nsc_context_set_parameters(encoder->nsc, NSC_COLOR_FORMAT, PIXEL_FORMAT_BGRX32))
|
||||
goto fail;
|
||||
encoder->codecs |= FREERDP_CODEC_NSCODEC;
|
||||
return 1;
|
||||
fail:
|
||||
nsc_context_free(encoder->nsc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static int shadow_encoder_init_planar(rdpShadowEncoder* encoder)
|
||||
{
|
||||
DWORD planarFlags = 0;
|
||||
rdpContext* context = (rdpContext*)encoder->client;
|
||||
rdpSettings* settings = context->settings;
|
||||
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_DrawAllowSkipAlpha))
|
||||
planarFlags |= PLANAR_FORMAT_HEADER_NA;
|
||||
|
||||
planarFlags |= PLANAR_FORMAT_HEADER_RLE;
|
||||
|
||||
if (!encoder->planar)
|
||||
{
|
||||
encoder->planar = freerdp_bitmap_planar_context_new(planarFlags, encoder->maxTileWidth,
|
||||
encoder->maxTileHeight);
|
||||
}
|
||||
|
||||
if (!encoder->planar)
|
||||
goto fail;
|
||||
|
||||
if (!freerdp_bitmap_planar_context_reset(encoder->planar, encoder->maxTileWidth,
|
||||
encoder->maxTileHeight))
|
||||
goto fail;
|
||||
|
||||
encoder->codecs |= FREERDP_CODEC_PLANAR;
|
||||
return 1;
|
||||
fail:
|
||||
freerdp_bitmap_planar_context_free(encoder->planar);
|
||||
return -1;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static int shadow_encoder_init_interleaved(rdpShadowEncoder* encoder)
|
||||
{
|
||||
if (!encoder->interleaved)
|
||||
encoder->interleaved = bitmap_interleaved_context_new(TRUE);
|
||||
|
||||
if (!encoder->interleaved)
|
||||
goto fail;
|
||||
|
||||
if (!bitmap_interleaved_context_reset(encoder->interleaved))
|
||||
goto fail;
|
||||
|
||||
encoder->codecs |= FREERDP_CODEC_INTERLEAVED;
|
||||
return 1;
|
||||
fail:
|
||||
bitmap_interleaved_context_free(encoder->interleaved);
|
||||
return -1;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static int shadow_encoder_init_h264(rdpShadowEncoder* encoder)
|
||||
{
|
||||
if (!encoder->h264)
|
||||
encoder->h264 = h264_context_new(TRUE);
|
||||
|
||||
if (!encoder->h264)
|
||||
goto fail;
|
||||
|
||||
if (!h264_context_reset(encoder->h264, encoder->width, encoder->height))
|
||||
goto fail;
|
||||
|
||||
if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_RATECONTROL,
|
||||
encoder->server->h264RateControlMode))
|
||||
goto fail;
|
||||
if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_BITRATE,
|
||||
encoder->server->h264BitRate))
|
||||
goto fail;
|
||||
if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_FRAMERATE,
|
||||
encoder->server->h264FrameRate))
|
||||
goto fail;
|
||||
if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_QP, encoder->server->h264QP))
|
||||
goto fail;
|
||||
|
||||
encoder->codecs |= FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444;
|
||||
return 1;
|
||||
fail:
|
||||
h264_context_free(encoder->h264);
|
||||
return -1;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static int shadow_encoder_init_progressive(rdpShadowEncoder* encoder)
|
||||
{
|
||||
WINPR_ASSERT(encoder);
|
||||
if (!encoder->progressive)
|
||||
encoder->progressive = progressive_context_new(TRUE);
|
||||
|
||||
if (!encoder->progressive)
|
||||
goto fail;
|
||||
|
||||
if (!progressive_context_reset(encoder->progressive))
|
||||
goto fail;
|
||||
|
||||
encoder->codecs |= FREERDP_CODEC_PROGRESSIVE;
|
||||
return 1;
|
||||
fail:
|
||||
progressive_context_free(encoder->progressive);
|
||||
return -1;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static int shadow_encoder_init(rdpShadowEncoder* encoder)
|
||||
{
|
||||
encoder->width = encoder->server->screen->width;
|
||||
encoder->height = encoder->server->screen->height;
|
||||
encoder->maxTileWidth = 64;
|
||||
encoder->maxTileHeight = 64;
|
||||
if (shadow_encoder_init_grid(encoder) < 0)
|
||||
return -1;
|
||||
|
||||
if (!encoder->bs)
|
||||
encoder->bs = Stream_New(nullptr, 4ULL * encoder->maxTileWidth * encoder->maxTileHeight);
|
||||
|
||||
if (!encoder->bs)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int shadow_encoder_uninit_rfx(rdpShadowEncoder* encoder)
|
||||
{
|
||||
if (encoder->rfx)
|
||||
{
|
||||
rfx_context_free(encoder->rfx);
|
||||
encoder->rfx = nullptr;
|
||||
}
|
||||
|
||||
encoder->codecs &= (UINT32)~FREERDP_CODEC_REMOTEFX;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int shadow_encoder_uninit_nsc(rdpShadowEncoder* encoder)
|
||||
{
|
||||
if (encoder->nsc)
|
||||
{
|
||||
nsc_context_free(encoder->nsc);
|
||||
encoder->nsc = nullptr;
|
||||
}
|
||||
|
||||
encoder->codecs &= (UINT32)~FREERDP_CODEC_NSCODEC;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int shadow_encoder_uninit_planar(rdpShadowEncoder* encoder)
|
||||
{
|
||||
if (encoder->planar)
|
||||
{
|
||||
freerdp_bitmap_planar_context_free(encoder->planar);
|
||||
encoder->planar = nullptr;
|
||||
}
|
||||
|
||||
encoder->codecs &= (UINT32)~FREERDP_CODEC_PLANAR;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int shadow_encoder_uninit_interleaved(rdpShadowEncoder* encoder)
|
||||
{
|
||||
if (encoder->interleaved)
|
||||
{
|
||||
bitmap_interleaved_context_free(encoder->interleaved);
|
||||
encoder->interleaved = nullptr;
|
||||
}
|
||||
|
||||
encoder->codecs &= (UINT32)~FREERDP_CODEC_INTERLEAVED;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int shadow_encoder_uninit_h264(rdpShadowEncoder* encoder)
|
||||
{
|
||||
if (encoder->h264)
|
||||
{
|
||||
h264_context_free(encoder->h264);
|
||||
encoder->h264 = nullptr;
|
||||
}
|
||||
|
||||
encoder->codecs &= (UINT32) ~(FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int shadow_encoder_uninit_progressive(rdpShadowEncoder* encoder)
|
||||
{
|
||||
WINPR_ASSERT(encoder);
|
||||
if (encoder->progressive)
|
||||
{
|
||||
progressive_context_free(encoder->progressive);
|
||||
encoder->progressive = nullptr;
|
||||
}
|
||||
|
||||
encoder->codecs &= (UINT32)~FREERDP_CODEC_PROGRESSIVE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int shadow_encoder_uninit(rdpShadowEncoder* encoder)
|
||||
{
|
||||
shadow_encoder_uninit_grid(encoder);
|
||||
|
||||
if (encoder->bs)
|
||||
{
|
||||
Stream_Free(encoder->bs, TRUE);
|
||||
encoder->bs = nullptr;
|
||||
}
|
||||
|
||||
shadow_encoder_uninit_rfx(encoder);
|
||||
|
||||
shadow_encoder_uninit_nsc(encoder);
|
||||
|
||||
shadow_encoder_uninit_planar(encoder);
|
||||
|
||||
shadow_encoder_uninit_interleaved(encoder);
|
||||
shadow_encoder_uninit_h264(encoder);
|
||||
|
||||
shadow_encoder_uninit_progressive(encoder);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int shadow_encoder_reset(rdpShadowEncoder* encoder)
|
||||
{
|
||||
int status = 0;
|
||||
UINT32 codecs = encoder->codecs;
|
||||
rdpContext* context = (rdpContext*)encoder->client;
|
||||
rdpSettings* settings = context->settings;
|
||||
status = shadow_encoder_uninit(encoder);
|
||||
|
||||
if (status < 0)
|
||||
return -1;
|
||||
|
||||
status = shadow_encoder_init(encoder);
|
||||
|
||||
if (status < 0)
|
||||
return -1;
|
||||
|
||||
status = shadow_encoder_prepare(encoder, codecs);
|
||||
|
||||
if (status < 0)
|
||||
return -1;
|
||||
|
||||
encoder->fps = 16;
|
||||
encoder->maxFps = 32;
|
||||
encoder->frameId = 0;
|
||||
encoder->lastAckframeId = 0;
|
||||
encoder->frameAck = freerdp_settings_get_bool(settings, FreeRDP_SurfaceFrameMarkerEnabled);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int shadow_encoder_prepare(rdpShadowEncoder* encoder, UINT32 codecs)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
if ((codecs & FREERDP_CODEC_REMOTEFX) && !(encoder->codecs & FREERDP_CODEC_REMOTEFX))
|
||||
{
|
||||
WLog_DBG(TAG, "initializing RemoteFX encoder");
|
||||
status = shadow_encoder_init_rfx(encoder);
|
||||
|
||||
if (status < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((codecs & FREERDP_CODEC_NSCODEC) && !(encoder->codecs & FREERDP_CODEC_NSCODEC))
|
||||
{
|
||||
WLog_DBG(TAG, "initializing NSCodec encoder");
|
||||
status = shadow_encoder_init_nsc(encoder);
|
||||
|
||||
if (status < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((codecs & FREERDP_CODEC_PLANAR) && !(encoder->codecs & FREERDP_CODEC_PLANAR))
|
||||
{
|
||||
WLog_DBG(TAG, "initializing planar bitmap encoder");
|
||||
status = shadow_encoder_init_planar(encoder);
|
||||
|
||||
if (status < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((codecs & FREERDP_CODEC_INTERLEAVED) && !(encoder->codecs & FREERDP_CODEC_INTERLEAVED))
|
||||
{
|
||||
WLog_DBG(TAG, "initializing interleaved bitmap encoder");
|
||||
status = shadow_encoder_init_interleaved(encoder);
|
||||
|
||||
if (status < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((codecs & (FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444)) &&
|
||||
!(encoder->codecs & (FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444)))
|
||||
{
|
||||
WLog_DBG(TAG, "initializing H.264 encoder");
|
||||
status = shadow_encoder_init_h264(encoder);
|
||||
|
||||
if (status < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((codecs & FREERDP_CODEC_PROGRESSIVE) && !(encoder->codecs & FREERDP_CODEC_PROGRESSIVE))
|
||||
{
|
||||
WLog_DBG(TAG, "initializing progressive encoder");
|
||||
status = shadow_encoder_init_progressive(encoder);
|
||||
|
||||
if (status < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
rdpShadowEncoder* shadow_encoder_new(rdpShadowClient* client)
|
||||
{
|
||||
rdpShadowEncoder* encoder = nullptr;
|
||||
rdpShadowServer* server = client->server;
|
||||
encoder = (rdpShadowEncoder*)calloc(1, sizeof(rdpShadowEncoder));
|
||||
|
||||
if (!encoder)
|
||||
return nullptr;
|
||||
|
||||
encoder->client = client;
|
||||
encoder->server = server;
|
||||
encoder->fps = 16;
|
||||
encoder->maxFps = 32;
|
||||
|
||||
if (shadow_encoder_init(encoder) < 0)
|
||||
{
|
||||
shadow_encoder_free(encoder);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return encoder;
|
||||
}
|
||||
|
||||
void shadow_encoder_free(rdpShadowEncoder* encoder)
|
||||
{
|
||||
if (!encoder)
|
||||
return;
|
||||
|
||||
shadow_encoder_uninit(encoder);
|
||||
free(encoder);
|
||||
}
|
||||
82
third_party/FreeRDP/server/shadow/shadow_encoder.h
vendored
Normal file
82
third_party/FreeRDP/server/shadow/shadow_encoder.h
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_SHADOW_ENCODER_H
|
||||
#define FREERDP_SERVER_SHADOW_ENCODER_H
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/codecs.h>
|
||||
|
||||
#include <freerdp/server/shadow.h>
|
||||
|
||||
struct rdp_shadow_encoder
|
||||
{
|
||||
rdpShadowClient* client;
|
||||
rdpShadowServer* server;
|
||||
|
||||
UINT32 width;
|
||||
UINT32 height;
|
||||
UINT32 codecs;
|
||||
|
||||
BYTE** grid;
|
||||
UINT32 gridWidth;
|
||||
UINT32 gridHeight;
|
||||
BYTE* gridBuffer;
|
||||
UINT32 maxTileWidth;
|
||||
UINT32 maxTileHeight;
|
||||
|
||||
wStream* bs;
|
||||
|
||||
RFX_CONTEXT* rfx;
|
||||
NSC_CONTEXT* nsc;
|
||||
BITMAP_PLANAR_CONTEXT* planar;
|
||||
BITMAP_INTERLEAVED_CONTEXT* interleaved;
|
||||
H264_CONTEXT* h264;
|
||||
PROGRESSIVE_CONTEXT* progressive;
|
||||
|
||||
UINT32 fps;
|
||||
UINT32 maxFps;
|
||||
BOOL frameAck;
|
||||
UINT32 frameId;
|
||||
UINT32 lastAckframeId;
|
||||
UINT32 queueDepth;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
WINPR_ATTR_NODISCARD int shadow_encoder_reset(rdpShadowEncoder* encoder);
|
||||
WINPR_ATTR_NODISCARD int shadow_encoder_prepare(rdpShadowEncoder* encoder, UINT32 codecs);
|
||||
WINPR_ATTR_NODISCARD UINT32 shadow_encoder_create_frame_id(rdpShadowEncoder* encoder);
|
||||
|
||||
void shadow_encoder_free(rdpShadowEncoder* encoder);
|
||||
|
||||
WINPR_ATTR_MALLOC(shadow_encoder_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
rdpShadowEncoder* shadow_encoder_new(rdpShadowClient* client);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_SERVER_SHADOW_ENCODER_H */
|
||||
138
third_party/FreeRDP/server/shadow/shadow_encomsp.c
vendored
Normal file
138
third_party/FreeRDP/server/shadow/shadow_encomsp.c
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2015 Thincast Technologies GmbH
|
||||
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#include "shadow.h"
|
||||
|
||||
#include "shadow_encomsp.h"
|
||||
|
||||
#define TAG SERVER_TAG("shadow")
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
WINPR_ATTR_NODISCARD
|
||||
static UINT
|
||||
encomsp_change_participant_control_level(EncomspServerContext* context,
|
||||
ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU* pdu)
|
||||
{
|
||||
BOOL inLobby = 0;
|
||||
BOOL mayView = 0;
|
||||
BOOL mayInteract = 0;
|
||||
rdpShadowClient* client = (rdpShadowClient*)context->custom;
|
||||
|
||||
WLog_INFO(TAG,
|
||||
"ChangeParticipantControlLevel: ParticipantId: %" PRIu32 " Flags: 0x%04" PRIX16 "",
|
||||
pdu->ParticipantId, pdu->Flags);
|
||||
|
||||
mayView = (pdu->Flags & ENCOMSP_MAY_VIEW) != 0;
|
||||
mayInteract = (pdu->Flags & ENCOMSP_MAY_INTERACT) != 0;
|
||||
|
||||
if (mayInteract && !mayView)
|
||||
mayView = TRUE; /* may interact implies may view */
|
||||
|
||||
if (mayInteract)
|
||||
{
|
||||
if (!client->mayInteract)
|
||||
{
|
||||
/* request interact + view */
|
||||
client->mayInteract = TRUE;
|
||||
client->mayView = TRUE;
|
||||
}
|
||||
}
|
||||
else if (mayView)
|
||||
{
|
||||
if (client->mayInteract)
|
||||
{
|
||||
/* release interact */
|
||||
client->mayInteract = FALSE;
|
||||
}
|
||||
else if (!client->mayView)
|
||||
{
|
||||
/* request view */
|
||||
client->mayView = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (client->mayInteract)
|
||||
{
|
||||
/* release interact + view */
|
||||
client->mayView = FALSE;
|
||||
client->mayInteract = FALSE;
|
||||
}
|
||||
else if (client->mayView)
|
||||
{
|
||||
/* release view */
|
||||
client->mayView = FALSE;
|
||||
client->mayInteract = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
inLobby = !(client->mayView);
|
||||
|
||||
if (inLobby != client->inLobby)
|
||||
{
|
||||
if (shadow_encoder_reset(client->encoder) < 0)
|
||||
return ERROR_NOT_READY;
|
||||
client->inLobby = inLobby;
|
||||
}
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
int shadow_client_encomsp_init(rdpShadowClient* client)
|
||||
{
|
||||
WINPR_ASSERT(client);
|
||||
|
||||
EncomspServerContext* encomsp = client->encomsp = encomsp_server_context_new(client->vcm);
|
||||
if (!encomsp)
|
||||
return -1;
|
||||
|
||||
encomsp->rdpcontext = &client->context;
|
||||
|
||||
encomsp->custom = (void*)client;
|
||||
|
||||
encomsp->ChangeParticipantControlLevel = encomsp_change_participant_control_level;
|
||||
|
||||
if (client->encomsp)
|
||||
{
|
||||
const UINT rc = client->encomsp->Start(client->encomsp);
|
||||
if (rc != CHANNEL_RC_OK)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void shadow_client_encomsp_uninit(rdpShadowClient* client)
|
||||
{
|
||||
WINPR_ASSERT(client);
|
||||
if (client->encomsp)
|
||||
{
|
||||
client->encomsp->Stop(client->encomsp);
|
||||
encomsp_server_context_free(client->encomsp);
|
||||
client->encomsp = nullptr;
|
||||
}
|
||||
}
|
||||
39
third_party/FreeRDP/server/shadow/shadow_encomsp.h
vendored
Normal file
39
third_party/FreeRDP/server/shadow/shadow_encomsp.h
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_SHADOW_ENCOMSP_H
|
||||
#define FREERDP_SERVER_SHADOW_ENCOMSP_H
|
||||
|
||||
#include <freerdp/server/shadow.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
WINPR_ATTR_NODISCARD int shadow_client_encomsp_init(rdpShadowClient* client);
|
||||
void shadow_client_encomsp_uninit(rdpShadowClient* client);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_SERVER_SHADOW_ENCOMSP_H */
|
||||
178
third_party/FreeRDP/server/shadow/shadow_input.c
vendored
Normal file
178
third_party/FreeRDP/server/shadow/shadow_input.c
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <winpr/assert.h>
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#include "shadow.h"
|
||||
|
||||
#define TAG SERVER_TAG("shadow.input")
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static BOOL shadow_input_synchronize_event(rdpInput* input, UINT32 flags)
|
||||
{
|
||||
WINPR_ASSERT(input);
|
||||
rdpShadowClient* client = (rdpShadowClient*)input->context;
|
||||
WINPR_ASSERT(client);
|
||||
WINPR_ASSERT(client->server);
|
||||
rdpShadowSubsystem* subsystem = client->server->subsystem;
|
||||
WINPR_ASSERT(subsystem);
|
||||
|
||||
WLog_DBG(TAG, "[%s] flags=0x%04" PRIx16, client->mayInteract ? "use" : "discard", flags);
|
||||
if (!client->mayInteract)
|
||||
return TRUE;
|
||||
|
||||
return IFCALLRESULT(TRUE, subsystem->SynchronizeEvent, subsystem, client, flags);
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static BOOL shadow_input_keyboard_event(rdpInput* input, UINT16 flags, UINT8 code)
|
||||
{
|
||||
WINPR_ASSERT(input);
|
||||
rdpShadowClient* client = (rdpShadowClient*)input->context;
|
||||
WINPR_ASSERT(client);
|
||||
WINPR_ASSERT(client->server);
|
||||
rdpShadowSubsystem* subsystem = client->server->subsystem;
|
||||
WINPR_ASSERT(subsystem);
|
||||
|
||||
WLog_DBG(TAG, "[%s] flags=0x%04" PRIx16, client->mayInteract ? "use" : "discard", flags);
|
||||
if (!client->mayInteract)
|
||||
return TRUE;
|
||||
|
||||
return IFCALLRESULT(TRUE, subsystem->KeyboardEvent, subsystem, client, flags, code);
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static BOOL shadow_input_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
|
||||
{
|
||||
WINPR_ASSERT(input);
|
||||
rdpShadowClient* client = (rdpShadowClient*)input->context;
|
||||
WINPR_ASSERT(client);
|
||||
WINPR_ASSERT(client->server);
|
||||
rdpShadowSubsystem* subsystem = client->server->subsystem;
|
||||
WINPR_ASSERT(subsystem);
|
||||
|
||||
WLog_DBG(TAG, "[%s] flags=0x%04" PRIx16, client->mayInteract ? "use" : "discard", flags);
|
||||
if (!client->mayInteract)
|
||||
return TRUE;
|
||||
|
||||
return IFCALLRESULT(TRUE, subsystem->UnicodeKeyboardEvent, subsystem, client, flags, code);
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static BOOL shadow_input_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
|
||||
{
|
||||
WINPR_ASSERT(input);
|
||||
rdpShadowClient* client = (rdpShadowClient*)input->context;
|
||||
WINPR_ASSERT(client);
|
||||
WINPR_ASSERT(client->server);
|
||||
rdpShadowSubsystem* subsystem = client->server->subsystem;
|
||||
WINPR_ASSERT(subsystem);
|
||||
|
||||
if (client->server->shareSubRect)
|
||||
{
|
||||
x += client->server->subRect.left;
|
||||
y += client->server->subRect.top;
|
||||
}
|
||||
|
||||
if ((flags & (PTR_FLAGS_WHEEL | PTR_FLAGS_HWHEEL | PTR_FLAGS_WHEEL_NEGATIVE)) == 0)
|
||||
{
|
||||
client->pointerX = x;
|
||||
client->pointerY = y;
|
||||
|
||||
if ((client->pointerX == subsystem->pointerX) && (client->pointerY == subsystem->pointerY))
|
||||
{
|
||||
flags &= ~PTR_FLAGS_MOVE;
|
||||
|
||||
if (!(flags & (PTR_FLAGS_BUTTON1 | PTR_FLAGS_BUTTON2 | PTR_FLAGS_BUTTON3)))
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
WLog_DBG(TAG, "[%s] flags=0x%04" PRIx16 ", x=%" PRIu16 ", y=%" PRIu16,
|
||||
client->mayInteract ? "use" : "discard", flags, x, y);
|
||||
if (!client->mayInteract)
|
||||
return TRUE;
|
||||
|
||||
return IFCALLRESULT(TRUE, subsystem->MouseEvent, subsystem, client, flags, x, y);
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static BOOL shadow_input_rel_mouse_event(rdpInput* input, UINT16 flags, INT16 xDelta, INT16 yDelta)
|
||||
{
|
||||
WINPR_ASSERT(input);
|
||||
|
||||
rdpShadowClient* client = (rdpShadowClient*)input->context;
|
||||
WINPR_ASSERT(client);
|
||||
WINPR_ASSERT(client->server);
|
||||
|
||||
rdpShadowSubsystem* subsystem = client->server->subsystem;
|
||||
WINPR_ASSERT(subsystem);
|
||||
|
||||
WLog_DBG(TAG, "[%s] flags=0x%04" PRIx16 ", x=%" PRId16 ", y=%" PRId16,
|
||||
client->mayInteract ? "use" : "discard", flags, xDelta, yDelta);
|
||||
const uint16_t mask = PTR_FLAGS_MOVE | PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1 | PTR_FLAGS_BUTTON2 |
|
||||
PTR_FLAGS_BUTTON3 | PTR_XFLAGS_BUTTON1 | PTR_XFLAGS_BUTTON2;
|
||||
if ((flags & mask) != 0)
|
||||
{
|
||||
WLog_WARN(TAG, "Unknown flags 0x%04x", WINPR_CXX_COMPAT_CAST(unsigned, flags & ~mask));
|
||||
}
|
||||
if (!client->mayInteract)
|
||||
return TRUE;
|
||||
|
||||
return IFCALLRESULT(TRUE, subsystem->RelMouseEvent, subsystem, client, flags, xDelta, yDelta);
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static BOOL shadow_input_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
|
||||
{
|
||||
WINPR_ASSERT(input);
|
||||
rdpShadowClient* client = (rdpShadowClient*)input->context;
|
||||
WINPR_ASSERT(client);
|
||||
WINPR_ASSERT(client->server);
|
||||
rdpShadowSubsystem* subsystem = client->server->subsystem;
|
||||
WINPR_ASSERT(subsystem);
|
||||
|
||||
if (client->server->shareSubRect)
|
||||
{
|
||||
x += client->server->subRect.left;
|
||||
y += client->server->subRect.top;
|
||||
}
|
||||
|
||||
client->pointerX = x;
|
||||
client->pointerY = y;
|
||||
|
||||
WLog_DBG(TAG, "[%s] flags=0x%04" PRIx16 ", x=%" PRIu16 ", y=%" PRIu16,
|
||||
client->mayInteract ? "use" : "discard", flags, x, y);
|
||||
if (!client->mayInteract)
|
||||
return TRUE;
|
||||
|
||||
return IFCALLRESULT(TRUE, subsystem->ExtendedMouseEvent, subsystem, client, flags, x, y);
|
||||
}
|
||||
|
||||
void shadow_input_register_callbacks(rdpInput* input)
|
||||
{
|
||||
WINPR_ASSERT(input);
|
||||
input->SynchronizeEvent = shadow_input_synchronize_event;
|
||||
input->KeyboardEvent = shadow_input_keyboard_event;
|
||||
input->UnicodeKeyboardEvent = shadow_input_unicode_keyboard_event;
|
||||
input->MouseEvent = shadow_input_mouse_event;
|
||||
input->ExtendedMouseEvent = shadow_input_extended_mouse_event;
|
||||
input->RelMouseEvent = shadow_input_rel_mouse_event;
|
||||
}
|
||||
35
third_party/FreeRDP/server/shadow/shadow_input.h
vendored
Normal file
35
third_party/FreeRDP/server/shadow/shadow_input.h
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_SHADOW_INPUT_H
|
||||
#define FREERDP_SERVER_SHADOW_INPUT_H
|
||||
|
||||
#include <freerdp/server/shadow.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void shadow_input_register_callbacks(rdpInput* input);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_SERVER_SHADOW_INPUT_H */
|
||||
101
third_party/FreeRDP/server/shadow/shadow_lobby.c
vendored
Normal file
101
third_party/FreeRDP/server/shadow/shadow_lobby.c
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/cast.h>
|
||||
|
||||
#if defined(WITH_RDTK)
|
||||
#include <rdtk/rdtk.h>
|
||||
#endif
|
||||
|
||||
#include "shadow.h"
|
||||
|
||||
#include "shadow_lobby.h"
|
||||
|
||||
BOOL shadow_client_init_lobby(rdpShadowServer* server)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
RECTANGLE_16 invalidRect = WINPR_C_ARRAY_INIT;
|
||||
|
||||
WINPR_ASSERT(server);
|
||||
rdpShadowSurface* lobby = server->lobby;
|
||||
|
||||
if (!lobby)
|
||||
return FALSE;
|
||||
|
||||
#if defined(WITH_RDTK)
|
||||
rdtkEngine* engine = rdtk_engine_new();
|
||||
if (!engine)
|
||||
return FALSE;
|
||||
|
||||
EnterCriticalSection(&lobby->lock);
|
||||
rdtkSurface* surface =
|
||||
rdtk_surface_new(engine, lobby->data, WINPR_ASSERTING_INT_CAST(uint16_t, lobby->width),
|
||||
WINPR_ASSERTING_INT_CAST(uint16_t, lobby->height), lobby->scanline);
|
||||
if (!surface)
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
invalidRect.left = 0;
|
||||
invalidRect.top = 0;
|
||||
WINPR_ASSERT(lobby->width <= UINT16_MAX);
|
||||
WINPR_ASSERT(lobby->height <= UINT16_MAX);
|
||||
invalidRect.right = (UINT16)lobby->width;
|
||||
invalidRect.bottom = (UINT16)lobby->height;
|
||||
if (server->shareSubRect)
|
||||
{
|
||||
/* If we have shared sub rect setting, only fill shared rect */
|
||||
if (!rectangles_intersection(&invalidRect, &(server->subRect), &invalidRect))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#if defined(WITH_RDTK)
|
||||
const int width = invalidRect.right - invalidRect.left;
|
||||
const int height = invalidRect.bottom - invalidRect.top;
|
||||
WINPR_ASSERT(width <= UINT16_MAX);
|
||||
WINPR_ASSERT(width >= 0);
|
||||
WINPR_ASSERT(height <= UINT16_MAX);
|
||||
WINPR_ASSERT(height >= 0);
|
||||
|
||||
if (rdtk_surface_fill(surface, invalidRect.left, invalidRect.top, (UINT16)width, (UINT16)height,
|
||||
0x3BB9FF) < 0)
|
||||
goto fail;
|
||||
|
||||
if (rdtk_label_draw(surface, invalidRect.left, invalidRect.top, (UINT16)width, (UINT16)height,
|
||||
nullptr, "Welcome", 0, 0) < 0)
|
||||
goto fail;
|
||||
// rdtk_button_draw(surface, 16, 64, 128, 32, nullptr, "button");
|
||||
// rdtk_text_field_draw(surface, 16, 128, 128, 32, nullptr, "text field");
|
||||
#endif
|
||||
|
||||
if (!region16_union_rect(&(lobby->invalidRegion), &(lobby->invalidRegion), &invalidRect))
|
||||
goto fail;
|
||||
|
||||
rc = TRUE;
|
||||
fail:
|
||||
|
||||
#if defined(WITH_RDTK)
|
||||
rdtk_surface_free(surface);
|
||||
rdtk_engine_free(engine);
|
||||
#endif
|
||||
|
||||
LeaveCriticalSection(&lobby->lock);
|
||||
return rc;
|
||||
}
|
||||
38
third_party/FreeRDP/server/shadow/shadow_lobby.h
vendored
Normal file
38
third_party/FreeRDP/server/shadow/shadow_lobby.h
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_SHADOW_LOBBY_H
|
||||
#define FREERDP_SERVER_SHADOW_LOBBY_H
|
||||
|
||||
#include <freerdp/server/shadow.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
WINPR_ATTR_NODISCARD BOOL shadow_client_init_lobby(rdpShadowServer* server);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_SERVER_SHADOW_LOBBY_H */
|
||||
341
third_party/FreeRDP/server/shadow/shadow_mcevent.c
vendored
Normal file
341
third_party/FreeRDP/server/shadow/shadow_mcevent.c
vendored
Normal file
@@ -0,0 +1,341 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2015 Jiang Zihao <zihao.jiang@yahoo.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <winpr/assert.h>
|
||||
#include <freerdp/log.h>
|
||||
#include "shadow.h"
|
||||
|
||||
#define TAG SERVER_TAG("shadow.mcevent")
|
||||
|
||||
struct rdp_shadow_multiclient_event
|
||||
{
|
||||
HANDLE event; /* Kickoff event */
|
||||
HANDLE barrierEvent; /* Represents that all clients have consumed event */
|
||||
HANDLE doneEvent; /* Event handling finished. Server could continue */
|
||||
wArrayList* subscribers;
|
||||
CRITICAL_SECTION lock;
|
||||
int consuming;
|
||||
int waiting;
|
||||
|
||||
/* For debug */
|
||||
int eventid;
|
||||
};
|
||||
|
||||
struct rdp_shadow_multiclient_subscriber
|
||||
{
|
||||
rdpShadowMultiClientEvent* ref;
|
||||
BOOL pleaseHandle; /* Indicate if server expects my handling in this turn */
|
||||
};
|
||||
|
||||
rdpShadowMultiClientEvent* shadow_multiclient_new(void)
|
||||
{
|
||||
rdpShadowMultiClientEvent* event =
|
||||
(rdpShadowMultiClientEvent*)calloc(1, sizeof(rdpShadowMultiClientEvent));
|
||||
if (!event)
|
||||
goto out_error;
|
||||
|
||||
event->event = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||
if (!event->event)
|
||||
goto out_free;
|
||||
|
||||
event->barrierEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||
if (!event->barrierEvent)
|
||||
goto out_free_event;
|
||||
|
||||
event->doneEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||
if (!event->doneEvent)
|
||||
goto out_free_barrierEvent;
|
||||
|
||||
event->subscribers = ArrayList_New(TRUE);
|
||||
if (!event->subscribers)
|
||||
goto out_free_doneEvent;
|
||||
|
||||
if (!InitializeCriticalSectionAndSpinCount(&(event->lock), 4000))
|
||||
goto out_free_subscribers;
|
||||
|
||||
event->consuming = 0;
|
||||
event->waiting = 0;
|
||||
event->eventid = 0;
|
||||
(void)SetEvent(event->doneEvent);
|
||||
return event;
|
||||
|
||||
out_free_subscribers:
|
||||
ArrayList_Free(event->subscribers);
|
||||
out_free_doneEvent:
|
||||
(void)CloseHandle(event->doneEvent);
|
||||
out_free_barrierEvent:
|
||||
(void)CloseHandle(event->barrierEvent);
|
||||
out_free_event:
|
||||
(void)CloseHandle(event->event);
|
||||
out_free:
|
||||
free(event);
|
||||
out_error:
|
||||
return (rdpShadowMultiClientEvent*)nullptr;
|
||||
}
|
||||
|
||||
void shadow_multiclient_free(rdpShadowMultiClientEvent* event)
|
||||
{
|
||||
if (!event)
|
||||
return;
|
||||
|
||||
DeleteCriticalSection(&(event->lock));
|
||||
|
||||
ArrayList_Free(event->subscribers);
|
||||
(void)CloseHandle(event->doneEvent);
|
||||
(void)CloseHandle(event->barrierEvent);
|
||||
(void)CloseHandle(event->event);
|
||||
free(event);
|
||||
}
|
||||
|
||||
static void Publish(rdpShadowMultiClientEvent* event)
|
||||
{
|
||||
wArrayList* subscribers = nullptr;
|
||||
struct rdp_shadow_multiclient_subscriber* subscriber = nullptr;
|
||||
|
||||
subscribers = event->subscribers;
|
||||
|
||||
WINPR_ASSERT(event->consuming == 0);
|
||||
|
||||
/* Count subscribing clients */
|
||||
ArrayList_Lock(subscribers);
|
||||
for (size_t i = 0; i < ArrayList_Count(subscribers); i++)
|
||||
{
|
||||
subscriber = (struct rdp_shadow_multiclient_subscriber*)ArrayList_GetItem(subscribers, i);
|
||||
/* Set flag to subscriber: I acknowledge and please handle */
|
||||
subscriber->pleaseHandle = TRUE;
|
||||
event->consuming++;
|
||||
}
|
||||
ArrayList_Unlock(subscribers);
|
||||
|
||||
if (event->consuming > 0)
|
||||
{
|
||||
event->eventid = (event->eventid & 0xff) + 1;
|
||||
WLog_VRB(TAG, "Server published event %d. %d clients.\n", event->eventid, event->consuming);
|
||||
(void)ResetEvent(event->doneEvent);
|
||||
(void)SetEvent(event->event);
|
||||
}
|
||||
}
|
||||
|
||||
static void WaitForSubscribers(rdpShadowMultiClientEvent* event)
|
||||
{
|
||||
if (event->consuming > 0)
|
||||
{
|
||||
/* Wait for clients done */
|
||||
WLog_VRB(TAG, "Server wait event %d. %d clients.\n", event->eventid, event->consuming);
|
||||
LeaveCriticalSection(&(event->lock));
|
||||
(void)WaitForSingleObject(event->doneEvent, INFINITE);
|
||||
EnterCriticalSection(&(event->lock));
|
||||
WLog_VRB(TAG, "Server quit event %d. %d clients.\n", event->eventid, event->consuming);
|
||||
}
|
||||
|
||||
/* Last subscriber should have already reset the event */
|
||||
WINPR_ASSERT(WaitForSingleObject(event->event, 0) != WAIT_OBJECT_0);
|
||||
}
|
||||
|
||||
void shadow_multiclient_publish(rdpShadowMultiClientEvent* event)
|
||||
{
|
||||
if (!event)
|
||||
return;
|
||||
|
||||
EnterCriticalSection(&(event->lock));
|
||||
Publish(event);
|
||||
LeaveCriticalSection(&(event->lock));
|
||||
}
|
||||
void shadow_multiclient_wait(rdpShadowMultiClientEvent* event)
|
||||
{
|
||||
if (!event)
|
||||
return;
|
||||
|
||||
EnterCriticalSection(&(event->lock));
|
||||
WaitForSubscribers(event);
|
||||
LeaveCriticalSection(&(event->lock));
|
||||
}
|
||||
void shadow_multiclient_publish_and_wait(rdpShadowMultiClientEvent* event)
|
||||
{
|
||||
if (!event)
|
||||
return;
|
||||
|
||||
EnterCriticalSection(&(event->lock));
|
||||
Publish(event);
|
||||
WaitForSubscribers(event);
|
||||
LeaveCriticalSection(&(event->lock));
|
||||
}
|
||||
|
||||
static BOOL Consume(struct rdp_shadow_multiclient_subscriber* subscriber, BOOL wait)
|
||||
{
|
||||
rdpShadowMultiClientEvent* event = subscriber->ref;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
if (WaitForSingleObject(event->event, 0) == WAIT_OBJECT_0 && subscriber->pleaseHandle)
|
||||
{
|
||||
/* Consume my share. Server is waiting for us */
|
||||
event->consuming--;
|
||||
ret = TRUE;
|
||||
}
|
||||
|
||||
WINPR_ASSERT(event->consuming >= 0);
|
||||
|
||||
if (event->consuming == 0)
|
||||
{
|
||||
/* Last client reset event before notify clients to continue */
|
||||
(void)ResetEvent(event->event);
|
||||
|
||||
if (event->waiting > 0)
|
||||
{
|
||||
/* Notify other clients to continue */
|
||||
(void)SetEvent(event->barrierEvent);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Only one client. Notify server directly */
|
||||
(void)SetEvent(event->doneEvent);
|
||||
}
|
||||
}
|
||||
else /* (event->consuming > 0) */
|
||||
{
|
||||
if (wait)
|
||||
{
|
||||
/*
|
||||
* This client need to wait. That means the client will
|
||||
* continue waiting for other clients to finish.
|
||||
* The last client should reset barrierEvent.
|
||||
*/
|
||||
event->waiting++;
|
||||
LeaveCriticalSection(&(event->lock));
|
||||
(void)WaitForSingleObject(event->barrierEvent, INFINITE);
|
||||
EnterCriticalSection(&(event->lock));
|
||||
event->waiting--;
|
||||
if (event->waiting == 0)
|
||||
{
|
||||
/*
|
||||
* This is last client waiting for barrierEvent.
|
||||
* We can now discard barrierEvent and notify
|
||||
* server to continue.
|
||||
*/
|
||||
(void)ResetEvent(event->barrierEvent);
|
||||
(void)SetEvent(event->doneEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void* shadow_multiclient_get_subscriber(rdpShadowMultiClientEvent* event)
|
||||
{
|
||||
struct rdp_shadow_multiclient_subscriber* subscriber = nullptr;
|
||||
|
||||
if (!event)
|
||||
return nullptr;
|
||||
|
||||
EnterCriticalSection(&(event->lock));
|
||||
|
||||
subscriber = (struct rdp_shadow_multiclient_subscriber*)calloc(
|
||||
1, sizeof(struct rdp_shadow_multiclient_subscriber));
|
||||
if (!subscriber)
|
||||
goto out_error;
|
||||
|
||||
subscriber->ref = event;
|
||||
subscriber->pleaseHandle = FALSE;
|
||||
|
||||
if (!ArrayList_Append(event->subscribers, subscriber))
|
||||
goto out_free;
|
||||
|
||||
WLog_VRB(TAG, "Get subscriber %p. Wait event %d. %d clients.\n", (void*)subscriber,
|
||||
event->eventid, event->consuming);
|
||||
(void)Consume(subscriber, TRUE);
|
||||
WLog_VRB(TAG, "Get subscriber %p. Quit event %d. %d clients.\n", (void*)subscriber,
|
||||
event->eventid, event->consuming);
|
||||
|
||||
LeaveCriticalSection(&(event->lock));
|
||||
|
||||
return subscriber;
|
||||
|
||||
out_free:
|
||||
free(subscriber);
|
||||
out_error:
|
||||
LeaveCriticalSection(&(event->lock));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Consume my share and release my register
|
||||
* If we have update event and pleaseHandle flag
|
||||
* We need to consume. Anyway we need to clear
|
||||
* pleaseHandle flag
|
||||
*/
|
||||
void shadow_multiclient_release_subscriber(void* subscriber)
|
||||
{
|
||||
struct rdp_shadow_multiclient_subscriber* s = nullptr;
|
||||
rdpShadowMultiClientEvent* event = nullptr;
|
||||
|
||||
if (!subscriber)
|
||||
return;
|
||||
|
||||
s = (struct rdp_shadow_multiclient_subscriber*)subscriber;
|
||||
event = s->ref;
|
||||
|
||||
EnterCriticalSection(&(event->lock));
|
||||
|
||||
WLog_VRB(TAG, "Release Subscriber %p. Drop event %d. %d clients.\n", subscriber, event->eventid,
|
||||
event->consuming);
|
||||
(void)Consume(s, FALSE);
|
||||
WLog_VRB(TAG, "Release Subscriber %p. Quit event %d. %d clients.\n", subscriber, event->eventid,
|
||||
event->consuming);
|
||||
|
||||
ArrayList_Remove(event->subscribers, subscriber);
|
||||
|
||||
LeaveCriticalSection(&(event->lock));
|
||||
|
||||
free(subscriber);
|
||||
}
|
||||
|
||||
BOOL shadow_multiclient_consume(void* subscriber)
|
||||
{
|
||||
struct rdp_shadow_multiclient_subscriber* s = nullptr;
|
||||
rdpShadowMultiClientEvent* event = nullptr;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
if (!subscriber)
|
||||
return ret;
|
||||
|
||||
s = (struct rdp_shadow_multiclient_subscriber*)subscriber;
|
||||
event = s->ref;
|
||||
|
||||
EnterCriticalSection(&(event->lock));
|
||||
|
||||
WLog_VRB(TAG, "Subscriber %p wait event %d. %d clients.\n", subscriber, event->eventid,
|
||||
event->consuming);
|
||||
ret = Consume(s, TRUE);
|
||||
WLog_VRB(TAG, "Subscriber %p quit event %d. %d clients.\n", subscriber, event->eventid,
|
||||
event->consuming);
|
||||
|
||||
LeaveCriticalSection(&(event->lock));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
HANDLE shadow_multiclient_getevent(void* subscriber)
|
||||
{
|
||||
if (!subscriber)
|
||||
return (HANDLE) nullptr;
|
||||
|
||||
return ((struct rdp_shadow_multiclient_subscriber*)subscriber)->ref->event;
|
||||
}
|
||||
57
third_party/FreeRDP/server/shadow/shadow_mcevent.h
vendored
Normal file
57
third_party/FreeRDP/server/shadow/shadow_mcevent.h
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2015 Jiang Zihao <zihao.jiang@yahoo.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_SHADOW_MCEVENT_H
|
||||
#define FREERDP_SERVER_SHADOW_MCEVENT_H
|
||||
|
||||
#include <freerdp/server/shadow.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/collections.h>
|
||||
|
||||
/*
|
||||
* This file implemented a model that an event is consumed
|
||||
* by multiple clients. All clients should wait others before continue
|
||||
* Server should wait for all clients before continue
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void shadow_multiclient_free(rdpShadowMultiClientEvent* event);
|
||||
|
||||
WINPR_ATTR_MALLOC(shadow_multiclient_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
rdpShadowMultiClientEvent* shadow_multiclient_new(void);
|
||||
|
||||
void shadow_multiclient_publish(rdpShadowMultiClientEvent* event);
|
||||
void shadow_multiclient_wait(rdpShadowMultiClientEvent* event);
|
||||
void shadow_multiclient_publish_and_wait(rdpShadowMultiClientEvent* event);
|
||||
WINPR_ATTR_NODISCARD void* shadow_multiclient_get_subscriber(rdpShadowMultiClientEvent* event);
|
||||
void shadow_multiclient_release_subscriber(void* subscriber);
|
||||
BOOL shadow_multiclient_consume(void* subscriber);
|
||||
WINPR_ATTR_NODISCARD HANDLE shadow_multiclient_getevent(void* subscriber);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_SERVER_SHADOW_MCEVENT_H */
|
||||
59
third_party/FreeRDP/server/shadow/shadow_rdpgfx.c
vendored
Normal file
59
third_party/FreeRDP/server/shadow/shadow_rdpgfx.c
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2016 Jiang Zihao <zihao.jiang@yahoo.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#include "shadow.h"
|
||||
|
||||
#include "shadow_rdpgfx.h"
|
||||
|
||||
int shadow_client_rdpgfx_init(rdpShadowClient* client)
|
||||
{
|
||||
WINPR_ASSERT(client);
|
||||
|
||||
if (!freerdp_settings_get_bool(client->context.settings, FreeRDP_SupportGraphicsPipeline))
|
||||
return 1;
|
||||
|
||||
#if defined(CHANNEL_RDPGFX_SERVER)
|
||||
RdpgfxServerContext* rdpgfx = client->rdpgfx = rdpgfx_server_context_new(client->vcm);
|
||||
if (!rdpgfx)
|
||||
return 0;
|
||||
|
||||
rdpgfx->rdpcontext = &client->context;
|
||||
|
||||
rdpgfx->custom = client;
|
||||
|
||||
if (!IFCALLRESULT(CHANNEL_RC_OK, rdpgfx->Initialize, rdpgfx, TRUE))
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void shadow_client_rdpgfx_uninit(rdpShadowClient* client)
|
||||
{
|
||||
WINPR_ASSERT(client);
|
||||
if (client->rdpgfx)
|
||||
{
|
||||
#if defined(CHANNEL_RDPGFX_SERVER)
|
||||
rdpgfx_server_context_free(client->rdpgfx);
|
||||
#endif
|
||||
client->rdpgfx = nullptr;
|
||||
}
|
||||
}
|
||||
39
third_party/FreeRDP/server/shadow/shadow_rdpgfx.h
vendored
Normal file
39
third_party/FreeRDP/server/shadow/shadow_rdpgfx.h
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2016 Jiang Zihao <zihao.jiang@yahoo.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_SHADOW_RDPGFX_H
|
||||
#define FREERDP_SERVER_SHADOW_RDPGFX_H
|
||||
|
||||
#include <freerdp/server/shadow.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
WINPR_ATTR_NODISCARD int shadow_client_rdpgfx_init(rdpShadowClient* client);
|
||||
void shadow_client_rdpgfx_uninit(rdpShadowClient* client);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_SERVER_SHADOW_RDPGFX_H */
|
||||
97
third_party/FreeRDP/server/shadow/shadow_rdpsnd.c
vendored
Normal file
97
third_party/FreeRDP/server/shadow/shadow_rdpsnd.c
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2015 Jiang Zihao <zihao.jiang@yahoo.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/cast.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#include <freerdp/codec/dsp.h>
|
||||
#include <freerdp/server/server-common.h>
|
||||
|
||||
#include "shadow.h"
|
||||
|
||||
#include "shadow_rdpsnd.h"
|
||||
|
||||
#define TAG SERVER_TAG("shadow")
|
||||
|
||||
static void rdpsnd_activated(RdpsndServerContext* context)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
for (size_t i = 0; i < context->num_client_formats; i++)
|
||||
{
|
||||
for (size_t j = 0; j < context->num_server_formats; j++)
|
||||
{
|
||||
if (audio_format_compatible(&context->server_formats[j], &context->client_formats[i]))
|
||||
{
|
||||
const UINT rc = context->SelectFormat(context, WINPR_ASSERTING_INT_CAST(UINT16, i));
|
||||
if (rc != CHANNEL_RC_OK)
|
||||
WLog_WARN(TAG, "SelectFormat failed with %" PRIu32, rc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WLog_ERR(TAG, "Could not agree on a audio format with the server\n");
|
||||
}
|
||||
|
||||
int shadow_client_rdpsnd_init(rdpShadowClient* client)
|
||||
{
|
||||
WINPR_ASSERT(client);
|
||||
RdpsndServerContext* rdpsnd = client->rdpsnd = rdpsnd_server_context_new(client->vcm);
|
||||
|
||||
if (!rdpsnd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
rdpsnd->data = client;
|
||||
|
||||
if (client->subsystem->rdpsndFormats)
|
||||
{
|
||||
rdpsnd->server_formats = client->subsystem->rdpsndFormats;
|
||||
rdpsnd->num_server_formats = client->subsystem->nRdpsndFormats;
|
||||
}
|
||||
else
|
||||
{
|
||||
rdpsnd->num_server_formats = server_rdpsnd_get_formats(&rdpsnd->server_formats);
|
||||
}
|
||||
|
||||
if (rdpsnd->num_server_formats > 0)
|
||||
rdpsnd->src_format = &rdpsnd->server_formats[0];
|
||||
|
||||
rdpsnd->Activated = rdpsnd_activated;
|
||||
|
||||
const UINT error = rdpsnd->Initialize(rdpsnd, TRUE);
|
||||
if (error != CHANNEL_RC_OK)
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void shadow_client_rdpsnd_uninit(rdpShadowClient* client)
|
||||
{
|
||||
WINPR_ASSERT(client);
|
||||
if (client->rdpsnd)
|
||||
{
|
||||
client->rdpsnd->Stop(client->rdpsnd);
|
||||
rdpsnd_server_context_free(client->rdpsnd);
|
||||
client->rdpsnd = nullptr;
|
||||
}
|
||||
}
|
||||
39
third_party/FreeRDP/server/shadow/shadow_rdpsnd.h
vendored
Normal file
39
third_party/FreeRDP/server/shadow/shadow_rdpsnd.h
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2015 Jiang Zihao <zihao.jiang@yahoo.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_SHADOW_RDPSND_H
|
||||
#define FREERDP_SERVER_SHADOW_RDPSND_H
|
||||
|
||||
#include <freerdp/server/shadow.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
WINPR_ATTR_NODISCARD int shadow_client_rdpsnd_init(rdpShadowClient* client);
|
||||
void shadow_client_rdpsnd_uninit(rdpShadowClient* client);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_SERVER_SHADOW_RDPSND_H */
|
||||
57
third_party/FreeRDP/server/shadow/shadow_remdesk.c
vendored
Normal file
57
third_party/FreeRDP/server/shadow/shadow_remdesk.c
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2015 Thincast Technologies GmbH
|
||||
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include "shadow.h"
|
||||
|
||||
#include "shadow_remdesk.h"
|
||||
|
||||
int shadow_client_remdesk_init(rdpShadowClient* client)
|
||||
{
|
||||
WINPR_ASSERT(client);
|
||||
RemdeskServerContext* remdesk = client->remdesk = remdesk_server_context_new(client->vcm);
|
||||
if (!remdesk)
|
||||
return -1;
|
||||
|
||||
remdesk->rdpcontext = &client->context;
|
||||
|
||||
remdesk->custom = (void*)client;
|
||||
|
||||
if (client->remdesk)
|
||||
{
|
||||
const UINT rc = client->remdesk->Start(client->remdesk);
|
||||
if (rc != CHANNEL_RC_OK)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void shadow_client_remdesk_uninit(rdpShadowClient* client)
|
||||
{
|
||||
WINPR_ASSERT(client);
|
||||
if (client->remdesk)
|
||||
{
|
||||
client->remdesk->Stop(client->remdesk);
|
||||
remdesk_server_context_free(client->remdesk);
|
||||
client->remdesk = nullptr;
|
||||
}
|
||||
}
|
||||
39
third_party/FreeRDP/server/shadow/shadow_remdesk.h
vendored
Normal file
39
third_party/FreeRDP/server/shadow/shadow_remdesk.h
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_SHADOW_REMDESK_H
|
||||
#define FREERDP_SERVER_SHADOW_REMDESK_H
|
||||
|
||||
#include <freerdp/server/shadow.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
WINPR_ATTR_NODISCARD int shadow_client_remdesk_init(rdpShadowClient* client);
|
||||
void shadow_client_remdesk_uninit(rdpShadowClient* client);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_SERVER_SHADOW_REMDESK_H */
|
||||
168
third_party/FreeRDP/server/shadow/shadow_screen.c
vendored
Normal file
168
third_party/FreeRDP/server/shadow/shadow_screen.c
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#include "shadow_surface.h"
|
||||
|
||||
#include "shadow_screen.h"
|
||||
#include "shadow_lobby.h"
|
||||
|
||||
rdpShadowScreen* shadow_screen_new(rdpShadowServer* server)
|
||||
{
|
||||
WINPR_ASSERT(server);
|
||||
WINPR_ASSERT(server->subsystem);
|
||||
|
||||
rdpShadowScreen* screen = (rdpShadowScreen*)calloc(1, sizeof(rdpShadowScreen));
|
||||
|
||||
if (!screen)
|
||||
goto fail;
|
||||
|
||||
screen->server = server;
|
||||
|
||||
{
|
||||
rdpShadowSubsystem* subsystem = server->subsystem;
|
||||
if (!InitializeCriticalSectionAndSpinCount(&(screen->lock), 4000))
|
||||
goto fail;
|
||||
|
||||
region16_init(&(screen->invalidRegion));
|
||||
|
||||
{
|
||||
WINPR_ASSERT(subsystem->selectedMonitor < ARRAYSIZE(subsystem->monitors));
|
||||
const MONITOR_DEF* primary = &(subsystem->monitors[subsystem->selectedMonitor]);
|
||||
WINPR_ASSERT(primary);
|
||||
|
||||
const INT64 x = primary->left;
|
||||
const INT64 y = primary->top;
|
||||
const INT64 width = primary->right - primary->left + 1;
|
||||
const INT64 height = primary->bottom - primary->top + 1;
|
||||
|
||||
WINPR_ASSERT(x >= 0);
|
||||
WINPR_ASSERT(x <= UINT16_MAX);
|
||||
WINPR_ASSERT(y >= 0);
|
||||
WINPR_ASSERT(y <= UINT16_MAX);
|
||||
WINPR_ASSERT(width >= 0);
|
||||
WINPR_ASSERT(width <= UINT16_MAX);
|
||||
WINPR_ASSERT(height >= 0);
|
||||
WINPR_ASSERT(height <= UINT16_MAX);
|
||||
|
||||
screen->width = (UINT16)width;
|
||||
screen->height = (UINT16)height;
|
||||
|
||||
screen->primary =
|
||||
shadow_surface_new(server, (UINT16)x, (UINT16)y, (UINT16)width, (UINT16)height);
|
||||
|
||||
if (!screen->primary)
|
||||
goto fail;
|
||||
|
||||
server->surface = screen->primary;
|
||||
|
||||
screen->lobby =
|
||||
shadow_surface_new(server, (UINT16)x, (UINT16)y, (UINT16)width, (UINT16)height);
|
||||
}
|
||||
}
|
||||
|
||||
if (!screen->lobby)
|
||||
goto fail;
|
||||
|
||||
server->lobby = screen->lobby;
|
||||
|
||||
if (!shadow_client_init_lobby(server))
|
||||
goto fail;
|
||||
|
||||
return screen;
|
||||
|
||||
fail:
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
shadow_screen_free(screen);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void shadow_screen_free(rdpShadowScreen* screen)
|
||||
{
|
||||
if (!screen)
|
||||
return;
|
||||
|
||||
DeleteCriticalSection(&(screen->lock));
|
||||
|
||||
region16_uninit(&(screen->invalidRegion));
|
||||
|
||||
if (screen->primary)
|
||||
{
|
||||
shadow_surface_free(screen->primary);
|
||||
screen->primary = nullptr;
|
||||
}
|
||||
|
||||
if (screen->lobby)
|
||||
{
|
||||
shadow_surface_free(screen->lobby);
|
||||
screen->lobby = nullptr;
|
||||
}
|
||||
|
||||
free(screen);
|
||||
}
|
||||
|
||||
BOOL shadow_screen_resize(rdpShadowScreen* screen)
|
||||
{
|
||||
if (!screen)
|
||||
return FALSE;
|
||||
|
||||
WINPR_ASSERT(screen->server);
|
||||
|
||||
rdpShadowSubsystem* subsystem = screen->server->subsystem;
|
||||
WINPR_ASSERT(subsystem);
|
||||
WINPR_ASSERT(subsystem->monitors);
|
||||
|
||||
MONITOR_DEF* primary = &(subsystem->monitors[subsystem->selectedMonitor]);
|
||||
WINPR_ASSERT(primary);
|
||||
|
||||
const INT32 x = primary->left;
|
||||
const INT32 y = primary->top;
|
||||
const INT32 width = primary->right - primary->left + 1;
|
||||
const INT32 height = primary->bottom - primary->top + 1;
|
||||
|
||||
WINPR_ASSERT(x >= 0);
|
||||
WINPR_ASSERT(x <= UINT16_MAX);
|
||||
WINPR_ASSERT(y >= 0);
|
||||
WINPR_ASSERT(y <= UINT16_MAX);
|
||||
WINPR_ASSERT(width >= 0);
|
||||
WINPR_ASSERT(width <= UINT16_MAX);
|
||||
WINPR_ASSERT(height >= 0);
|
||||
WINPR_ASSERT(height <= UINT16_MAX);
|
||||
|
||||
if (shadow_surface_resize(screen->primary, (UINT16)x, (UINT16)y, (UINT16)width,
|
||||
(UINT16)height) &&
|
||||
shadow_surface_resize(screen->lobby, (UINT16)x, (UINT16)y, (UINT16)width, (UINT16)height))
|
||||
{
|
||||
if (((UINT32)width != screen->width) || ((UINT32)height != screen->height))
|
||||
{
|
||||
/* screen size is changed. Store new size and reinit lobby */
|
||||
screen->width = (UINT32)width;
|
||||
screen->height = (UINT32)height;
|
||||
return shadow_client_init_lobby(screen->server);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
56
third_party/FreeRDP/server/shadow/shadow_screen.h
vendored
Normal file
56
third_party/FreeRDP/server/shadow/shadow_screen.h
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_SHADOW_SCREEN_H
|
||||
#define FREERDP_SERVER_SHADOW_SCREEN_H
|
||||
|
||||
#include <freerdp/server/shadow.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
|
||||
struct rdp_shadow_screen
|
||||
{
|
||||
rdpShadowServer* server;
|
||||
|
||||
UINT32 width;
|
||||
UINT32 height;
|
||||
|
||||
CRITICAL_SECTION lock;
|
||||
REGION16 invalidRegion;
|
||||
|
||||
rdpShadowSurface* primary;
|
||||
rdpShadowSurface* lobby;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void shadow_screen_free(rdpShadowScreen* screen);
|
||||
|
||||
WINPR_ATTR_MALLOC(shadow_screen_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
rdpShadowScreen* shadow_screen_new(rdpShadowServer* server);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_SERVER_SHADOW_SCREEN_H */
|
||||
1102
third_party/FreeRDP/server/shadow/shadow_server.c
vendored
Normal file
1102
third_party/FreeRDP/server/shadow/shadow_server.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
296
third_party/FreeRDP/server/shadow/shadow_subsystem.c
vendored
Normal file
296
third_party/FreeRDP/server/shadow/shadow_subsystem.c
vendored
Normal file
@@ -0,0 +1,296 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include "shadow.h"
|
||||
|
||||
#include "shadow_subsystem.h"
|
||||
|
||||
static pfnShadowSubsystemEntry pSubsystemEntry = nullptr;
|
||||
|
||||
void shadow_subsystem_set_entry(pfnShadowSubsystemEntry pEntry)
|
||||
{
|
||||
pSubsystemEntry = pEntry;
|
||||
}
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static int shadow_subsystem_load_entry_points(RDP_SHADOW_ENTRY_POINTS* pEntryPoints)
|
||||
{
|
||||
WINPR_ASSERT(pEntryPoints);
|
||||
ZeroMemory(pEntryPoints, sizeof(RDP_SHADOW_ENTRY_POINTS));
|
||||
|
||||
if (!pSubsystemEntry)
|
||||
return -1;
|
||||
|
||||
if (pSubsystemEntry(pEntryPoints) < 0)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
rdpShadowSubsystem* shadow_subsystem_new(void)
|
||||
{
|
||||
RDP_SHADOW_ENTRY_POINTS ep = WINPR_C_ARRAY_INIT;
|
||||
|
||||
if (shadow_subsystem_load_entry_points(&ep) < 0)
|
||||
return nullptr;
|
||||
|
||||
if (!ep.New)
|
||||
return nullptr;
|
||||
|
||||
rdpShadowSubsystem* subsystem = ep.New();
|
||||
|
||||
if (!subsystem)
|
||||
return nullptr;
|
||||
|
||||
subsystem->ep = ep;
|
||||
|
||||
return subsystem;
|
||||
}
|
||||
|
||||
void shadow_subsystem_free(rdpShadowSubsystem* subsystem)
|
||||
{
|
||||
if (subsystem && subsystem->ep.Free)
|
||||
subsystem->ep.Free(subsystem);
|
||||
}
|
||||
|
||||
int shadow_subsystem_init(rdpShadowSubsystem* subsystem, rdpShadowServer* server)
|
||||
{
|
||||
int status = -1;
|
||||
|
||||
if (!subsystem || !subsystem->ep.Init)
|
||||
return -1;
|
||||
|
||||
subsystem->server = server;
|
||||
subsystem->selectedMonitor = server->selectedMonitor;
|
||||
|
||||
if (!(subsystem->MsgPipe = MessagePipe_New()))
|
||||
goto fail;
|
||||
|
||||
if (!(subsystem->updateEvent = shadow_multiclient_new()))
|
||||
goto fail;
|
||||
|
||||
status = subsystem->ep.Init(subsystem);
|
||||
if (status >= 0)
|
||||
return status;
|
||||
|
||||
fail:
|
||||
if (subsystem->MsgPipe)
|
||||
{
|
||||
MessagePipe_Free(subsystem->MsgPipe);
|
||||
subsystem->MsgPipe = nullptr;
|
||||
}
|
||||
|
||||
if (subsystem->updateEvent)
|
||||
{
|
||||
shadow_multiclient_free(subsystem->updateEvent);
|
||||
subsystem->updateEvent = nullptr;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void shadow_subsystem_free_queued_message(void* obj)
|
||||
{
|
||||
wMessage* message = (wMessage*)obj;
|
||||
if (message->Free)
|
||||
{
|
||||
message->Free(message);
|
||||
message->Free = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void shadow_subsystem_uninit(rdpShadowSubsystem* subsystem)
|
||||
{
|
||||
if (!subsystem)
|
||||
return;
|
||||
|
||||
if (subsystem->ep.Uninit)
|
||||
subsystem->ep.Uninit(subsystem);
|
||||
|
||||
if (subsystem->MsgPipe)
|
||||
{
|
||||
wObject* obj1 = nullptr;
|
||||
wObject* obj2 = nullptr;
|
||||
/* Release resource in messages before free */
|
||||
obj1 = MessageQueue_Object(subsystem->MsgPipe->In);
|
||||
|
||||
obj1->fnObjectFree = shadow_subsystem_free_queued_message;
|
||||
MessageQueue_Clear(subsystem->MsgPipe->In);
|
||||
|
||||
obj2 = MessageQueue_Object(subsystem->MsgPipe->Out);
|
||||
obj2->fnObjectFree = shadow_subsystem_free_queued_message;
|
||||
MessageQueue_Clear(subsystem->MsgPipe->Out);
|
||||
MessagePipe_Free(subsystem->MsgPipe);
|
||||
subsystem->MsgPipe = nullptr;
|
||||
}
|
||||
|
||||
if (subsystem->updateEvent)
|
||||
{
|
||||
shadow_multiclient_free(subsystem->updateEvent);
|
||||
subsystem->updateEvent = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
int shadow_subsystem_start(rdpShadowSubsystem* subsystem)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
if (!subsystem || !subsystem->ep.Start)
|
||||
return -1;
|
||||
|
||||
status = subsystem->ep.Start(subsystem);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int shadow_subsystem_stop(rdpShadowSubsystem* subsystem)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
if (!subsystem || !subsystem->ep.Stop)
|
||||
return -1;
|
||||
|
||||
status = subsystem->ep.Stop(subsystem);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
UINT32 shadow_enum_monitors(MONITOR_DEF* monitors, UINT32 maxMonitors)
|
||||
{
|
||||
UINT32 numMonitors = 0;
|
||||
RDP_SHADOW_ENTRY_POINTS ep;
|
||||
|
||||
if (shadow_subsystem_load_entry_points(&ep) < 0)
|
||||
return 0;
|
||||
|
||||
numMonitors = ep.EnumMonitors(monitors, maxMonitors);
|
||||
|
||||
return numMonitors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Common function for subsystem implementation.
|
||||
* This function convert 32bit ARGB format pixels to xormask data
|
||||
* and andmask data and fill into SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE
|
||||
* Caller should free the andMaskData and xorMaskData later.
|
||||
*/
|
||||
#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
|
||||
int shadow_subsystem_pointer_convert_alpha_pointer_data(
|
||||
const BYTE* WINPR_RESTRICT pixels, BOOL premultiplied, UINT32 width, UINT32 height,
|
||||
SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE* WINPR_RESTRICT pointerColor)
|
||||
{
|
||||
return shadow_subsystem_pointer_convert_alpha_pointer_data_to_format(
|
||||
pixels, PIXEL_FORMAT_BGRX32, premultiplied, width, height, pointerColor);
|
||||
}
|
||||
#endif
|
||||
|
||||
int shadow_subsystem_pointer_convert_alpha_pointer_data_to_format(
|
||||
const BYTE* pixels, UINT32 format, BOOL premultiplied, UINT32 width, UINT32 height,
|
||||
SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE* pointerColor)
|
||||
{
|
||||
UINT32 xorStep = 0;
|
||||
UINT32 andStep = 0;
|
||||
UINT32 andBit = 0;
|
||||
BYTE* andBits = nullptr;
|
||||
UINT32 andPixel = 0;
|
||||
const size_t bpp = FreeRDPGetBytesPerPixel(format);
|
||||
|
||||
xorStep = (width * 3);
|
||||
xorStep += (xorStep % 2);
|
||||
|
||||
andStep = ((width + 7) / 8);
|
||||
andStep += (andStep % 2);
|
||||
|
||||
pointerColor->lengthXorMask = height * xorStep;
|
||||
pointerColor->xorMaskData = (BYTE*)calloc(1, pointerColor->lengthXorMask);
|
||||
|
||||
if (!pointerColor->xorMaskData)
|
||||
return -1;
|
||||
|
||||
pointerColor->lengthAndMask = height * andStep;
|
||||
pointerColor->andMaskData = (BYTE*)calloc(1, pointerColor->lengthAndMask);
|
||||
|
||||
if (!pointerColor->andMaskData)
|
||||
{
|
||||
free(pointerColor->xorMaskData);
|
||||
pointerColor->xorMaskData = nullptr;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (size_t y = 0; y < height; y++)
|
||||
{
|
||||
const BYTE* pSrc8 = &pixels[(width * bpp) * (height - 1 - y)];
|
||||
BYTE* pDst8 = &(pointerColor->xorMaskData[y * xorStep]);
|
||||
|
||||
andBit = 0x80;
|
||||
andBits = &(pointerColor->andMaskData[andStep * y]);
|
||||
|
||||
for (size_t x = 0; x < width; x++)
|
||||
{
|
||||
BYTE B = 0;
|
||||
BYTE G = 0;
|
||||
BYTE R = 0;
|
||||
BYTE A = 0;
|
||||
|
||||
const UINT32 color = FreeRDPReadColor(&pSrc8[x * bpp], format);
|
||||
FreeRDPSplitColor(color, format, &R, &G, &B, &A, nullptr);
|
||||
|
||||
andPixel = 0;
|
||||
|
||||
if (A < 64)
|
||||
A = 0; /* pixel cannot be partially transparent */
|
||||
|
||||
if (!A)
|
||||
{
|
||||
/* transparent pixel: XOR = black, AND = 1 */
|
||||
andPixel = 1;
|
||||
B = G = R = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (premultiplied)
|
||||
{
|
||||
B = (B * 0xFF) / A;
|
||||
G = (G * 0xFF) / A;
|
||||
R = (R * 0xFF) / A;
|
||||
}
|
||||
}
|
||||
|
||||
*pDst8++ = B;
|
||||
*pDst8++ = G;
|
||||
*pDst8++ = R;
|
||||
|
||||
if (andPixel)
|
||||
*andBits |= andBit;
|
||||
if (!(andBit >>= 1))
|
||||
{
|
||||
andBits++;
|
||||
andBit = 0x80;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void shadow_subsystem_frame_update(rdpShadowSubsystem* subsystem)
|
||||
{
|
||||
shadow_multiclient_publish_and_wait(subsystem->updateEvent);
|
||||
}
|
||||
49
third_party/FreeRDP/server/shadow/shadow_subsystem.h
vendored
Normal file
49
third_party/FreeRDP/server/shadow/shadow_subsystem.h
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_SHADOW_SUBSYSTEM_H
|
||||
#define FREERDP_SERVER_SHADOW_SUBSYSTEM_H
|
||||
|
||||
#include <freerdp/server/shadow.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void shadow_subsystem_free(rdpShadowSubsystem* subsystem);
|
||||
|
||||
WINPR_ATTR_MALLOC(shadow_subsystem_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
rdpShadowSubsystem* shadow_subsystem_new(void);
|
||||
|
||||
WINPR_ATTR_NODISCARD int shadow_subsystem_init(rdpShadowSubsystem* subsystem,
|
||||
rdpShadowServer* server);
|
||||
void shadow_subsystem_uninit(rdpShadowSubsystem* subsystem);
|
||||
|
||||
WINPR_ATTR_NODISCARD int shadow_subsystem_start(rdpShadowSubsystem* subsystem);
|
||||
int shadow_subsystem_stop(rdpShadowSubsystem* subsystem);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_SERVER_SHADOW_SUBSYSTEM_H */
|
||||
74
third_party/FreeRDP/server/shadow/shadow_subsystem_builtin.c
vendored
Normal file
74
third_party/FreeRDP/server/shadow/shadow_subsystem_builtin.c
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2016 Jiang Zihao <zihao.jiang@yahoo.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <freerdp/server/shadow.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char* (*name)(void);
|
||||
pfnShadowSubsystemEntry entry;
|
||||
} RDP_SHADOW_SUBSYSTEM;
|
||||
|
||||
extern int ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints);
|
||||
extern const char* ShadowSubsystemName(void);
|
||||
|
||||
static const RDP_SHADOW_SUBSYSTEM g_Subsystems[] = {
|
||||
|
||||
{ ShadowSubsystemName, ShadowSubsystemEntry }
|
||||
};
|
||||
|
||||
static const size_t g_SubsystemCount = ARRAYSIZE(g_Subsystems);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static pfnShadowSubsystemEntry shadow_subsystem_load_static_entry(const char* name)
|
||||
{
|
||||
if (!name)
|
||||
{
|
||||
if (g_SubsystemCount > 0)
|
||||
{
|
||||
const RDP_SHADOW_SUBSYSTEM* cur = &g_Subsystems[0];
|
||||
WINPR_ASSERT(cur->entry);
|
||||
|
||||
return cur->entry;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (size_t index = 0; index < g_SubsystemCount; index++)
|
||||
{
|
||||
const RDP_SHADOW_SUBSYSTEM* cur = &g_Subsystems[index];
|
||||
WINPR_ASSERT(cur->name);
|
||||
WINPR_ASSERT(cur->entry);
|
||||
|
||||
if (strcmp(name, cur->name()) == 0)
|
||||
return cur->entry;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void shadow_subsystem_set_entry_builtin(const char* name)
|
||||
{
|
||||
pfnShadowSubsystemEntry entry = shadow_subsystem_load_static_entry(name);
|
||||
|
||||
if (entry)
|
||||
shadow_subsystem_set_entry(entry);
|
||||
}
|
||||
104
third_party/FreeRDP/server/shadow/shadow_surface.c
vendored
Normal file
104
third_party/FreeRDP/server/shadow/shadow_surface.c
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include "shadow.h"
|
||||
|
||||
#include "shadow_surface.h"
|
||||
#define ALIGN_SCREEN_SIZE(size, align) \
|
||||
((((size) % (align)) != 0) ? ((size) + (align) - ((size) % (align))) : (size))
|
||||
|
||||
rdpShadowSurface* shadow_surface_new(rdpShadowServer* server, UINT16 x, UINT16 y, UINT32 width,
|
||||
UINT32 height)
|
||||
{
|
||||
rdpShadowSurface* surface = nullptr;
|
||||
surface = (rdpShadowSurface*)calloc(1, sizeof(rdpShadowSurface));
|
||||
|
||||
if (!surface)
|
||||
return nullptr;
|
||||
|
||||
surface->server = server;
|
||||
surface->x = x;
|
||||
surface->y = y;
|
||||
surface->width = width;
|
||||
surface->height = height;
|
||||
surface->scanline = ALIGN_SCREEN_SIZE(surface->width, 32) * 4;
|
||||
surface->format = PIXEL_FORMAT_BGRX32;
|
||||
surface->data = (BYTE*)calloc(ALIGN_SCREEN_SIZE(surface->height, 32), surface->scanline);
|
||||
|
||||
if (!surface->data)
|
||||
{
|
||||
free(surface);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!InitializeCriticalSectionAndSpinCount(&(surface->lock), 4000))
|
||||
{
|
||||
free(surface->data);
|
||||
free(surface);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
region16_init(&(surface->invalidRegion));
|
||||
return surface;
|
||||
}
|
||||
|
||||
void shadow_surface_free(rdpShadowSurface* surface)
|
||||
{
|
||||
if (!surface)
|
||||
return;
|
||||
|
||||
free(surface->data);
|
||||
DeleteCriticalSection(&(surface->lock));
|
||||
region16_uninit(&(surface->invalidRegion));
|
||||
free(surface);
|
||||
}
|
||||
|
||||
BOOL shadow_surface_resize(rdpShadowSurface* surface, UINT16 x, UINT16 y, UINT32 width,
|
||||
UINT32 height)
|
||||
{
|
||||
BYTE* buffer = nullptr;
|
||||
UINT32 scanline = ALIGN_SCREEN_SIZE(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, 1ull * scanline * ALIGN_SCREEN_SIZE(height, 4ull));
|
||||
|
||||
if (buffer)
|
||||
{
|
||||
surface->x = x;
|
||||
surface->y = y;
|
||||
surface->width = width;
|
||||
surface->height = height;
|
||||
surface->scanline = scanline;
|
||||
surface->data = buffer;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
46
third_party/FreeRDP/server/shadow/shadow_surface.h
vendored
Normal file
46
third_party/FreeRDP/server/shadow/shadow_surface.h
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_SERVER_SHADOW_SURFACE_H
|
||||
#define FREERDP_SERVER_SHADOW_SURFACE_H
|
||||
|
||||
#include <freerdp/server/shadow.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void shadow_surface_free(rdpShadowSurface* surface);
|
||||
|
||||
WINPR_ATTR_MALLOC(shadow_surface_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
rdpShadowSurface* shadow_surface_new(rdpShadowServer* server, UINT16 x, UINT16 y, UINT32 width,
|
||||
UINT32 height);
|
||||
|
||||
WINPR_ATTR_NODISCARD BOOL shadow_surface_resize(rdpShadowSurface* surface, UINT16 x, UINT16 y,
|
||||
UINT32 width, UINT32 height);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_SERVER_SHADOW_SURFACE_H */
|
||||
Reference in New Issue
Block a user